Using DMA: ADC and UART without the CPU
Two practical DMA setups: keep filling a circular buffer with ADC values, and receive UART packets of unknown length.
ADC + circular DMA
DMA keeps writing the ADC scan results into an array. The CPU only has to read the array, and the latest values are there.
uint16_t adc_buf[4];
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_buf, 4); // keeps updating when set to circular mode
When collecting a long waveform, split the buffer in two and process the opposite half on each half-complete / complete interrupt (double buffering).
UART receive + IDLE line
This is the standard approach when the packet length is unknown.
- Keep receiving UART RX into a large buffer (for example 256 bytes) with circular DMA
- When the line is quiet for more than one byte time, an IDLE interrupt fires
- Work out the current write position from the DMA remaining count (NDTR) and process only the newly arrived section
HAL provides HAL_UARTEx_ReceiveToIdle_DMA().
Things to check
- DMA stream and channel numbers are fixed for each peripheral (see the table in the reference manual).
- Some chips have memory regions DMA cannot access (CCM RAM and DTCM on some STM32 parts).
- On chips with a cache (H7, F7), put DMA buffers in a non-cached region, or clean and invalidate the cache.