I've been working on a simple data acquisition project using STM32L432 (nucleo board). The aim is to continuously read ADC, and whenever the value exceeds fixed threshold (trigger event), to collect given amount of samples and send back to PC (along with CRC control word for data integrity). The arithmetic is basic enough that DMA or INT modes were not of my interest. Just a quick test of the MCU performance. I am using a probe compensation output of a scope, generating 1 kHz square wave (amplitude in the range of the ADC input). Thus it is straightforward to measure the effective ADC sample rate (expected 5.33 Msps maximum conversion rate with full 12b resolution) observing the recorded waveform (both on the scope and on the PC).
The project was generated with the latest CubeMX (.ioc file attached), clock set to 80 MHz, ADC in continuous mode, async UART (230 kBaud). Compiled, loaded, debugged in the latest System Workbench for STM32. I have enlarged stack and heap just in case because I encountered some problems I try to understand:
1) Depending on the location (declaration and definition in main.c as a global or local variable, volatile or not, in "while(1)" or outside "while(1)" etc.) and size of the data buffer pData1 (3/2 of the intended size or original size + 1 for CRC word) the code seems to run with highly different speeds. I presume this is caused by conflicts(?) in MCU accessing SRAM.
I tried to affect the placement of my buffer variable (when declared global) using loader script and the "section" and "aligned" attributes, but without clear pattern.
2) After programming the board sometimes needs to be unplugged from the USB port to execute the newly uploaded code. Sometimes it hangs on HAL_RCC_OscConfig...
Seems that I may overwrite some local variables while accessing buffer, but the buffer index is well guarded for overrun.
The amount of registered samples is always the same = ABufferSize. Release compilation (-O3, -g1, -ffunction-sections -fdata-sections).
To sum up:
"uint16_t pData1[ABufferSize + 1];"
1) if the pData1 buffer is a global variable without modifiers, with the desired size (ABufferSize + 1 for CRC) the effective sample rate (combined ADC readout + instruction execution time, memory access) is ~6 Msps (>5.33). I expect accuracy loss of the ADC, but on the other hand the DR register should be synchronized. And I do not see the accuracy loss in data (post-analysis on PC).
2) if the pData1 is is a global volatile variable the MCU sometimes hangs on Hard Fault after calling HAL_RCC_OscConfig. Sometimes the program yields 5 Msps (close to what is expected).
3) if the pData1 is is a local variable declared just before "while(1)" - sample rate drops down to 2 Msps.
4) if the pData1 is is a local volatile variable declared just before "while(1)" - sample rate is also ~2 Msps.
5) if the pData1 is is a local variable declared inside "while(1)" - sample rate is also ~2 Msps.
6) if the pData1 is is a local volatile variable declared inside "while(1)" - sample rate is also ~2 Msps.
"uint16_t pData1[3 * ABufferSize / 2];"
1a) 5 Msps (the closest to what I would expect)
2a) Hangs on Hard Fault after calling HAL_RCC_OscConfig.
3a) 2.3 Msps
4a) 2.3 Msps
5a) 2.3 Msps
6a) 2.3 Msps
"uint16_t pData1[2 * ABufferSize];"
1b) like 1)
2b) 6 Msps, sometimes hangs.
3b) 4.5 Msps
4b) 4.5 Msps
5b) 4.5 Msps
6b) 4.5 Msps
PS: I have implemented a similar code on STM32F Discovery board, 3 ADC in interleaved mode, 7.2 Msps - no problems at all using DMA mode to a global small buffer, then copying to a larger buffer with similar trigger logic in between.