137 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			137 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|  * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-3-Clause
 | |
|  */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include "pico/stdlib.h"
 | |
| // For ADC input:
 | |
| #include "hardware/adc.h"
 | |
| #include "hardware/dma.h"
 | |
| // For resistor DAC output:
 | |
| #include "pico/multicore.h"
 | |
| #include "hardware/pio.h"
 | |
| #include "resistor_dac.pio.h"
 | |
| 
 | |
| // 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.
 | |
| 
 | |
| // Channel 0 is GPIO26
 | |
| #define CAPTURE_CHANNEL 0
 | |
| #define CAPTURE_DEPTH 1000
 | |
| 
 | |
| uint8_t capture_buf[CAPTURE_DEPTH];
 | |
| 
 | |
| void core1_main();
 | |
| 
 | |
| int main() {
 | |
|     stdio_init_all();
 | |
| 
 | |
|     // 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");
 | |
|     }
 | |
| }
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // 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);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 |