Audio FFT using STM32L432KC Nucleo and .96" SPI OLED
Dependencies: Adafruit_GFX mbed
main.cpp@1:947ee109759e, 2017-03-23 (annotated)
- Committer:
- ColoradoRob
- Date:
- Thu Mar 23 00:42:09 2017 +0000
- Revision:
- 1:947ee109759e
- Parent:
- 0:ac337301f28b
Initial commit.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ColoradoRob | 0:ac337301f28b | 1 | #include "mbed.h" |
ColoradoRob | 0:ac337301f28b | 2 | #include "Adafruit_SSD1306.h" |
ColoradoRob | 0:ac337301f28b | 3 | #include "arm_math.h" |
ColoradoRob | 0:ac337301f28b | 4 | |
ColoradoRob | 0:ac337301f28b | 5 | DigitalOut led(LED1); |
ColoradoRob | 0:ac337301f28b | 6 | AnalogIn audio_in(PA_0); |
ColoradoRob | 0:ac337301f28b | 7 | Ticker sampler; |
ColoradoRob | 0:ac337301f28b | 8 | |
ColoradoRob | 0:ac337301f28b | 9 | SPI oled_spi(PA_7, PA_6, PA_5); |
ColoradoRob | 0:ac337301f28b | 10 | Adafruit_SSD1306_Spi oled(oled_spi, PA_11, PB_5, PB_4, 64); |
ColoradoRob | 0:ac337301f28b | 11 | |
ColoradoRob | 0:ac337301f28b | 12 | volatile int flag = 0; |
ColoradoRob | 0:ac337301f28b | 13 | |
ColoradoRob | 0:ac337301f28b | 14 | #define AMPLITUDE (1.0) // x * 3.3V |
ColoradoRob | 0:ac337301f28b | 15 | #define RANGE (32) |
ColoradoRob | 0:ac337301f28b | 16 | #define OFFSET (32) |
ColoradoRob | 0:ac337301f28b | 17 | |
ColoradoRob | 0:ac337301f28b | 18 | #define BUFFER_SIZE (128) |
ColoradoRob | 0:ac337301f28b | 19 | int16_t buffer[BUFFER_SIZE]; |
ColoradoRob | 0:ac337301f28b | 20 | |
ColoradoRob | 0:ac337301f28b | 21 | void calculate_sinewave(void); |
ColoradoRob | 0:ac337301f28b | 22 | |
ColoradoRob | 0:ac337301f28b | 23 | arm_rfft_fast_instance_f32 S; |
ColoradoRob | 0:ac337301f28b | 24 | float audio_buffer[BUFFER_SIZE * 2]; |
ColoradoRob | 0:ac337301f28b | 25 | float fft_output[BUFFER_SIZE * 2]; |
ColoradoRob | 0:ac337301f28b | 26 | |
ColoradoRob | 0:ac337301f28b | 27 | void sample() |
ColoradoRob | 0:ac337301f28b | 28 | { |
ColoradoRob | 0:ac337301f28b | 29 | static int16_t count = 0; |
ColoradoRob | 0:ac337301f28b | 30 | if (flag) return; |
ColoradoRob | 0:ac337301f28b | 31 | audio_buffer[count++] = audio_in * 2.0f - 1.0f; |
ColoradoRob | 0:ac337301f28b | 32 | if (count == (BUFFER_SIZE * 2)) { |
ColoradoRob | 0:ac337301f28b | 33 | count = 0; |
ColoradoRob | 0:ac337301f28b | 34 | flag = 1; |
ColoradoRob | 0:ac337301f28b | 35 | } |
ColoradoRob | 0:ac337301f28b | 36 | } |
ColoradoRob | 0:ac337301f28b | 37 | |
ColoradoRob | 0:ac337301f28b | 38 | void do_fft() |
ColoradoRob | 0:ac337301f28b | 39 | { |
ColoradoRob | 0:ac337301f28b | 40 | int32_t sum = 0; |
ColoradoRob | 0:ac337301f28b | 41 | arm_rfft_fast_f32 (&S, audio_buffer, fft_output, 0); |
ColoradoRob | 0:ac337301f28b | 42 | for (int i = 0; i != BUFFER_SIZE * 2; i += 2) { |
ColoradoRob | 0:ac337301f28b | 43 | float n = fft_output[i] * fft_output[i] + fft_output[i + 1] * fft_output[i + 1]; |
ColoradoRob | 0:ac337301f28b | 44 | buffer[i/2] = 20 * log10(n); // convert to dB |
ColoradoRob | 0:ac337301f28b | 45 | if (i != 0) sum += buffer[i/2]; // ignore DC component |
ColoradoRob | 0:ac337301f28b | 46 | } |
ColoradoRob | 0:ac337301f28b | 47 | int avg = sum / BUFFER_SIZE; |
ColoradoRob | 0:ac337301f28b | 48 | oled.printf("%+02ddB\r", avg); |
ColoradoRob | 0:ac337301f28b | 49 | buffer[0] = avg; // overwrite DC offset |
ColoradoRob | 0:ac337301f28b | 50 | for (int i = 0; i != BUFFER_SIZE; ++i) { |
ColoradoRob | 0:ac337301f28b | 51 | int offset = 48 - (buffer[i] - int(avg)); // Normalize the values |
ColoradoRob | 0:ac337301f28b | 52 | offset = std::max(0, offset); // Limit to display size |
ColoradoRob | 0:ac337301f28b | 53 | offset = std::min(63, offset); |
ColoradoRob | 0:ac337301f28b | 54 | oled.drawFastVLine(i, offset, 63, 1); |
ColoradoRob | 0:ac337301f28b | 55 | } |
ColoradoRob | 0:ac337301f28b | 56 | oled.drawFastHLine(0, 48 - avg / 2, 127, 0); |
ColoradoRob | 0:ac337301f28b | 57 | oled.drawFastHLine(0, 47 - avg / 2, 127, 0); |
ColoradoRob | 0:ac337301f28b | 58 | oled.drawFastHLine(0, 49 - avg / 2, 127, 0); |
ColoradoRob | 0:ac337301f28b | 59 | |
ColoradoRob | 0:ac337301f28b | 60 | } |
ColoradoRob | 0:ac337301f28b | 61 | |
ColoradoRob | 0:ac337301f28b | 62 | |
ColoradoRob | 0:ac337301f28b | 63 | int main() { |
ColoradoRob | 0:ac337301f28b | 64 | arm_rfft_fast_init_f32(&S , 256); |
ColoradoRob | 0:ac337301f28b | 65 | |
ColoradoRob | 0:ac337301f28b | 66 | oled_spi.frequency(8000000); |
ColoradoRob | 0:ac337301f28b | 67 | oled.begin(); |
ColoradoRob | 0:ac337301f28b | 68 | wait_ms(200); |
ColoradoRob | 0:ac337301f28b | 69 | |
ColoradoRob | 0:ac337301f28b | 70 | oled.splash(); |
ColoradoRob | 0:ac337301f28b | 71 | oled.display(); |
ColoradoRob | 0:ac337301f28b | 72 | wait(2); |
ColoradoRob | 0:ac337301f28b | 73 | oled.clearDisplay(); |
ColoradoRob | 0:ac337301f28b | 74 | |
ColoradoRob | 0:ac337301f28b | 75 | sampler.attach(sample, 1.0 / 6600.0); |
ColoradoRob | 0:ac337301f28b | 76 | |
ColoradoRob | 0:ac337301f28b | 77 | while(1) { |
ColoradoRob | 0:ac337301f28b | 78 | if (flag) { |
ColoradoRob | 0:ac337301f28b | 79 | do_fft(); |
ColoradoRob | 0:ac337301f28b | 80 | oled.display(); |
ColoradoRob | 0:ac337301f28b | 81 | oled.clearDisplay(); |
ColoradoRob | 0:ac337301f28b | 82 | led = !led; |
ColoradoRob | 0:ac337301f28b | 83 | flag = 0; |
ColoradoRob | 0:ac337301f28b | 84 | } |
ColoradoRob | 0:ac337301f28b | 85 | } |
ColoradoRob | 0:ac337301f28b | 86 | } |