STM32 UART DMA Idle Detection
Jump to navigation
Jump to search
Using an UART to send and receive data is a very common way to communicate between two devices.
A common approach to receiving data from an UART is to have an interrupt generated after each character has been received. The problem with this approach is that a lot of interrupts will be generated leaving very few CPU cycles to process the received data without losing characters. A better approach is to use DMA for this, but this leaves another challenge since DMA in STM32 generally generate an interrupt when the buffer is half full and then another one when the buffer is full.
The Code
The callback (interrupt handler):
/** * @brief UART Event Callback. Fired on idle or if dma buffer half full or full. * @param huart Pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * @param offset A offset counter pointing to last valid character in DMA buffer. * @retval None */ void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t offset) { static uint16_t last_offset = 0; // Ignore if called twice (which will happen on every half buffer) if (offset != last_offset) { // If wrap around reset last_size if (offset < last_offset) last_offset = 0; while (last_offset < offset) { process_character((char) dmabuf[last_offset]); ++last_offset; } } }
We can now fire up the receiver:
HAL_UARTEx_ReceiveToIdle_DMA(&huart4, (uint8_t*) &dmabuf, DMA_BUFFER_SIZE);