| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- // 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 <stdio.h>
- #include <math.h>
- #include "pico/stdlib.h"
- #include "hardware/adc.h"
- #include "hardware/dma.h"
- #include "kiss_fftr.h"
- #include <stdio.h>
- #include <stdlib.h>
- #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;i<NSAMP;i++) {sum+=cap_buf[i];}
- float avg = (float)sum/NSAMP;
- for (int i=0;i<NSAMP;i++) {fft_in[i]=(float)cap_buf[i]-avg;}
- // compute fast fourier transform
- kiss_fftr(cfg , fft_in, fft_out);
-
- // compute power and calculate max freq component
- float max_power = 0;
- int max_idx = 0;
- // any frequency bin over NSAMP/2 is aliased (nyquist sampling theorum)
- for (int i = 0; i < NSAMP/2; i++) {
- float power = fft_out[i].r*fft_out[i].r+fft_out[i].i*fft_out[i].i;
- if (power>max_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;}
- }
|