adc_fft.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Sample from the ADC continuously at a particular sample rate
  2. // and then compute an FFT over the data
  3. //
  4. // much of this code is from pico-examples/adc/dma_capture/dma_capture.c
  5. // the rest is written by Alex Wulff (www.AlexWulff.com)
  6. #include <stdio.h>
  7. #include <math.h>
  8. #include "pico/stdlib.h"
  9. #include "hardware/adc.h"
  10. #include "hardware/dma.h"
  11. #include "kiss_fftr.h"
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include "pico/stdlib.h"
  15. #include "hardware/pio.h"
  16. #include "hardware/clocks.h"
  17. #include "ws2812.pio.h"
  18. #define IS_RGBW false
  19. #define NUM_PIXELS 150
  20. #ifdef PICO_DEFAULT_WS2812_PIN
  21. #define WS2812_PIN PICO_DEFAULT_WS2812_PIN
  22. #else
  23. // default to pin 2 if the board doesn't have a default WS2812 pin defined
  24. #define WS2812_PIN 6
  25. #endif
  26. static inline void put_pixel(uint32_t pixel_grb) {
  27. pio_sm_put_blocking(pio0, 0, pixel_grb << 8u);
  28. }
  29. // set this to determine sample rate
  30. // 0 = 500,000 Hz
  31. // 960 = 50,000 Hz
  32. // 9600 = 5,000 Hz
  33. #define CLOCK_DIV 960
  34. #define FSAMP 50000
  35. // Channel 0 is GPIO26
  36. #define CAPTURE_CHANNEL 0
  37. #define LED_PIN 25
  38. // BE CAREFUL: anything over about 9000 here will cause things
  39. // to silently break. The code will compile and upload, but due
  40. // to memory issues nothing will work properly
  41. #define NSAMP 4096
  42. // globals
  43. dma_channel_config cfg;
  44. uint dma_chan;
  45. float freqs[NSAMP];
  46. void setup();
  47. void sample(uint8_t *capture_buf);
  48. int main() {
  49. uint8_t cap_buf[NSAMP];
  50. kiss_fft_scalar fft_in[NSAMP]; // kiss_fft_scalar is a float
  51. kiss_fft_cpx fft_out[NSAMP];
  52. kiss_fftr_cfg cfg = kiss_fftr_alloc(NSAMP,false,0,0);
  53. // setup ports and outputs
  54. setup();
  55. while (1) {
  56. // get NSAMP samples at FSAMP
  57. sample(cap_buf);
  58. // fill fourier transform input while subtracting DC component
  59. uint64_t sum = 0;
  60. for (int i=0;i<NSAMP;i++) {sum+=cap_buf[i];}
  61. float avg = (float)sum/NSAMP;
  62. for (int i=0;i<NSAMP;i++) {fft_in[i]=(float)cap_buf[i]-avg;}
  63. // compute fast fourier transform
  64. kiss_fftr(cfg , fft_in, fft_out);
  65. // compute power and calculate max freq component
  66. float max_power = 0;
  67. int max_idx = 0;
  68. // any frequency bin over NSAMP/2 is aliased (nyquist sampling theorum)
  69. for (int i = 0; i < NSAMP/2; i++) {
  70. float power = fft_out[i].r*fft_out[i].r+fft_out[i].i*fft_out[i].i;
  71. if (power>max_power) {
  72. max_power=power;
  73. max_idx = i;
  74. }
  75. }
  76. float max_freq = freqs[max_idx];
  77. printf("Greatest Frequency Component: %0.1f Hz\n",max_freq);
  78. put_pixel(0x00ffff);
  79. put_pixel(0xff00ff);
  80. }
  81. // should never get here
  82. kiss_fft_free(cfg);
  83. }
  84. void sample(uint8_t *capture_buf) {
  85. adc_fifo_drain();
  86. adc_run(false);
  87. dma_channel_configure(dma_chan, &cfg,
  88. capture_buf, // dst
  89. &adc_hw->fifo, // src
  90. NSAMP, // transfer count
  91. true // start immediately
  92. );
  93. gpio_put(LED_PIN, 1);
  94. adc_run(true);
  95. dma_channel_wait_for_finish_blocking(dma_chan);
  96. gpio_put(LED_PIN, 0);
  97. }
  98. void setup() {
  99. stdio_init_all();
  100. // todo get free sm
  101. PIO pio = pio0;
  102. int sm = 0;
  103. uint offset = pio_add_program(pio, &ws2812_program);
  104. ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, IS_RGBW);
  105. //gpio_init(LED_PIN);
  106. //gpio_set_dir(LED_PIN, GPIO_OUT);
  107. adc_gpio_init(26 + CAPTURE_CHANNEL);
  108. adc_init();
  109. adc_select_input(CAPTURE_CHANNEL);
  110. adc_fifo_setup(
  111. true, // Write each completed conversion to the sample FIFO
  112. true, // Enable DMA data request (DREQ)
  113. 1, // DREQ (and IRQ) asserted when at least 1 sample present
  114. false, // We won't see the ERR bit because of 8 bit reads; disable.
  115. true // Shift each sample to 8 bits when pushing to FIFO
  116. );
  117. // set sample rate
  118. adc_set_clkdiv(CLOCK_DIV);
  119. sleep_ms(1000);
  120. // Set up the DMA to start transferring data as soon as it appears in FIFO
  121. uint dma_chan = dma_claim_unused_channel(true);
  122. cfg = dma_channel_get_default_config(dma_chan);
  123. // Reading from constant address, writing to incrementing byte addresses
  124. channel_config_set_transfer_data_size(&cfg, DMA_SIZE_8);
  125. channel_config_set_read_increment(&cfg, false);
  126. channel_config_set_write_increment(&cfg, true);
  127. // Pace transfers based on availability of ADC samples
  128. channel_config_set_dreq(&cfg, DREQ_ADC);
  129. // calculate frequencies of each bin
  130. float f_max = FSAMP;
  131. float f_res = f_max / NSAMP;
  132. for (int i = 0; i < NSAMP; i++) {freqs[i] = f_res*i;}
  133. }