// Sample from the ADC continuously at a particular sample rate // and then compute an FFT over the data // // much of this code is from pico-examples/adc/dma_capture/dma_capture.c // the rest is written by Alex Wulff (www.AlexWulff.com) #include #include #include "pico/stdlib.h" #include "hardware/adc.h" #include "hardware/dma.h" #include "kiss_fftr.h" #include #include #include "pico/stdlib.h" #include "hardware/pio.h" #include "hardware/clocks.h" #include "ws2812.pio.h" #define IS_RGBW false #define NUM_PIXELS 150 #ifdef PICO_DEFAULT_WS2812_PIN #define WS2812_PIN PICO_DEFAULT_WS2812_PIN #else // default to pin 2 if the board doesn't have a default WS2812 pin defined #define WS2812_PIN 6 #endif static inline void put_pixel(uint32_t pixel_grb) { pio_sm_put_blocking(pio0, 0, pixel_grb << 8u); } // set this to determine sample rate // 0 = 500,000 Hz // 960 = 50,000 Hz // 9600 = 5,000 Hz #define CLOCK_DIV 960 #define FSAMP 50000 // Channel 0 is GPIO26 #define CAPTURE_CHANNEL 0 #define LED_PIN 25 // BE CAREFUL: anything over about 9000 here will cause things // to silently break. The code will compile and upload, but due // to memory issues nothing will work properly #define NSAMP 4096 // globals dma_channel_config cfg; uint dma_chan; float freqs[NSAMP]; void setup(); void sample(uint8_t *capture_buf); int main() { uint8_t cap_buf[NSAMP]; kiss_fft_scalar fft_in[NSAMP]; // kiss_fft_scalar is a float kiss_fft_cpx fft_out[NSAMP]; kiss_fftr_cfg cfg = kiss_fftr_alloc(NSAMP,false,0,0); // setup ports and outputs setup(); while (1) { // get NSAMP samples at FSAMP sample(cap_buf); // fill fourier transform input while subtracting DC component uint64_t sum = 0; for (int i=0;imax_power) { max_power=power; max_idx = i; } } float max_freq = freqs[max_idx]; printf("Greatest Frequency Component: %0.1f Hz\n",max_freq); put_pixel(0x00ffff); put_pixel(0xff00ff); } // should never get here kiss_fft_free(cfg); } void sample(uint8_t *capture_buf) { adc_fifo_drain(); adc_run(false); dma_channel_configure(dma_chan, &cfg, capture_buf, // dst &adc_hw->fifo, // src NSAMP, // transfer count true // start immediately ); gpio_put(LED_PIN, 1); adc_run(true); dma_channel_wait_for_finish_blocking(dma_chan); gpio_put(LED_PIN, 0); } void setup() { stdio_init_all(); // todo get free sm PIO pio = pio0; int sm = 0; uint offset = pio_add_program(pio, &ws2812_program); ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, IS_RGBW); //gpio_init(LED_PIN); //gpio_set_dir(LED_PIN, GPIO_OUT); 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 ); // set sample rate adc_set_clkdiv(CLOCK_DIV); 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); 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); // calculate frequencies of each bin float f_max = FSAMP; float f_res = f_max / NSAMP; for (int i = 0; i < NSAMP; i++) {freqs[i] = f_res*i;} }