adc_fft.c 10 KB

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