Audio Spectrum analyser - FFT using mbed-dsp - driving RGB(W) LED or PC python script.

Dependencies:   HSI2RGBW_PWM NVIC_set_all_priorities mbed-dsp mbed FastAnalogIn

Spectrum Analyzer

Code ported from Tony DiCola at AdaFruit FFT: Fun with Fourier Transforms.
Modifications were made to allow the use of the KL25Z on-board RGB LED or an external RGBW power LED.
See items marked with * in the next sections.

Main features

  • Uses mbed-dsp library.
  • Uses FastAnalogIn to allow a sample rate of 40kHz.
  • Display the audio spectrum on a single RGB(W) LED*.
  • Display the audio spectrum on your computer using an audio spectrogram tool (python script).
  • Change parameters using a terminal connection : Sample rate, min/max db, slowdown*.

Information

Detailed information and download of the python scripts is available here.

KL25Z wiring

Audio inputs
The software samples a single audio channel at 40kHz and applies a Fourier transform to return the frequency spectrum.
Analog input : PTC2.
A DC offset, and possibly some amplification or attenuation, is needed before the signal is fed into the analog inputs.
The opamp choice is not critical, just make sure it supports single supply operation.
Schematic
Currently, only one channel is used when the KL25Z is sampling at 40kHz.
/media/uploads/frankvnk/opamp_input_stage-tlc2264.png

External PWM outputs

PinColor
PTD4Red
PTA12Green
PTA4Blue
PTA5White

If you want to use a RGB LED, remove the last pin declaration (PTA5).
The conversion routine automatically switches from HSI/RGBW to HSI/RGB.
To use the external RGBW LED, enable following line in the code:

#define RGBW_ext // Disable this line when you want to use the KL25Z on-board RGB LED.

Commands

Parameters can be altered through the serial port Using a terminal program (eg : TeraTerm).
Communication settings : 38400 baud + local echo.
Each command needs to be terminated with a semicolon.
Use GET <command>; to read a parameter.
Use SET <command> <value>; to set a parameter.

CommandDescription
GET MAGNITUDES;Reads back the FFT magnitudes.
Number of magnitudes = PIXEL_COUNT.
GET SAMPLES;Reads back the current samples.
Number of samples = PIXEL_COUNT.
GET FFT_SIZE;The size of the FFT.
GET SAMPLE_RATE_HZ;Audio sample rate (Hz).
SET SAMPLE_RATE_HZ <value>;Change the audio sample rate (see also 'Limitations' below).
GET LEDS_ENABLED;LEDs enabled status.
SET LEDS_ENABLED <value>;Control if the LED's should display the spectrum or not.
1 is true, 0 is false.
GET SPECTRUM_MIN_DB;Audio intensity (in decibels) that maps to low LED brightness.
SET SPECTRUM_MIN_DB <value>;Change low sensitivity (0...100dB).
GET SPECTRUM_MAX_DB;Audio intensity (in decibels) that maps to high LED brightness.
SET SPECTRUM_MAX_DB <value>;Change high sensitivity (0...100dB).
GET SLOWDOWN;LED visualisation delay.
SET SLOWDOWN <value>;* Useful to visualize the spectrum using a single RGB(W) LED.
Without this command, the color values are shown too fast for the human eye.
This allows you to slow down the visualization without interfering in the FFT conversion.
Each frequency window is shown a little longer.
The number of frequency windows depends on the value of the PIXEL_COUNT variable.
[0...999] The larger the value, the longer each frequency window is shown - a good value is 4 when PIXEL_COUNT = 32 (choose a higher SLOWDOWN value when PIXEL_COUNT is lowered).
[1000...1000 + PIXEL_COUNT] Selecting a value within this range allows us to lock to a specific frequency window.

NOTE : PIXEL_COUNT is declared at compile time and determines the number of frequency windows (aka LED colors).

Limitations

The original code was written for a cortex-M4 processor.
For a cortex-M0 processor, following limitations apply:

SAMPLE_RATE_HZFFT_SIZE
1...40000max 64

Demo Videos

Parameter settings

SLOWDOWN16 (initial value - changed to 1000+ during the video to demonstrate the lock option).
SAMPLE_RATE_HZ40000
SPECTRUM_MIN_DB40.0
SPECTRUM_MAX_DB80.0
FFT_SIZE64
PIXEL_COUNT32

Using the on-board RGB LED
SLOWDOWN is set to different values (normal mode and locked mode).

Using an external 10W RGBW LED
SLOWDOWN is set to different values (normal mode and locked mode).

Spectrogram on Computer screen (serial input from KL25Z board

Committer:
frankvnk
Date:
Sat Mar 08 18:56:14 2014 +0000
Revision:
1:736b34e0f484
Parent:
0:0c037aff5039
Child:
2:035d551759a5
Replaced AnalogIn with FastAnalogIn

Who changed what in which revision?

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