
// ****************************************************************************
//
//                                 Main code
//
// ****************************************************************************
// ADC input using DMA.

// This example uses the DMA to capture many samples from the ADC.
//
// - We are putting the ADC in free-running capture mode at 0.5 Msps
//
// - A DMA channel will be attached to the ADC sample FIFO
//
// - Configure the ADC to right-shift samples to 8 bits of significance, so we
//   can DMA into a byte buffer
//
// This could be extended to use the ADC's round robin feature to sample two
// channels concurrently at 0.25 Msps each.
//
// It would be nice to have some analog samples to measure! This example also
// drives waves out through a 5-bit resistor DAC, as found on the reference
// VGA board. If you have that board, you can take an M-F jumper wire from
// GPIO 26 to the Green pin on the VGA connector (top row, next-but-rightmost
// hole). Or you can ignore that part of the code and connect your own signal
// to the ADC input.

#include "include.h"

// Channel 0 is GPIO26
#define CAPTURE_CHANNEL 0
#define CAPTURE_DEPTH 1000

uint8_t capture_buf[CAPTURE_DEPTH];

// core 1 will drive DAC to measure
void core1_main();

int main()
{
	stdio_init_all();

	// wait to connect terminal
	int c;
	do {
		printf("Press spacebar to start...\n");
		c = getchar();
	} while (c != ' ');

	// Send core 1 off to start driving the "DAC" whilst we configure the ADC.
	multicore_launch_core1(core1_main);

	// Init GPIO for analogue use: hi-Z, no pulls, disable digital input buffer.
	adc_gpio_init(26 + CAPTURE_CHANNEL);

	adc_init();
	adc_select_input(CAPTURE_CHANNEL);
	adc_fifo_setup(
		true,    // Write each completed conversion to the sample FIFO
		true,    // Enable DMA data request (DREQ)
		1,       // DREQ (and IRQ) asserted when at least 1 sample present
		false,   // We won't see the ERR bit because of 8 bit reads; disable.
		true     // Shift each sample to 8 bits when pushing to FIFO
	);

	// Divisor of 0 -> full speed. Free-running capture with the divider is
	// equivalent to pressing the ADC_CS_START_ONCE button once per `div + 1`
	// cycles (div not necessarily an integer). Each conversion takes 96
	// cycles, so in general you want a divider of 0 (hold down the button
	// continuously) or > 95 (take samples less frequently than 96 cycle
	// intervals). This is all timed by the 48 MHz ADC clock.
	adc_set_clkdiv(0);

	printf("Arming DMA\n");
	sleep_ms(1000);

	// Set up the DMA to start transferring data as soon as it appears in FIFO
	uint dma_chan = dma_claim_unused_channel(true);
	dma_channel_config cfg = dma_channel_get_default_config(dma_chan);

	// Reading from constant address, writing to incrementing byte addresses
	channel_config_set_transfer_data_size(&cfg, DMA_SIZE_8);
	channel_config_set_read_increment(&cfg, false);
	channel_config_set_write_increment(&cfg, true);

	// Pace transfers based on availability of ADC samples
	channel_config_set_dreq(&cfg, DREQ_ADC);

	dma_channel_configure(dma_chan, &cfg,
		capture_buf,    // dst
		&adc_hw->fifo,  // src
		CAPTURE_DEPTH,  // transfer count
		true            // start immediately
	);

	printf("Starting capture\n");
	adc_run(true);

	// Once DMA finishes, stop any new conversions from starting, and clean up
	// the FIFO in case the ADC was still mid-conversion.
	dma_channel_wait_for_finish_blocking(dma_chan);
	printf("Capture finished\n");
	adc_run(false);
	adc_fifo_drain();

	// Print samples to stdout so you can display them in pyplot, excel, matlab
	for (int i = 0; i < CAPTURE_DEPTH; ++i)
	{
		printf("%-3d, ", capture_buf[i]);
		if (i % 10 == 9)
			printf("\n");
	}

	return 0;
}

// ----------------------------------------------------------------------------
// Code for driving the "DAC" output for us to measure

// Core 1 is just going to sit and drive samples out continously. PIO provides
// consistent sample frequency.

#define OUTPUT_FREQ_KHZ 5
#define SAMPLE_WIDTH 5
// This is the green channel on the VGA board
#define DAC_PIN_BASE 6

void core1_main()
{
	PIO pio = pio0;
	uint sm = pio_claim_unused_sm(pio0, true);
	uint offset = pio_add_program(pio0, &resistor_dac_5bit_program);
	resistor_dac_5bit_program_init(pio0, sm, offset,
		OUTPUT_FREQ_KHZ * 1000 * 2 * (1 << SAMPLE_WIDTH), DAC_PIN_BASE);
	while (true)
	{
		// Triangle wave
		for (int i = 0; i < (1 << SAMPLE_WIDTH); ++i)
			pio_sm_put_blocking(pio, sm, i);
		for (int i = 0; i < (1 << SAMPLE_WIDTH); ++i)
			pio_sm_put_blocking(pio, sm, (1 << SAMPLE_WIDTH) - 1 - i);
	}
}
