Skip to main content
Associate II
October 10, 2023
Question

STM32 UART Transmit stops responding after some time

  • October 10, 2023
  • 6 replies
  • 2724 views

Hi all,

I am using a STM32L476RG NUCLEO Board with FreeRTOS and STM32 iCUBE LoRaWAN stack. I have a UART interface connected to Raspberry Pi, which periodically sends and receives data to-from STM32. I am using a circular buffer with DMA and IDLE Line detection as amount of data I receive is not fixed.

(https://github.com/controllerstech/STM32/tree/master/UART%20CIRCULAR%20BUFFER)

However,  UART Transmit stops after sometime. I have followed the instructions  in

https://community.st.com/t5/stm32-mcus-products/stm32-uart-interrupt-stops-working-after-1-hour/td-p/99642

And have stopped and restarted my HAL_UART_Receive_IT().

However it seems not to work, Could you please give me some suggestions?

 

This topic has been closed for replies.

6 replies

TDK
October 10, 2023

> I am using a circular buffer with DMA and IDLE Line detection

> And have stopped and restarted my HAL_UART_Receive_IT().

Are you using IT or DMA? Can't use both. Perhaps show your code or follow an existing example:

https://github.com/STMicroelectronics/STM32CubeL4/blob/4ca3922f320dbb2c4f3f9486f4a094f36125f31d/Projects/NUCLEO-L476RG/Examples/UART/UART_ReceptionToIdle_CircularDMA/readme.txt#L63

 

"If you feel a post has answered your question, please click ""Accept as Solution""."
Tesla DeLorean
Guru
October 10, 2023

Transmit and Receive can operate in different modes. Check what the UART Peripheral reports as a problem. Check Status and Error flagging. Then check in DMA unit.

Check it's not stuck in interrupt context. Toggle a GPIO and scope, check if that saturates. Don't put a persistent peripheral view over registers or FIFOs that might have secondary effects.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
ST Technical Moderator
October 12, 2023

Hello @anumathews7 

Are you receiving data in circular mode ? 

Could you share the minimum code to reproduce the issue?

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
Associate II
October 27, 2023

Yes, I am receiving data in circular mode

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {

if (huart->Instance == USART3)
{

//memcpy(MainBuf,RxBuf,Size);

oldPos = newPos; // Update the last position before copying new data

/* If the data in large and it is about to exceed the buffer size, we have to route it to the start of the buffer
* This is to maintain the circular buffer
* The old data in the main buffer will be overlapped
*/
if (oldPos+Size > MainBuf_SIZE) // If the current position + new data size is greater than the main buffer
{
uint16_t datatocopy = MainBuf_SIZE-oldPos; // find out how much space is left in the main buffer
memcpy ((uint8_t *)MainBuf+oldPos, RxBuf, datatocopy); // copy data in that remaining space

oldPos = 0; // point to the start of the buffer
memcpy ((uint8_t *)MainBuf, (uint8_t *)RxBuf+datatocopy, (Size-datatocopy)); // copy the remaining data
newPos = ((Size)-datatocopy); // update the position
}

/* if the current position + new data size is less than the main buffer
* we will simply copy the data into the buffer and update the position
*/
else
{
memcpy (MainBuf+oldPos, RxBuf, Size);
newPos = Size+oldPos;
}

}

print_mem_hex(RxBuf, Size);

//HAL_UARTEx_ReceiveToIdle_DMA(&huart3, RxBuf, RxBuf_SIZE);

Karl Yamashita
Principal
October 27, 2023

Use code formatting as it makes it easier to read code

Clipboard01.jpg

 

 

You say "And have stopped and restarted my HAL_UART_Receive_IT()" but I don't see it in your code you've posted. So if HAL returns HAL_BUSY when you call HAL_UARTEx_ReceiveToIdle_DMA, then the interrupts is not enabled and you'll never get an interrupt on any new data received.

What you should do is set a error flag and check the flag outside of the interrupt. If set, then try to enable the HAL_UARTEx_ReceiveToIdle_DMA again. See code below

 

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) 
{
	if (huart->Instance == USART3) {

//memcpy(MainBuf,RxBuf,Size);

		oldPos = newPos; // Update the last position before copying new data

		/* If the data in large and it is about to exceed the buffer size, we have to route it to the start of the buffer
		 * This is to maintain the circular buffer
		 * The old data in the main buffer will be overlapped
		 */
		if (oldPos + Size > MainBuf_SIZE) // If the current position + new data size is greater than the main buffer
				{
			uint16_t datatocopy = MainBuf_SIZE - oldPos; // find out how much space is left in the main buffer
			memcpy((uint8_t*) MainBuf + oldPos, RxBuf, datatocopy); // copy data in that remaining space

			oldPos = 0; // point to the start of the buffer
			memcpy((uint8_t*) MainBuf, (uint8_t*) RxBuf + datatocopy,
					(Size - datatocopy)); // copy the remaining data
			newPos = ((Size) - datatocopy); // update the position
		}

		/* if the current position + new data size is less than the main buffer
		 * we will simply copy the data into the buffer and update the position
		 */
		else {
			memcpy(MainBuf + oldPos, RxBuf, Size);
			newPos = Size + oldPos;
		}

	}

	print_mem_hex(RxBuf, Size);

 UART_EnIdleDMA(huart);

}


int errorFlag;

void UART_EnIdleDMA(ART_HandleTypeDef *huart)
{
 if(HAL_UARTEx_ReceiveToIdle_DMA(huart, RxBuf, RxBuf_SIZE) != HAL_OK)
 {
 // set error flag. Check error flag in main loop and call HAL_UARTEx_ReceiveToIdle_DMA again later.
		errorFlag = 1;
 }
}

void UART_CheckIdleDMA(void)
{
	if(errorFlag)
	{
		errorFlag = 0;
		UART_EnIdleDMA(&huart2);
	}
}


int main(void)
{
	// other HAL code

	while(1)
	{

		UART_CheckIdleDMA();

	}

}

 

Also should avoid doing memcpy and print routines inside an interrupt as it will prevent other interrupts from firing. You'll want to re-enable UART interrupts and exit right away. That way you don't miss any new packets of data. 

 

See my github code https://github.com/karlyama**bleep**a/Nucleo-L432KC_UART_DMA_HAL_status 

It shows how to deal with HAL status. It also uses a ring buffer to save the received data to. Because I use pointers, there is no need to memcpy the data to a buffer. The DMA knows which index of the buffer to save each packet of data to. 

UART_Parse function shows how to then get each packet and parse it.

 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
Bob S
Super User
October 27, 2023

You originally said that TX stops, and then also said you stopped and restarted your HAL_UART_Receive_IT().  And you show you RX code.

So which is it?  Does your TX stop?  Or does your RX stop?  Or both?

Also realize that the RxEventCallback() is called from the UART interrupt handler.  Whatever print-mem_hex() does, it probably shouldn't be called from interrupts.

And as an aside and FWIW, I typically do not use/rely on "receive to idle" to frame incoming data.  Unless you can absolutely guarantee the sender will always send "packets" with no delay between bytes (I'm not betting MY paycheck on that).  I just run my RX in continuous DMA circular mode with a buffer at least 2x the size of the largest packet.  Then check for incoming data based off a timer or polling loop.  THAT always works, though software needs to determine start/end of data packets/frames.  Similar to https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx .