adc_fft.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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. typedef struct {
  27. double r; // a fraction between 0 and 1
  28. double g; // a fraction between 0 and 1
  29. double b; // a fraction between 0 and 1
  30. } rgb;
  31. static inline void put_pixel(uint32_t pixel_grb) {
  32. pio_sm_put_blocking(pio0, 0, pixel_grb << 8u);
  33. }
  34. // set this to determine sample rate
  35. // 0 = 500,000 Hz
  36. // 960 = 50,000 Hz
  37. // 9600 = 5,000 Hz
  38. #define CLOCK_DIV 960
  39. #define FSAMP 50000
  40. // Channel 0 is GPIO26
  41. #define CAPTURE_CHANNEL 0
  42. #define LED_PIN 25
  43. // BE CAREFUL: anything over about 9000 here will cause things
  44. // to silently break. The code will compile and upload, but due
  45. // to memory issues nothing will work properly
  46. #define NSAMP 2048 //4096
  47. // globals
  48. dma_channel_config cfg;
  49. uint dma_chan;
  50. float freqs[NSAMP];
  51. float freqsInLog[NSAMP];
  52. float power[NSAMP / 2];
  53. float powerInLog[NUM_PIXELS];
  54. uint64_t lastColorChange;
  55. void setup();
  56. void sample(uint8_t *capture_buf);
  57. rgb hsv2rgb(double h, double s, double v);
  58. int main() {
  59. uint8_t cap_buf[NSAMP];
  60. kiss_fft_scalar fft_in[NSAMP]; // kiss_fft_scalar is a float
  61. kiss_fft_cpx fft_out[NSAMP];
  62. kiss_fftr_cfg cfg = kiss_fftr_alloc(NSAMP, false, 0, 0);
  63. // setup ports and outputs
  64. setup();
  65. printf("Started\n");
  66. while (1) {
  67. //printf("Loop\n");
  68. // get NSAMP samples at FSAMP
  69. //uint64_t sampleStart = to_us_since_boot(get_absolute_time());
  70. sample(cap_buf);
  71. //printf("Sample time: %llu \n", to_us_since_boot(get_absolute_time())-sampleStart);
  72. // fill fourier transform input while subtracting DC component
  73. uint64_t sum = 0;
  74. for (int i = 0; i < NSAMP; i++) { sum += cap_buf[i]; }
  75. float avg = (float) sum / NSAMP;
  76. for (int i = 0; i < NSAMP; i++) { fft_in[i] = (float) cap_buf[i] - avg; }
  77. // compute fast fourier transform
  78. kiss_fftr(cfg, fft_in, fft_out);
  79. // compute power and calculate max freq component
  80. // any frequency bin over NSAMP/2 is aliased (nyquist sampling theorum)
  81. for (int i = 0; i < NSAMP / 2; i++) {
  82. power[i] = fft_out[i].r * fft_out[i].r + fft_out[i].i * fft_out[i].i;
  83. }
  84. float f_max = FSAMP;
  85. float f_res = f_max / NSAMP;
  86. for (int i = 0; i < NUM_PIXELS; i++) {
  87. float lowFreq = freqs[i]; //freqsInLog[i];
  88. float highFreq;
  89. if (i != NUM_PIXELS - 1) {
  90. highFreq = freqs[i+1]; //freqsInLog[i + 1];
  91. } else {
  92. highFreq = FSAMP / 2;
  93. }
  94. int lowInd = lowFreq / f_res;
  95. int highInd = highFreq / f_res;
  96. float totalPower = 0;
  97. for (int j = lowInd; j < highInd + 1; j++) {
  98. totalPower += power[j];
  99. }
  100. //printf("lowInd = %d, highInd = %d, lowFreq = %f, highFreq = %f, freq[lowInd] = %f, freq[highInd] = %f\n", lowInd, highInd, lowFreq, highFreq, freqs[lowInd], freqs[highInd]);
  101. float div_power = totalPower / (highInd + 1 - lowInd);
  102. powerInLog[i] = div_power/1000.0; //20 * log(fmax(div_power - 1000000, 1));
  103. }
  104. //for (int i = 0; i < NUM_PIXELS - 1; i++) {
  105. // printf("Power for freq %f to %f = %f (%f)\n", freqsInLog[i], freqsInLog[i + 1], powerInLog[i], power[i]);
  106. //}
  107. //uint64_t timmmme = to_us_since_boot(get_absolute_time()) - lastColorChange;
  108. //printf("%llu \n", timmmme);
  109. if (to_us_since_boot(get_absolute_time()) - lastColorChange < 300) {
  110. sleep_us(300 - (to_us_since_boot(get_absolute_time()) - lastColorChange));
  111. }
  112. for (int i = 0; i < NUM_PIXELS; i++) {
  113. uint32_t value = (uint32_t)(fmin(255, powerInLog[i]/400.0 * 255));
  114. //uint32_t value = (uint32_t)(fmin(255, power[i]/400.0 * 255));
  115. //rgb color = hsv2rgb(fmin(1, power[i]/400.0), 1, 0.5);
  116. //rgb color = hsv2rgb(fmin(1, 0.1), 1, 0.5);
  117. //uint32_t value = color.g * 256 * pow(2, 16) + color.r * 256 * pow(2, 8) + color.b * 256;
  118. //printf("Color = %d, pixel = %d\n", value, i);
  119. put_pixel(value);
  120. put_pixel(value);
  121. }
  122. lastColorChange = to_us_since_boot(get_absolute_time());
  123. //sleep_ms(50);
  124. }
  125. // should never get here
  126. kiss_fft_free(cfg);
  127. }
  128. rgb hsv2rgb(double h, double s, double v) {
  129. double hh, p, q, t, ff;
  130. long i;
  131. rgb out;
  132. if(s <= 0.0) { // < is bogus, just shuts up warnings
  133. out.r = v;
  134. out.g = v;
  135. out.b = v;
  136. return out;
  137. }
  138. hh = h;
  139. if(hh >= 360.0) hh = 0.0;
  140. hh /= 60.0;
  141. i = (long)hh;
  142. ff = hh - i;
  143. p = v * (1.0 - s);
  144. q = v * (1.0 - (s * ff));
  145. t = v * (1.0 - (s * (1.0 - ff)));
  146. switch(i) {
  147. case 0:
  148. out.r = v;
  149. out.g = t;
  150. out.b = p;
  151. break;
  152. case 1:
  153. out.r = q;
  154. out.g = v;
  155. out.b = p;
  156. break;
  157. case 2:
  158. out.r = p;
  159. out.g = v;
  160. out.b = t;
  161. break;
  162. case 3:
  163. out.r = p;
  164. out.g = q;
  165. out.b = v;
  166. break;
  167. case 4:
  168. out.r = t;
  169. out.g = p;
  170. out.b = v;
  171. break;
  172. case 5:
  173. default:
  174. out.r = v;
  175. out.g = p;
  176. out.b = q;
  177. break;
  178. }
  179. return out;
  180. }
  181. void sample(uint8_t *capture_buf) {
  182. adc_fifo_drain();
  183. adc_run(false);
  184. dma_channel_configure(dma_chan, &cfg,
  185. capture_buf, // dst
  186. &adc_hw->fifo, // src
  187. NSAMP, // transfer count
  188. true // start immediately
  189. );
  190. gpio_put(LED_PIN, 1);
  191. adc_run(true);
  192. dma_channel_wait_for_finish_blocking(dma_chan);
  193. gpio_put(LED_PIN, 0);
  194. }
  195. void setup() {
  196. stdio_init_all();
  197. // todo get free sm
  198. PIO pio = pio0;
  199. int sm = 0;
  200. uint offset = pio_add_program(pio, &ws2812_program);
  201. ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, IS_RGBW);
  202. //gpio_init(LED_PIN);
  203. //gpio_set_dir(LED_PIN, GPIO_OUT);
  204. adc_gpio_init(26 + CAPTURE_CHANNEL);
  205. adc_init();
  206. adc_select_input(CAPTURE_CHANNEL);
  207. adc_fifo_setup(
  208. true, // Write each completed conversion to the sample FIFO
  209. true, // Enable DMA data request (DREQ)
  210. 1, // DREQ (and IRQ) asserted when at least 1 sample present
  211. false, // We won't see the ERR bit because of 8 bit reads; disable.
  212. true // Shift each sample to 8 bits when pushing to FIFO
  213. );
  214. // set sample rate
  215. adc_set_clkdiv(CLOCK_DIV);
  216. sleep_ms(1000);
  217. // Set up the DMA to start transferring data as soon as it appears in FIFO
  218. uint dma_chan = dma_claim_unused_channel(true);
  219. cfg = dma_channel_get_default_config(dma_chan);
  220. // Reading from constant address, writing to incrementing byte addresses
  221. channel_config_set_transfer_data_size(&cfg, DMA_SIZE_8);
  222. channel_config_set_read_increment(&cfg, false);
  223. channel_config_set_write_increment(&cfg, true);
  224. // Pace transfers based on availability of ADC samples
  225. channel_config_set_dreq(&cfg, DREQ_ADC);
  226. printf("Starting\n");
  227. // calculate frequencies of each bin
  228. float f_max = FSAMP;
  229. float f_res = f_max / NSAMP;
  230. for (int i = 0; i < NSAMP; i++) {
  231. freqs[i] = f_res * i;
  232. }
  233. // Or 20kHz?
  234. float max_power = log(FSAMP / 2.0);
  235. float min_power = log(80);
  236. for (int i = 0; i < NUM_PIXELS; i++) {
  237. freqsInLog[i] = exp(i / (float) NUM_PIXELS * (max_power - min_power) + min_power);
  238. printf("freqsInLog[%d] = %f.1\n", i, freqsInLog[i]);
  239. }
  240. }