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 19:30:20 2014 +0000
Revision:
2:035d551759a5
Parent:
1:736b34e0f484
Replaced deprecated FFT calls with new ones.

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