cancel
Showing results for 
Search instead for 
Did you mean: 

Change USART RX data retrieval from Rec Not Empty interrupt to DMA

CharlieMangold
Associate III

STM32G0B0RE, Low Level Drivers(no HAL), USART1

Our past 7-8 projects that use the older STM32F micros have used the USART Receiver Not Empty interrupt to drive reading of the data into a internal buffer. This allowed for the interrupt code to log the time of the byte and size of the current buffer. We are coding up changes to use the DMA engine but have run across questions that do not seem to be covered(or at least that we can find.)

 

	if(LL_USART_IsActiveFlag_RXNE_RXFNE(USART1) != RESET)
	{
		/* Read one byte from the receive data register and log the current time stamp */
		uart1RxBuffer[rxHead][uart1RX[rxHead].rxSize]	= LL_USART_ReceiveData9(USART1);
		uart1RX[rxHead].rxTime[uart1RX[rxHead].rxSize]	= timer3_get_count();
		uart1RX[rxHead].rxSize++;
    }

 

 When using the DMA to move data from the USART RX into memory there does not seem to be a clear way to track the current depth of the buffer. Setting the DMA config requires a size that needs to be set but because reception size is unknown, and can be as deep as 512 bytes, what would be the best method of tracking current depth? Our current non DMA method allows us to trace depth and also allows use of the buffers contents before the full packet has been received. The packet is determined by idle time on the USART RX line.

It does not seem possible to use a Transfer Complete interrupt(like we use in the TX direction) because of the unknown packet size(DMA triggers the TC by the programmed size.) We can use the USART RX Timeout interrupt(LL_USART_EnableRxTimeout(USART1)), but we would not be able to use the packet until the entire thing was received.

Is is possible to set the USART RX DMA size to 1 so that we could track the current buffer size and then use the USART RX Timeout interrupt to move the Rx buffer pointer the the next one?

Suggestions/Comments? Thanks.

10 REPLIES 10
CharlieMangold
Associate III

Still can't get the USART1 RX DMA to work. Current theory is that the DMAMUX is the issue. RM0454 Table 39 shows different Resources and the DMAMUX request inputs and the Low Level drivers USART RX definitions seem to match(LL_DMAMUX_SetRequestID(DMAMUX1, LL_DMA_CHANNEL_2, LL_DMAMUX_REQ_USART1_RX)), so I'm not sure where the misalignment could be. Maybe DMA channels need to be assigned to specific peripherals or in a specific order?

	// ----------------------------------------------------------------------------------------------
	// Init UART1 RX DMA
	LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_2, LL_DMAMUX_REQ_USART1_RX);
	LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
	LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_HIGH);
	LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MODE_CIRCULAR);
	LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);
	LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);
	LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);
	LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);
	LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, 512);

	LL_DMAMUX_SetRequestID(DMAMUX1, LL_DMA_CHANNEL_2, LL_DMAMUX_REQ_USART1_RX);
	LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_2, (uint32_t)(&uart1RxBuffer[0][0]),
							LL_USART_DMA_GetRegAddr(USART1, LL_USART_DMA_REG_DATA_RECEIVE),
							LL_DMA_DIRECTION_PERIPH_TO_MEMORY);

	/* Enable the USART1 RX DMA1 requests */
	LL_USART_EnableDMAReq_RX(USART1);

	// Enable transfer complete and transfer error interrupts.
	LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2);
	LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_2);
	// ----------------------------------------------------------------------------------------------