Simplified version of FFT code - drives on-board LED as a "Colour Organ".
Dependencies: FastAnalogIn NVIC_set_all_priorities mbed-dsp mbed
Fork of KL25Z_FFT_Demo_tony by
main.cpp@1:7421267b0777, 2016-11-15 (annotated)
- Committer:
- luisda130595
- Date:
- Tue Nov 15 22:16:24 2016 +0000
- Revision:
- 1:7421267b0777
- Parent:
- 0:b8c9dffbbe7e
- Child:
- 2:177596541c8d
Pa' Ramiro
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
tony1tf | 0:b8c9dffbbe7e | 1 | // Audio Spectrum Display |
tony1tf | 0:b8c9dffbbe7e | 2 | // Copyright 2013 Tony DiCola (tony@tonydicola.com) |
tony1tf | 0:b8c9dffbbe7e | 3 | // Code ported from the guide at http://learn.adafruit.com/fft-fun-with-fourier-transforms?view=all |
tony1tf | 0:b8c9dffbbe7e | 4 | // mods by Tony Abbey to simplify code to drive tri-colour LED as a "colour organ" |
tony1tf | 0:b8c9dffbbe7e | 5 | |
tony1tf | 0:b8c9dffbbe7e | 6 | #include "mbed.h" |
tony1tf | 0:b8c9dffbbe7e | 7 | #include "NVIC_set_all_priorities.h" |
tony1tf | 0:b8c9dffbbe7e | 8 | #include <ctype.h> |
tony1tf | 0:b8c9dffbbe7e | 9 | #include "arm_math.h" |
tony1tf | 0:b8c9dffbbe7e | 10 | #include "arm_const_structs.h" |
tony1tf | 0:b8c9dffbbe7e | 11 | #include "FastAnalogIn.h" |
luisda130595 | 1:7421267b0777 | 12 | #include <string> |
tony1tf | 0:b8c9dffbbe7e | 13 | |
luisda130595 | 1:7421267b0777 | 14 | FastAnalogIn Audio(PTC2); |
tony1tf | 0:b8c9dffbbe7e | 15 | Serial pc(USBTX, USBRX); |
tony1tf | 0:b8c9dffbbe7e | 16 | |
tony1tf | 0:b8c9dffbbe7e | 17 | |
tony1tf | 0:b8c9dffbbe7e | 18 | //#define RGBW_ext // Disable this line when you want to use the KL25Z on-board RGB LED. |
tony1tf | 0:b8c9dffbbe7e | 19 | |
tony1tf | 0:b8c9dffbbe7e | 20 | |
tony1tf | 0:b8c9dffbbe7e | 21 | #ifndef RGBW_ext |
tony1tf | 0:b8c9dffbbe7e | 22 | // RGB direct output to PWM channels - on-board RGB LED |
tony1tf | 0:b8c9dffbbe7e | 23 | PwmOut gled(LED_GREEN); |
tony1tf | 0:b8c9dffbbe7e | 24 | PwmOut rled(LED_RED); |
tony1tf | 0:b8c9dffbbe7e | 25 | PwmOut bled(LED_BLUE); |
tony1tf | 0:b8c9dffbbe7e | 26 | #else |
tony1tf | 0:b8c9dffbbe7e | 27 | // HSI to RGBW conversion with direct output to external PWM channels - RGBW LED |
tony1tf | 0:b8c9dffbbe7e | 28 | // hsi2rgbw_pwm led(PTD4, PTA12, PTA4, PTA5); //Red, Green, Blue, White |
tony1tf | 0:b8c9dffbbe7e | 29 | #endif |
tony1tf | 0:b8c9dffbbe7e | 30 | |
tony1tf | 0:b8c9dffbbe7e | 31 | // Dummy ISR for disabling NMI on PTA4 - !! DO NOT REMOVE THIS !! |
tony1tf | 0:b8c9dffbbe7e | 32 | // More info at https://mbed.org/questions/1387/How-can-I-access-the-FTFA_FOPT-register-/ |
tony1tf | 0:b8c9dffbbe7e | 33 | extern "C" void NMI_Handler() { |
tony1tf | 0:b8c9dffbbe7e | 34 | DigitalIn test(PTA4); |
tony1tf | 0:b8c9dffbbe7e | 35 | } |
tony1tf | 0:b8c9dffbbe7e | 36 | |
tony1tf | 0:b8c9dffbbe7e | 37 | |
tony1tf | 0:b8c9dffbbe7e | 38 | //////////////////////////////////////////////////////////////////////////////// |
tony1tf | 0:b8c9dffbbe7e | 39 | // CONFIGURATION |
tony1tf | 0:b8c9dffbbe7e | 40 | // These values can be changed to alter the behavior of the spectrum display. |
tony1tf | 0:b8c9dffbbe7e | 41 | // KL25Z limitations |
tony1tf | 0:b8c9dffbbe7e | 42 | // ----------------- |
tony1tf | 0:b8c9dffbbe7e | 43 | // - When used with the Spectrogram python script : |
tony1tf | 0:b8c9dffbbe7e | 44 | // There is a substantial time lag between the music and the screen output. |
tony1tf | 0:b8c9dffbbe7e | 45 | // Max allowed SAMPLE_RATE_HZ is 40000 |
tony1tf | 0:b8c9dffbbe7e | 46 | // Max allowed FFT_SIZE is 64 |
tony1tf | 0:b8c9dffbbe7e | 47 | //////////////////////////////////////////////////////////////////////////////// |
tony1tf | 0:b8c9dffbbe7e | 48 | // A value >= 1000 and <= 1000 + PIXEL_COUNT fixes the output to a single frequency |
tony1tf | 0:b8c9dffbbe7e | 49 | // window = a single color. |
luisda130595 | 1:7421267b0777 | 50 | int SAMPLE_RATE_HZ = 1000; // Sample rate of the audio in hertz. |
luisda130595 | 1:7421267b0777 | 51 | |
tony1tf | 0:b8c9dffbbe7e | 52 | // Useful for turning the LED display on and off with commands from the serial port. |
luisda130595 | 1:7421267b0777 | 53 | const int FFT_SIZE = 256; // Size of the FFT. |
tony1tf | 0:b8c9dffbbe7e | 54 | |
tony1tf | 0:b8c9dffbbe7e | 55 | //////////////////////////////////////////////////////////////////////////////// |
tony1tf | 0:b8c9dffbbe7e | 56 | // INTERNAL STATE |
tony1tf | 0:b8c9dffbbe7e | 57 | // These shouldn't be modified unless you know what you're doing. |
tony1tf | 0:b8c9dffbbe7e | 58 | //////////////////////////////////////////////////////////////////////////////// |
tony1tf | 0:b8c9dffbbe7e | 59 | const static arm_cfft_instance_f32 *S; |
tony1tf | 0:b8c9dffbbe7e | 60 | Ticker samplingTimer; |
tony1tf | 0:b8c9dffbbe7e | 61 | float samples[FFT_SIZE*2]; |
tony1tf | 0:b8c9dffbbe7e | 62 | float magnitudes[FFT_SIZE]; |
tony1tf | 0:b8c9dffbbe7e | 63 | int sampleCounter = 0; |
tony1tf | 0:b8c9dffbbe7e | 64 | |
luisda130595 | 1:7421267b0777 | 65 | int arrayPosition; |
luisda130595 | 1:7421267b0777 | 66 | int maxFrequencyValue; |
tony1tf | 0:b8c9dffbbe7e | 67 | |
luisda130595 | 1:7421267b0777 | 68 | int FFTFrequency; |
tony1tf | 0:b8c9dffbbe7e | 69 | |
tony1tf | 0:b8c9dffbbe7e | 70 | // Convert a frequency to the appropriate FFT bin it will fall within. |
tony1tf | 0:b8c9dffbbe7e | 71 | int frequencyToBin(float frequency) |
tony1tf | 0:b8c9dffbbe7e | 72 | { |
tony1tf | 0:b8c9dffbbe7e | 73 | float binFrequency = float(SAMPLE_RATE_HZ) / float(FFT_SIZE); |
tony1tf | 0:b8c9dffbbe7e | 74 | return int(frequency / binFrequency); |
tony1tf | 0:b8c9dffbbe7e | 75 | } |
tony1tf | 0:b8c9dffbbe7e | 76 | |
tony1tf | 0:b8c9dffbbe7e | 77 | |
tony1tf | 0:b8c9dffbbe7e | 78 | |
tony1tf | 0:b8c9dffbbe7e | 79 | //////////////////////////////////////////////////////////////////////////////// |
tony1tf | 0:b8c9dffbbe7e | 80 | // SAMPLING FUNCTIONS |
tony1tf | 0:b8c9dffbbe7e | 81 | //////////////////////////////////////////////////////////////////////////////// |
tony1tf | 0:b8c9dffbbe7e | 82 | |
tony1tf | 0:b8c9dffbbe7e | 83 | void samplingCallback() |
tony1tf | 0:b8c9dffbbe7e | 84 | { |
tony1tf | 0:b8c9dffbbe7e | 85 | // Read from the ADC and store the sample data |
tony1tf | 0:b8c9dffbbe7e | 86 | samples[sampleCounter] = (1023 * Audio) - 511.0f; |
tony1tf | 0:b8c9dffbbe7e | 87 | // Complex FFT functions require a coefficient for the imaginary part of the input. |
tony1tf | 0:b8c9dffbbe7e | 88 | // Since we only have real data, set this coefficient to zero. |
tony1tf | 0:b8c9dffbbe7e | 89 | samples[sampleCounter+1] = 0.0; |
tony1tf | 0:b8c9dffbbe7e | 90 | // Update sample buffer position and stop after the buffer is filled |
tony1tf | 0:b8c9dffbbe7e | 91 | sampleCounter += 2; |
tony1tf | 0:b8c9dffbbe7e | 92 | if (sampleCounter >= FFT_SIZE*2) { |
tony1tf | 0:b8c9dffbbe7e | 93 | samplingTimer.detach(); |
tony1tf | 0:b8c9dffbbe7e | 94 | } |
tony1tf | 0:b8c9dffbbe7e | 95 | } |
tony1tf | 0:b8c9dffbbe7e | 96 | |
tony1tf | 0:b8c9dffbbe7e | 97 | void samplingBegin() |
tony1tf | 0:b8c9dffbbe7e | 98 | { |
tony1tf | 0:b8c9dffbbe7e | 99 | // Reset sample buffer position and start callback at necessary rate. |
tony1tf | 0:b8c9dffbbe7e | 100 | sampleCounter = 0; |
tony1tf | 0:b8c9dffbbe7e | 101 | samplingTimer.attach_us(&samplingCallback, 1000000/SAMPLE_RATE_HZ); |
tony1tf | 0:b8c9dffbbe7e | 102 | } |
tony1tf | 0:b8c9dffbbe7e | 103 | |
tony1tf | 0:b8c9dffbbe7e | 104 | bool samplingIsDone() |
tony1tf | 0:b8c9dffbbe7e | 105 | { |
tony1tf | 0:b8c9dffbbe7e | 106 | return sampleCounter >= FFT_SIZE*2; |
tony1tf | 0:b8c9dffbbe7e | 107 | } |
tony1tf | 0:b8c9dffbbe7e | 108 | |
tony1tf | 0:b8c9dffbbe7e | 109 | //////////////////////////////////////////////////////////////////////////////// |
luisda130595 | 1:7421267b0777 | 110 | // FREQUENCY |
tony1tf | 0:b8c9dffbbe7e | 111 | //////////////////////////////////////////////////////////////////////////////// |
tony1tf | 0:b8c9dffbbe7e | 112 | |
luisda130595 | 1:7421267b0777 | 113 | |
luisda130595 | 1:7421267b0777 | 114 | void set_ArrayPosition() |
tony1tf | 0:b8c9dffbbe7e | 115 | { |
luisda130595 | 1:7421267b0777 | 116 | float maxValue = 0.0; |
tony1tf | 0:b8c9dffbbe7e | 117 | |
luisda130595 | 1:7421267b0777 | 118 | for(int counter=0; counter < FFT_SIZE; counter++) |
luisda130595 | 1:7421267b0777 | 119 | { |
luisda130595 | 1:7421267b0777 | 120 | if(magnitudes[counter] > maxValue){ |
luisda130595 | 1:7421267b0777 | 121 | maxValue = magnitudes[counter]; |
luisda130595 | 1:7421267b0777 | 122 | arrayPosition = counter+1; |
tony1tf | 0:b8c9dffbbe7e | 123 | } |
tony1tf | 0:b8c9dffbbe7e | 124 | } |
tony1tf | 0:b8c9dffbbe7e | 125 | } |
tony1tf | 0:b8c9dffbbe7e | 126 | |
luisda130595 | 1:7421267b0777 | 127 | int get_FFTFrequency() |
luisda130595 | 1:7421267b0777 | 128 | { |
luisda130595 | 1:7421267b0777 | 129 | maxFrequencyValue = SAMPLE_RATE_HZ/2; |
luisda130595 | 1:7421267b0777 | 130 | |
luisda130595 | 1:7421267b0777 | 131 | set_ArrayPosition(); |
luisda130595 | 1:7421267b0777 | 132 | |
luisda130595 | 1:7421267b0777 | 133 | return (maxFrequencyValue*arrayPosition)/FFT_SIZE; |
luisda130595 | 1:7421267b0777 | 134 | |
luisda130595 | 1:7421267b0777 | 135 | } |
tony1tf | 0:b8c9dffbbe7e | 136 | //////////////////////////////////////////////////////////////////////////////// |
tony1tf | 0:b8c9dffbbe7e | 137 | // MAIN FUNCTION |
tony1tf | 0:b8c9dffbbe7e | 138 | //////////////////////////////////////////////////////////////////////////////// |
tony1tf | 0:b8c9dffbbe7e | 139 | |
tony1tf | 0:b8c9dffbbe7e | 140 | int main() |
tony1tf | 0:b8c9dffbbe7e | 141 | { |
tony1tf | 0:b8c9dffbbe7e | 142 | NVIC_set_all_irq_priorities(1); |
tony1tf | 0:b8c9dffbbe7e | 143 | NVIC_SetPriority(UART0_IRQn, 0); |
tony1tf | 0:b8c9dffbbe7e | 144 | |
tony1tf | 0:b8c9dffbbe7e | 145 | // Begin sampling audio |
tony1tf | 0:b8c9dffbbe7e | 146 | samplingBegin(); |
tony1tf | 0:b8c9dffbbe7e | 147 | |
tony1tf | 0:b8c9dffbbe7e | 148 | // Init arm_ccft_32 |
tony1tf | 0:b8c9dffbbe7e | 149 | switch (FFT_SIZE) |
tony1tf | 0:b8c9dffbbe7e | 150 | { |
tony1tf | 0:b8c9dffbbe7e | 151 | case 16: |
tony1tf | 0:b8c9dffbbe7e | 152 | S = & arm_cfft_sR_f32_len16; |
tony1tf | 0:b8c9dffbbe7e | 153 | break; |
tony1tf | 0:b8c9dffbbe7e | 154 | case 32: |
tony1tf | 0:b8c9dffbbe7e | 155 | S = & arm_cfft_sR_f32_len32; |
tony1tf | 0:b8c9dffbbe7e | 156 | break; |
tony1tf | 0:b8c9dffbbe7e | 157 | case 64: |
tony1tf | 0:b8c9dffbbe7e | 158 | S = & arm_cfft_sR_f32_len64; |
tony1tf | 0:b8c9dffbbe7e | 159 | break; |
tony1tf | 0:b8c9dffbbe7e | 160 | case 128: |
tony1tf | 0:b8c9dffbbe7e | 161 | S = & arm_cfft_sR_f32_len128; |
tony1tf | 0:b8c9dffbbe7e | 162 | break; |
tony1tf | 0:b8c9dffbbe7e | 163 | case 256: |
tony1tf | 0:b8c9dffbbe7e | 164 | S = & arm_cfft_sR_f32_len256; |
tony1tf | 0:b8c9dffbbe7e | 165 | break; |
tony1tf | 0:b8c9dffbbe7e | 166 | case 512: |
tony1tf | 0:b8c9dffbbe7e | 167 | S = & arm_cfft_sR_f32_len512; |
tony1tf | 0:b8c9dffbbe7e | 168 | break; |
tony1tf | 0:b8c9dffbbe7e | 169 | case 1024: |
tony1tf | 0:b8c9dffbbe7e | 170 | S = & arm_cfft_sR_f32_len1024; |
tony1tf | 0:b8c9dffbbe7e | 171 | break; |
tony1tf | 0:b8c9dffbbe7e | 172 | case 2048: |
tony1tf | 0:b8c9dffbbe7e | 173 | S = & arm_cfft_sR_f32_len2048; |
tony1tf | 0:b8c9dffbbe7e | 174 | break; |
tony1tf | 0:b8c9dffbbe7e | 175 | case 4096: |
tony1tf | 0:b8c9dffbbe7e | 176 | S = & arm_cfft_sR_f32_len4096; |
tony1tf | 0:b8c9dffbbe7e | 177 | break; |
tony1tf | 0:b8c9dffbbe7e | 178 | } |
tony1tf | 0:b8c9dffbbe7e | 179 | |
luisda130595 | 1:7421267b0777 | 180 | while(true) { |
tony1tf | 0:b8c9dffbbe7e | 181 | // Calculate FFT if a full sample is available. |
tony1tf | 0:b8c9dffbbe7e | 182 | if (samplingIsDone()) { |
tony1tf | 0:b8c9dffbbe7e | 183 | // Run FFT on sample data. |
tony1tf | 0:b8c9dffbbe7e | 184 | arm_cfft_f32(S, samples, 0, 1); |
tony1tf | 0:b8c9dffbbe7e | 185 | // Calculate magnitude of complex numbers output by the FFT. |
tony1tf | 0:b8c9dffbbe7e | 186 | arm_cmplx_mag_f32(samples, magnitudes, FFT_SIZE); |
luisda130595 | 1:7421267b0777 | 187 | //Obtaining the value of the frequency |
luisda130595 | 1:7421267b0777 | 188 | FFTFrequency = get_FFTFrequency(); |
luisda130595 | 1:7421267b0777 | 189 | |
luisda130595 | 1:7421267b0777 | 190 | for(int i=0; |
luisda130595 | 1:7421267b0777 | 191 | pc.printf("Frequency is: ", FFTFrequency); |
luisda130595 | 1:7421267b0777 | 192 | pc.printf("\r\n ["); |
luisda130595 | 1:7421267b0777 | 193 | |
tony1tf | 0:b8c9dffbbe7e | 194 | // Restart audio sampling. |
tony1tf | 0:b8c9dffbbe7e | 195 | samplingBegin(); |
luisda130595 | 1:7421267b0777 | 196 | } |
tony1tf | 0:b8c9dffbbe7e | 197 | } |
luisda130595 | 1:7421267b0777 | 198 | |
tony1tf | 0:b8c9dffbbe7e | 199 | } |