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 Tony Abbey

Committer:
tony1tf
Date:
Thu Jul 10 06:54:57 2014 +0000
Revision:
1:7c7539fba82b
Parent:
0:b8c9dffbbe7e
Child:
2:aa24865dfef5
latest slowdown to give good sensitivity

Who changed what in which revision?

UserRevisionLine numberNew 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"
tony1tf 0:b8c9dffbbe7e 12
tony1tf 0:b8c9dffbbe7e 13 Serial pc(USBTX, USBRX);
tony1tf 0:b8c9dffbbe7e 14
tony1tf 0:b8c9dffbbe7e 15 FastAnalogIn Audio(PTC2);
tony1tf 0:b8c9dffbbe7e 16
tony1tf 0:b8c9dffbbe7e 17 //#define RGBW_ext // Disable this line when you want to use the KL25Z on-board RGB LED.
tony1tf 0:b8c9dffbbe7e 18
tony1tf 0:b8c9dffbbe7e 19
tony1tf 0:b8c9dffbbe7e 20 #ifndef RGBW_ext
tony1tf 0:b8c9dffbbe7e 21 // RGB direct output to PWM channels - on-board RGB LED
tony1tf 0:b8c9dffbbe7e 22 PwmOut gled(LED_GREEN);
tony1tf 0:b8c9dffbbe7e 23 PwmOut rled(LED_RED);
tony1tf 0:b8c9dffbbe7e 24 PwmOut bled(LED_BLUE);
tony1tf 0:b8c9dffbbe7e 25 #else
tony1tf 0:b8c9dffbbe7e 26 // HSI to RGBW conversion with direct output to external PWM channels - RGBW LED
tony1tf 0:b8c9dffbbe7e 27 // hsi2rgbw_pwm led(PTD4, PTA12, PTA4, PTA5); //Red, Green, Blue, White
tony1tf 0:b8c9dffbbe7e 28 #endif
tony1tf 0:b8c9dffbbe7e 29
tony1tf 0:b8c9dffbbe7e 30 // Dummy ISR for disabling NMI on PTA4 - !! DO NOT REMOVE THIS !!
tony1tf 0:b8c9dffbbe7e 31 // More info at https://mbed.org/questions/1387/How-can-I-access-the-FTFA_FOPT-register-/
tony1tf 0:b8c9dffbbe7e 32 extern "C" void NMI_Handler() {
tony1tf 0:b8c9dffbbe7e 33 DigitalIn test(PTA4);
tony1tf 0:b8c9dffbbe7e 34 }
tony1tf 0:b8c9dffbbe7e 35
tony1tf 0:b8c9dffbbe7e 36
tony1tf 0:b8c9dffbbe7e 37 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 38 // CONFIGURATION
tony1tf 0:b8c9dffbbe7e 39 // These values can be changed to alter the behavior of the spectrum display.
tony1tf 0:b8c9dffbbe7e 40 // KL25Z limitations
tony1tf 0:b8c9dffbbe7e 41 // -----------------
tony1tf 0:b8c9dffbbe7e 42 // - When used with the Spectrogram python script :
tony1tf 0:b8c9dffbbe7e 43 // There is a substantial time lag between the music and the screen output.
tony1tf 0:b8c9dffbbe7e 44 // Max allowed SAMPLE_RATE_HZ is 40000
tony1tf 0:b8c9dffbbe7e 45 // Max allowed FFT_SIZE is 64
tony1tf 0:b8c9dffbbe7e 46 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 47
tony1tf 1:7c7539fba82b 48 int SLOWDOWN = 0; // Create an optical delay in spectrumLoop - useful when only one RGB led is used.
tony1tf 0:b8c9dffbbe7e 49 // Only active when nonzero.
tony1tf 0:b8c9dffbbe7e 50 // A value >= 1000 and <= 1000 + PIXEL_COUNT fixes the output to a single frequency
tony1tf 0:b8c9dffbbe7e 51 // window = a single color.
tony1tf 0:b8c9dffbbe7e 52 int SAMPLE_RATE_HZ = 20000; // Sample rate of the audio in hertz.
tony1tf 0:b8c9dffbbe7e 53 float SPECTRUM_MIN_DB = 20.0; // Audio intensity (in decibels) that maps to low LED brightness.
tony1tf 0:b8c9dffbbe7e 54 float SPECTRUM_MAX_DB = 80.0; // Audio intensity (in decibels) that maps to high LED brightness.
tony1tf 0:b8c9dffbbe7e 55 int LEDS_ENABLED = 1; // Control if the LED's should display the spectrum or not. 1 is true, 0 is false.
tony1tf 0:b8c9dffbbe7e 56 // Useful for turning the LED display on and off with commands from the serial port.
tony1tf 0:b8c9dffbbe7e 57 const int FFT_SIZE = 64; // Size of the FFT.
tony1tf 0:b8c9dffbbe7e 58 const int PIXEL_COUNT = 3; // Number of pixels (RGB LED). You should be able to increase this without
tony1tf 0:b8c9dffbbe7e 59 // any other changes to the program.
tony1tf 0:b8c9dffbbe7e 60 const int MAX_CHARS = 65; // Max size of the input command buffer
tony1tf 1:7c7539fba82b 61 int PRINT_ON = 0; // flag to send chars continually to serial output
tony1tf 0:b8c9dffbbe7e 62
tony1tf 0:b8c9dffbbe7e 63 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 64 // INTERNAL STATE
tony1tf 0:b8c9dffbbe7e 65 // These shouldn't be modified unless you know what you're doing.
tony1tf 0:b8c9dffbbe7e 66 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 67 const static arm_cfft_instance_f32 *S;
tony1tf 0:b8c9dffbbe7e 68 Ticker samplingTimer;
tony1tf 0:b8c9dffbbe7e 69 float samples[FFT_SIZE*2];
tony1tf 0:b8c9dffbbe7e 70 float magnitudes[FFT_SIZE];
tony1tf 0:b8c9dffbbe7e 71 int sampleCounter = 0;
tony1tf 0:b8c9dffbbe7e 72 char commandBuffer[MAX_CHARS];
tony1tf 0:b8c9dffbbe7e 73 float frequencyWindow[PIXEL_COUNT+1];
tony1tf 0:b8c9dffbbe7e 74 float hues[PIXEL_COUNT];
tony1tf 0:b8c9dffbbe7e 75 bool commandRecv = 0;
tony1tf 0:b8c9dffbbe7e 76 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 77 // UTILITY FUNCTIONS
tony1tf 0:b8c9dffbbe7e 78 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 79
tony1tf 0:b8c9dffbbe7e 80 void rxisr() {
tony1tf 0:b8c9dffbbe7e 81 char c = pc.getc();
tony1tf 0:b8c9dffbbe7e 82 // Add any characters that aren't the end of a command (semicolon) to the input buffer.
tony1tf 0:b8c9dffbbe7e 83 if (c != ';') {
tony1tf 0:b8c9dffbbe7e 84 c = toupper(c);
tony1tf 0:b8c9dffbbe7e 85 strncat(commandBuffer, &c, 1);
tony1tf 0:b8c9dffbbe7e 86 } else {
tony1tf 0:b8c9dffbbe7e 87 // Parse the command because an end of command token was encountered.
tony1tf 0:b8c9dffbbe7e 88 commandRecv = 1;
tony1tf 0:b8c9dffbbe7e 89 }
tony1tf 0:b8c9dffbbe7e 90 }
tony1tf 0:b8c9dffbbe7e 91
tony1tf 0:b8c9dffbbe7e 92 // Compute the average magnitude of a target frequency window vs. all other frequencies.
tony1tf 0:b8c9dffbbe7e 93 void windowMean(float* magnitudes, int lowBin, int highBin, float* windowMean, float* otherMean)
tony1tf 0:b8c9dffbbe7e 94 {
tony1tf 0:b8c9dffbbe7e 95 *windowMean = 0;
tony1tf 0:b8c9dffbbe7e 96 *otherMean = 0;
tony1tf 0:b8c9dffbbe7e 97 // Notice the first magnitude bin is skipped because it represents the
tony1tf 0:b8c9dffbbe7e 98 // average power of the signal.
tony1tf 0:b8c9dffbbe7e 99 for (int i = 1; i < FFT_SIZE/2; ++i) {
tony1tf 0:b8c9dffbbe7e 100 if (i >= lowBin && i <= highBin) {
tony1tf 0:b8c9dffbbe7e 101 *windowMean += magnitudes[i];
tony1tf 0:b8c9dffbbe7e 102 } else {
tony1tf 0:b8c9dffbbe7e 103 *otherMean += magnitudes[i];
tony1tf 0:b8c9dffbbe7e 104 }
tony1tf 0:b8c9dffbbe7e 105 }
tony1tf 0:b8c9dffbbe7e 106 *windowMean /= (highBin - lowBin) + 1;
tony1tf 0:b8c9dffbbe7e 107 *otherMean /= (FFT_SIZE / 2 - (highBin - lowBin));
tony1tf 0:b8c9dffbbe7e 108 }
tony1tf 0:b8c9dffbbe7e 109
tony1tf 0:b8c9dffbbe7e 110 // Convert a frequency to the appropriate FFT bin it will fall within.
tony1tf 0:b8c9dffbbe7e 111 int frequencyToBin(float frequency)
tony1tf 0:b8c9dffbbe7e 112 {
tony1tf 0:b8c9dffbbe7e 113 float binFrequency = float(SAMPLE_RATE_HZ) / float(FFT_SIZE);
tony1tf 0:b8c9dffbbe7e 114 return int(frequency / binFrequency);
tony1tf 0:b8c9dffbbe7e 115 }
tony1tf 0:b8c9dffbbe7e 116
tony1tf 0:b8c9dffbbe7e 117
tony1tf 0:b8c9dffbbe7e 118 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 119 // SPECTRUM DISPLAY FUNCTIONS
tony1tf 0:b8c9dffbbe7e 120 ///////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 121
tony1tf 0:b8c9dffbbe7e 122 void spectrumSetup()
tony1tf 0:b8c9dffbbe7e 123 {
tony1tf 0:b8c9dffbbe7e 124 // Set the frequency window values by evenly dividing the possible frequency
tony1tf 0:b8c9dffbbe7e 125 // spectrum across the number of neo pixels.
tony1tf 0:b8c9dffbbe7e 126 float windowSize = (SAMPLE_RATE_HZ / 2.0) / float(PIXEL_COUNT);
tony1tf 0:b8c9dffbbe7e 127 for (int i = 0; i < PIXEL_COUNT+1; ++i) {
tony1tf 0:b8c9dffbbe7e 128 frequencyWindow[i] = i*windowSize;
tony1tf 0:b8c9dffbbe7e 129 }
tony1tf 0:b8c9dffbbe7e 130
tony1tf 0:b8c9dffbbe7e 131 }
tony1tf 0:b8c9dffbbe7e 132
tony1tf 0:b8c9dffbbe7e 133 void spectrumLoop()
tony1tf 0:b8c9dffbbe7e 134 {
tony1tf 0:b8c9dffbbe7e 135 // Update each LED based on the intensity of the audio
tony1tf 0:b8c9dffbbe7e 136 // in the associated frequency window.
tony1tf 0:b8c9dffbbe7e 137 static int SLrpt = 0, SLpixcnt = 0;
tony1tf 0:b8c9dffbbe7e 138 int SLpixend = 0;
tony1tf 0:b8c9dffbbe7e 139 float intensity, otherMean;
tony1tf 0:b8c9dffbbe7e 140 if(SLOWDOWN != 0)
tony1tf 0:b8c9dffbbe7e 141 {
tony1tf 0:b8c9dffbbe7e 142 if(SLOWDOWN >= 1000)
tony1tf 0:b8c9dffbbe7e 143 {
tony1tf 0:b8c9dffbbe7e 144 if(SLOWDOWN <= (1000 + PIXEL_COUNT-1))
tony1tf 0:b8c9dffbbe7e 145 {
tony1tf 0:b8c9dffbbe7e 146 SLpixcnt = SLOWDOWN - 1000;
tony1tf 0:b8c9dffbbe7e 147 SLrpt = 0;
tony1tf 0:b8c9dffbbe7e 148 SLpixend = SLpixcnt + 1;
tony1tf 0:b8c9dffbbe7e 149 }
tony1tf 0:b8c9dffbbe7e 150 else
tony1tf 0:b8c9dffbbe7e 151 SLOWDOWN = 0;
tony1tf 0:b8c9dffbbe7e 152 }
tony1tf 0:b8c9dffbbe7e 153 else
tony1tf 0:b8c9dffbbe7e 154 {
tony1tf 0:b8c9dffbbe7e 155 SLrpt++;
tony1tf 0:b8c9dffbbe7e 156 if (SLrpt >= SLOWDOWN)
tony1tf 0:b8c9dffbbe7e 157 {
tony1tf 0:b8c9dffbbe7e 158 SLrpt = 0;
tony1tf 0:b8c9dffbbe7e 159 SLpixcnt = SLpixcnt < PIXEL_COUNT-1 ? ++SLpixcnt : 0;
tony1tf 0:b8c9dffbbe7e 160 }
tony1tf 0:b8c9dffbbe7e 161 SLpixend = SLpixcnt + 1;
tony1tf 0:b8c9dffbbe7e 162 }
tony1tf 0:b8c9dffbbe7e 163 }
tony1tf 0:b8c9dffbbe7e 164 else
tony1tf 0:b8c9dffbbe7e 165 {
tony1tf 0:b8c9dffbbe7e 166 SLpixcnt = 0;
tony1tf 0:b8c9dffbbe7e 167 SLrpt = 0;
tony1tf 0:b8c9dffbbe7e 168 SLpixend = PIXEL_COUNT;
tony1tf 0:b8c9dffbbe7e 169 }
tony1tf 0:b8c9dffbbe7e 170 for (int i = SLpixcnt; i < SLpixend; ++i) {
tony1tf 0:b8c9dffbbe7e 171 windowMean(magnitudes,
tony1tf 0:b8c9dffbbe7e 172 frequencyToBin(frequencyWindow[i]),
tony1tf 0:b8c9dffbbe7e 173 frequencyToBin(frequencyWindow[i+1]),
tony1tf 0:b8c9dffbbe7e 174 &intensity,
tony1tf 0:b8c9dffbbe7e 175 &otherMean);
tony1tf 0:b8c9dffbbe7e 176 // Convert intensity to decibels.
tony1tf 0:b8c9dffbbe7e 177 intensity = 20.0*log10(intensity);
tony1tf 0:b8c9dffbbe7e 178 // Scale the intensity and clamp between 0 and 1.0.
tony1tf 0:b8c9dffbbe7e 179 intensity -= SPECTRUM_MIN_DB;
tony1tf 0:b8c9dffbbe7e 180 intensity = intensity < 0.0 ? 0.0 : intensity;
tony1tf 0:b8c9dffbbe7e 181 intensity /= (SPECTRUM_MAX_DB-SPECTRUM_MIN_DB);
tony1tf 0:b8c9dffbbe7e 182 intensity = intensity > 1.0 ? 1.0 : intensity;
tony1tf 0:b8c9dffbbe7e 183 hues[i]=intensity;
tony1tf 0:b8c9dffbbe7e 184 }
tony1tf 0:b8c9dffbbe7e 185 rled=1.0-hues[0] ; // onboard LED is common anode so inversion needed
tony1tf 0:b8c9dffbbe7e 186 gled=1.0-hues[1];
tony1tf 0:b8c9dffbbe7e 187 bled=1.0-hues[2];
tony1tf 0:b8c9dffbbe7e 188 }
tony1tf 0:b8c9dffbbe7e 189
tony1tf 0:b8c9dffbbe7e 190
tony1tf 0:b8c9dffbbe7e 191 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 192 // SAMPLING FUNCTIONS
tony1tf 0:b8c9dffbbe7e 193 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 194
tony1tf 0:b8c9dffbbe7e 195 void samplingCallback()
tony1tf 0:b8c9dffbbe7e 196 {
tony1tf 0:b8c9dffbbe7e 197 // Read from the ADC and store the sample data
tony1tf 0:b8c9dffbbe7e 198 samples[sampleCounter] = (1023 * Audio) - 511.0f;
tony1tf 0:b8c9dffbbe7e 199 // Complex FFT functions require a coefficient for the imaginary part of the input.
tony1tf 0:b8c9dffbbe7e 200 // Since we only have real data, set this coefficient to zero.
tony1tf 0:b8c9dffbbe7e 201 samples[sampleCounter+1] = 0.0;
tony1tf 0:b8c9dffbbe7e 202 // Update sample buffer position and stop after the buffer is filled
tony1tf 0:b8c9dffbbe7e 203 sampleCounter += 2;
tony1tf 0:b8c9dffbbe7e 204 if (sampleCounter >= FFT_SIZE*2) {
tony1tf 0:b8c9dffbbe7e 205 samplingTimer.detach();
tony1tf 0:b8c9dffbbe7e 206 }
tony1tf 0:b8c9dffbbe7e 207 }
tony1tf 0:b8c9dffbbe7e 208
tony1tf 0:b8c9dffbbe7e 209 void samplingBegin()
tony1tf 0:b8c9dffbbe7e 210 {
tony1tf 0:b8c9dffbbe7e 211 // Reset sample buffer position and start callback at necessary rate.
tony1tf 0:b8c9dffbbe7e 212 sampleCounter = 0;
tony1tf 0:b8c9dffbbe7e 213 samplingTimer.attach_us(&samplingCallback, 1000000/SAMPLE_RATE_HZ);
tony1tf 0:b8c9dffbbe7e 214 }
tony1tf 0:b8c9dffbbe7e 215
tony1tf 0:b8c9dffbbe7e 216 bool samplingIsDone()
tony1tf 0:b8c9dffbbe7e 217 {
tony1tf 0:b8c9dffbbe7e 218 return sampleCounter >= FFT_SIZE*2;
tony1tf 0:b8c9dffbbe7e 219 }
tony1tf 0:b8c9dffbbe7e 220
tony1tf 0:b8c9dffbbe7e 221
tony1tf 0:b8c9dffbbe7e 222 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 223 // COMMAND PARSING FUNCTIONS
tony1tf 0:b8c9dffbbe7e 224 // These functions allow parsing simple commands input on the serial port.
tony1tf 0:b8c9dffbbe7e 225 // Commands allow reading and writing variables that control the device.
tony1tf 0:b8c9dffbbe7e 226 //
tony1tf 0:b8c9dffbbe7e 227 // All commands must end with a semicolon character.
tony1tf 0:b8c9dffbbe7e 228 //
tony1tf 0:b8c9dffbbe7e 229 // Example commands are:
tony1tf 0:b8c9dffbbe7e 230 // GET SAMPLE_RATE_HZ;
tony1tf 0:b8c9dffbbe7e 231 // - Get the sample rate of the device.
tony1tf 0:b8c9dffbbe7e 232 // SET SAMPLE_RATE_HZ 400;
tony1tf 0:b8c9dffbbe7e 233 // - Set the sample rate of the device to 400 hertz.
tony1tf 0:b8c9dffbbe7e 234 //
tony1tf 0:b8c9dffbbe7e 235 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 236
tony1tf 0:b8c9dffbbe7e 237 void parseCommand(char* command)
tony1tf 1:7c7539fba82b 238 {
tony1tf 0:b8c9dffbbe7e 239 if (strcmp(command, "GET MAGNITUDES") == 0) {
tony1tf 0:b8c9dffbbe7e 240 for (int i = 0; i < FFT_SIZE; ++i) {
tony1tf 0:b8c9dffbbe7e 241 printf("%f\r\n", magnitudes[i]);
tony1tf 0:b8c9dffbbe7e 242 }
tony1tf 0:b8c9dffbbe7e 243 } else if (strcmp(command, "GET SAMPLES") == 0) {
tony1tf 0:b8c9dffbbe7e 244 for (int i = 0; i < FFT_SIZE*2; i+=2) {
tony1tf 0:b8c9dffbbe7e 245 printf("%f\r\n", samples[i]);
tony1tf 0:b8c9dffbbe7e 246 }
tony1tf 0:b8c9dffbbe7e 247 } else if (strcmp(command, "GET FFT_SIZE") == 0) {
tony1tf 0:b8c9dffbbe7e 248 printf("%d\r\n", FFT_SIZE);
tony1tf 0:b8c9dffbbe7e 249 } else if (strcmp(command, "GET SAMPLE_RATE_HZ") == 0) {
tony1tf 0:b8c9dffbbe7e 250 printf("%d\r\n", SAMPLE_RATE_HZ);
tony1tf 0:b8c9dffbbe7e 251 } else if (strstr(command, "SET SAMPLE_RATE_HZ") != NULL) {
tony1tf 0:b8c9dffbbe7e 252 SAMPLE_RATE_HZ = (typeof(SAMPLE_RATE_HZ)) atof(command+(sizeof("SET SAMPLE_RATE_HZ")-1));
tony1tf 0:b8c9dffbbe7e 253 } else if (strcmp(command, "GET LEDS_ENABLED") == 0) {
tony1tf 0:b8c9dffbbe7e 254 printf("%d\r\n", LEDS_ENABLED);
tony1tf 0:b8c9dffbbe7e 255 } else if (strstr(command, "SET LEDS_ENABLED") != NULL) {
tony1tf 0:b8c9dffbbe7e 256 LEDS_ENABLED = (typeof(LEDS_ENABLED)) atof(command+(sizeof("SET LEDS_ENABLED")-1));
tony1tf 0:b8c9dffbbe7e 257 } else if (strcmp(command, "GET SPECTRUM_MIN_DB") == 0) {
tony1tf 0:b8c9dffbbe7e 258 printf("%f\r\n", SPECTRUM_MIN_DB);
tony1tf 0:b8c9dffbbe7e 259 } else if (strstr(command, "SET SPECTRUM_MIN_DB") != NULL) {
tony1tf 0:b8c9dffbbe7e 260 SPECTRUM_MIN_DB = (typeof(SPECTRUM_MIN_DB)) atof(command+(sizeof("SET SPECTRUM_MIN_DB")-1));
tony1tf 0:b8c9dffbbe7e 261 } else if (strcmp(command, "GET SPECTRUM_MAX_DB") == 0) {
tony1tf 0:b8c9dffbbe7e 262 printf("%f\r\n", SPECTRUM_MAX_DB);
tony1tf 0:b8c9dffbbe7e 263 } else if (strstr(command, "SET SPECTRUM_MAX_DB") != NULL) {
tony1tf 0:b8c9dffbbe7e 264 SPECTRUM_MAX_DB = (typeof(SPECTRUM_MAX_DB)) atof(command+(sizeof("SET SPECTRUM_MAX_DB")-1));
tony1tf 0:b8c9dffbbe7e 265 } else if (strcmp(command, "GET SLOWDOWN") == 0) {
tony1tf 0:b8c9dffbbe7e 266 printf("%d\r\n", SLOWDOWN);
tony1tf 0:b8c9dffbbe7e 267 } else if (strstr(command, "SET SLOWDOWN") != NULL) {
tony1tf 0:b8c9dffbbe7e 268 SLOWDOWN = (typeof(SLOWDOWN)) atoi(command+(sizeof("SET SLOWDOWN")-1));
tony1tf 1:7c7539fba82b 269 } else if (strcmp(command, "GET HUES") == 0) {
tony1tf 1:7c7539fba82b 270 for (int i = 0; i < PIXEL_COUNT; ++i) {
tony1tf 1:7c7539fba82b 271 printf("%f\r\n", hues[i]);
tony1tf 1:7c7539fba82b 272 }
tony1tf 1:7c7539fba82b 273 } else if (strcmp(command, "GET FREQUENCIES") == 0) {
tony1tf 1:7c7539fba82b 274 for (int i = 0; i < PIXEL_COUNT; ++i) {
tony1tf 1:7c7539fba82b 275 printf("%f\r\n", frequencyWindow[i]);
tony1tf 1:7c7539fba82b 276 }
tony1tf 1:7c7539fba82b 277 } else if (strcmp(command, "PRINT_ON") == 0) {
tony1tf 1:7c7539fba82b 278 PRINT_ON = 1;
tony1tf 1:7c7539fba82b 279 } else if (strcmp(command, "PRINT_OFF") == 0) {
tony1tf 1:7c7539fba82b 280 PRINT_ON = 0;
tony1tf 1:7c7539fba82b 281 }
tony1tf 0:b8c9dffbbe7e 282 // Update spectrum display values if sample rate was changed.
tony1tf 0:b8c9dffbbe7e 283 if (strstr(command, "SET SAMPLE_RATE_HZ ") != NULL) {
tony1tf 0:b8c9dffbbe7e 284 spectrumSetup();
tony1tf 0:b8c9dffbbe7e 285 }
tony1tf 0:b8c9dffbbe7e 286
tony1tf 0:b8c9dffbbe7e 287
tony1tf 0:b8c9dffbbe7e 288 // Turn off the LEDs if the state changed.
tony1tf 0:b8c9dffbbe7e 289 if (LEDS_ENABLED == 0) {
tony1tf 0:b8c9dffbbe7e 290 }
tony1tf 0:b8c9dffbbe7e 291 }
tony1tf 0:b8c9dffbbe7e 292
tony1tf 0:b8c9dffbbe7e 293 void parserLoop()
tony1tf 0:b8c9dffbbe7e 294 {
tony1tf 0:b8c9dffbbe7e 295 // Process any incoming characters from the serial port
tony1tf 0:b8c9dffbbe7e 296 while (pc.readable()) {
tony1tf 0:b8c9dffbbe7e 297 char c = pc.getc();
tony1tf 0:b8c9dffbbe7e 298 // (doesnt work!) printf("%c",c); // echo characters typed
tony1tf 0:b8c9dffbbe7e 299 // Add any characters that aren't the end of a command (semicolon) to the input buffer.
tony1tf 0:b8c9dffbbe7e 300 if (c != ';') {
tony1tf 0:b8c9dffbbe7e 301 c = toupper(c);
tony1tf 0:b8c9dffbbe7e 302 strncat(commandBuffer, &c, 1);
tony1tf 0:b8c9dffbbe7e 303 } else {
tony1tf 0:b8c9dffbbe7e 304 // Parse the command because an end of command token was encountered.
tony1tf 0:b8c9dffbbe7e 305 parseCommand(commandBuffer);
tony1tf 0:b8c9dffbbe7e 306 // Clear the input buffer
tony1tf 0:b8c9dffbbe7e 307 memset(commandBuffer, 0, sizeof(commandBuffer));
tony1tf 0:b8c9dffbbe7e 308 }
tony1tf 0:b8c9dffbbe7e 309 }
tony1tf 0:b8c9dffbbe7e 310 }
tony1tf 0:b8c9dffbbe7e 311
tony1tf 0:b8c9dffbbe7e 312 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 313 // MAIN FUNCTION
tony1tf 0:b8c9dffbbe7e 314 ////////////////////////////////////////////////////////////////////////////////
tony1tf 0:b8c9dffbbe7e 315
tony1tf 0:b8c9dffbbe7e 316 int main()
tony1tf 0:b8c9dffbbe7e 317 {
tony1tf 0:b8c9dffbbe7e 318 NVIC_set_all_irq_priorities(1);
tony1tf 0:b8c9dffbbe7e 319 NVIC_SetPriority(UART0_IRQn, 0);
tony1tf 0:b8c9dffbbe7e 320 // Set up serial port.
tony1tf 0:b8c9dffbbe7e 321 pc.baud (38400);
tony1tf 0:b8c9dffbbe7e 322 pc.attach(&rxisr);
tony1tf 0:b8c9dffbbe7e 323
tony1tf 0:b8c9dffbbe7e 324 // Clear the input command buffer
tony1tf 0:b8c9dffbbe7e 325 memset(commandBuffer, 0, sizeof(commandBuffer));
tony1tf 0:b8c9dffbbe7e 326
tony1tf 0:b8c9dffbbe7e 327 // Initialize spectrum display
tony1tf 0:b8c9dffbbe7e 328 spectrumSetup();
tony1tf 0:b8c9dffbbe7e 329
tony1tf 0:b8c9dffbbe7e 330 // Begin sampling audio
tony1tf 0:b8c9dffbbe7e 331 samplingBegin();
tony1tf 0:b8c9dffbbe7e 332
tony1tf 0:b8c9dffbbe7e 333 // Init arm_ccft_32
tony1tf 0:b8c9dffbbe7e 334 switch (FFT_SIZE)
tony1tf 0:b8c9dffbbe7e 335 {
tony1tf 0:b8c9dffbbe7e 336 case 16:
tony1tf 0:b8c9dffbbe7e 337 S = & arm_cfft_sR_f32_len16;
tony1tf 0:b8c9dffbbe7e 338 break;
tony1tf 0:b8c9dffbbe7e 339 case 32:
tony1tf 0:b8c9dffbbe7e 340 S = & arm_cfft_sR_f32_len32;
tony1tf 0:b8c9dffbbe7e 341 break;
tony1tf 0:b8c9dffbbe7e 342 case 64:
tony1tf 0:b8c9dffbbe7e 343 S = & arm_cfft_sR_f32_len64;
tony1tf 0:b8c9dffbbe7e 344 break;
tony1tf 0:b8c9dffbbe7e 345 case 128:
tony1tf 0:b8c9dffbbe7e 346 S = & arm_cfft_sR_f32_len128;
tony1tf 0:b8c9dffbbe7e 347 break;
tony1tf 0:b8c9dffbbe7e 348 case 256:
tony1tf 0:b8c9dffbbe7e 349 S = & arm_cfft_sR_f32_len256;
tony1tf 0:b8c9dffbbe7e 350 break;
tony1tf 0:b8c9dffbbe7e 351 case 512:
tony1tf 0:b8c9dffbbe7e 352 S = & arm_cfft_sR_f32_len512;
tony1tf 0:b8c9dffbbe7e 353 break;
tony1tf 0:b8c9dffbbe7e 354 case 1024:
tony1tf 0:b8c9dffbbe7e 355 S = & arm_cfft_sR_f32_len1024;
tony1tf 0:b8c9dffbbe7e 356 break;
tony1tf 0:b8c9dffbbe7e 357 case 2048:
tony1tf 0:b8c9dffbbe7e 358 S = & arm_cfft_sR_f32_len2048;
tony1tf 0:b8c9dffbbe7e 359 break;
tony1tf 0:b8c9dffbbe7e 360 case 4096:
tony1tf 0:b8c9dffbbe7e 361 S = & arm_cfft_sR_f32_len4096;
tony1tf 0:b8c9dffbbe7e 362 break;
tony1tf 0:b8c9dffbbe7e 363 }
tony1tf 0:b8c9dffbbe7e 364
tony1tf 0:b8c9dffbbe7e 365 while(1) {
tony1tf 0:b8c9dffbbe7e 366 // Calculate FFT if a full sample is available.
tony1tf 0:b8c9dffbbe7e 367 if (samplingIsDone()) {
tony1tf 0:b8c9dffbbe7e 368 // Run FFT on sample data.
tony1tf 0:b8c9dffbbe7e 369 arm_cfft_f32(S, samples, 0, 1);
tony1tf 0:b8c9dffbbe7e 370 // Calculate magnitude of complex numbers output by the FFT.
tony1tf 0:b8c9dffbbe7e 371 arm_cmplx_mag_f32(samples, magnitudes, FFT_SIZE);
tony1tf 0:b8c9dffbbe7e 372
tony1tf 0:b8c9dffbbe7e 373 if (LEDS_ENABLED == 1) {
tony1tf 0:b8c9dffbbe7e 374 spectrumLoop();
tony1tf 0:b8c9dffbbe7e 375 }
tony1tf 1:7c7539fba82b 376 wait_ms(10);
tony1tf 0:b8c9dffbbe7e 377 // Restart audio sampling.
tony1tf 0:b8c9dffbbe7e 378 samplingBegin();
tony1tf 1:7c7539fba82b 379 if (PRINT_ON == 1) {
tony1tf 1:7c7539fba82b 380 for (int i = 0; i < PIXEL_COUNT; ++i) {
tony1tf 1:7c7539fba82b 381 printf("%f\r\n", hues[i]);
tony1tf 1:7c7539fba82b 382 }
tony1tf 1:7c7539fba82b 383 }
tony1tf 1:7c7539fba82b 384 }
tony1tf 0:b8c9dffbbe7e 385
tony1tf 0:b8c9dffbbe7e 386 // Parse any pending commands.
tony1tf 0:b8c9dffbbe7e 387 if(commandRecv) {
tony1tf 0:b8c9dffbbe7e 388 // pc.attach(NULL);
tony1tf 0:b8c9dffbbe7e 389 parseCommand(commandBuffer);
tony1tf 0:b8c9dffbbe7e 390 commandRecv = 0;
tony1tf 0:b8c9dffbbe7e 391 // Clear the input buffer
tony1tf 0:b8c9dffbbe7e 392 memset(commandBuffer, 0, sizeof(commandBuffer));
tony1tf 0:b8c9dffbbe7e 393 // pc.attach(&rxisr);
tony1tf 0:b8c9dffbbe7e 394 }
tony1tf 0:b8c9dffbbe7e 395 }
tony1tf 0:b8c9dffbbe7e 396 }