STM32 UART DMA Idle Detection

From Stm32World Wiki
Revision as of 02:42, 12 April 2022 by Lth (talk | contribs)
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);


Miscellaneous Links