Building a miniature spectrum analyzer
Over winter break, I built a miniature spectrum analyzer using an STM32 and PlatformIO. Doing this lets you code cross-platform between different frameworks, such as Arduino. Another advantage is that the platform allows you to mix code styles as you’ll see below, where I mixed the basic Arduino-style setup & loop with lower level STM32 HAL functions.
The idea was to continuously take an FFT of incoming audio samples from a microphone and send it out over USB to a computer that would run a python script to build the display. As easy as it sounds, there were a lot of quirks about the FFT and running it on real-time data that proved to be difficult to work with.
The CMSIS-DSP library that interfaces to ridiculously optimized mathematical functions on ARM processors did not link in any way on PlatformIO. So, I used an open-source library called ArduinoFFT, which introduced the issue of timing. Since this library was much slower, and not optimized at all for time, timing became much more of an issue when writing the code to perform the FFT.
The solution was to use DMA to pipe data from the ADC directly to memory. This way, we could use a ringed double buffer, where as one half fills with data, the other half is being processed.
I used a hardware timer on the STM32 to trigger an interrupt and time each sample to an accurate sample rate. Each interrupt would trigger the DMA to take a reading off the ADC, and pipe it into the buffer. I set up the DMA to trigger a callback when the buffer was half full, and full. This way, the callbacks would indicate to the processor when data was ready to be processed.
The main loop would check for this condition, then perform an FFT on this data and immediately start sending data over serial.
The python script on the other end would take in the 256 points of data, and display it on a graph using PyQtGraph.
The end result looked like this: