cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 LPUART only works with breakpoint.

SCabr.1
Associate II

Hi, I need your help, please:

I'm using a STM32 and the STM32CubeIDE and I want to communicate the MCU and a FPS module R502 through LPUART (Low Power UART). When I send the correct packages, the FPS answers correctly (I check that reading via serie with Saleae Logic) and follow my instructions (for example, led on).

The problem seems to be handling the interruption (is that different when the UART is low power???). It's weird, because when I write at the beginning of main() the function HAL_UART_Receive_IT(lpuart), the code doesn`t execute anymore, it keeps in the HAL_UART_IRQHandler() forever, where I can see that there aren`t errors but huart->RxISR = NULL.

What seems to make no sense is that when I set a breakpoint in the instruction  SET_BIT(huart->Instance->CR3, USART_CR3_EIE) inside of the HUART_Receive_IT(lpuart) and I do a "Step Into" and then "Resume", the code works perfectly, which I use all the FPS`s funcionalities in (removing the breakpoint previously).

Has someone any idea about why that's happening or has had a similar bug? It would be so good, because I've spent a week in that.

Thank you.

11 REPLIES 11
Ozone
Lead II

I don't know LPUART specifics, sine I don't use any of this MCUs.

But you are aware that debuggers are invasive, aren't you ?

Reading a peripheral interrupt register in the debugger will clear associated bits/flags as well.

You can try to instrument your code, to check it without a debugger.

Like, setting GPIOs when the code enters/exits specific code sections or functions.

I am still dealing regularly with old projects at my day job that enjoy very limited debug support.

Paul1
Lead

It could be a stack issue...

Are you using or passing data on the stack for these operations, possibly passing a pointer to a variable that is on stack, and variable vanishes when subroutine or interrupt exits, leaving pointer pointing to invalid position in stack?

Quick test: Change all variables in trouble code to static (add word static before variables declared in the functions, or move variables outside the functions). Possibly the issue is actually with other code, and the lost pointer is just now hitting your newer code.

Also enabling Breakpoints and such adds code that can affect the stack and where things are compiled in memory.

Basic rules:

  • Hardware issue: Check the cables
  • Software issue: check the stack (Especially when the issue is very strange and makes no sense, like yours where it varies with position in code)

Similar can happen with array overruns (storing more data in array than allocated array size). Maybe your receive routines are writing to arrays/buffers/ringbuffers, and their pointers/indexes are not calculated quite right?

Paul

Which STM32? There's hundreds at this point.

The debugger might change low-power behaviour. Does the LPUART need an EXTI interrupt in these mode?

Watch for debugger changing UART states/status.

Check code flow and exit conditions, that you are not handling states correctly, or ignoring error states that need clearing/management.

Perhaps show handler or some minimal code.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
SCabr.1
Associate II

Thank you for your answers!

I've tried some options you adviced me, but it doesn't work.

In debug mode, I've seen that after "HAL_UART_Receive(lpuart)" I have an error code in my UART_HandleTypeDef. The error is 8, which means I have an overrrun error, but I don't know how to solve that.

Does someone know how to solve with this new information?

Thank you

SCabr.1
Associate II

I solved the bug adding a false delay (HAL_Delay() didn't work) after SET_BIT. It seems there it needs a wait. Here the code:

 /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */

 SET_BIT(huart->Instance->CR3, USART_CR3_EIE);

 a = 0;

 while(a<1000){

 a++;

 }

 /* Set the Rx ISR function pointer according to the data word length */

 if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))

 {

  huart->RxISR = UART_RxISR_16BIT;

 }

 else

 {

  huart->RxISR = UART_RxISR_8BIT;

 }

If someone has a smarter solution, it would be interesting.

Thank you everyone.

Paul1
Lead

Overrun error - means you are receiving data faster than your code is processing it.

I take it you are not using interrupts for UART? This means the receive data isn't read until your main routine has time.

If you receive a second character before main routine has read first then Overrun.

Solution: Use Receive Interrupts and/or Receive DMA (Transmit doesn't need to be interrupt or DMA unless you are aiming for very high throughput/speed).

I tend to use Rx Interrupt with non-interrupt transmit, but what you need depends on what you are making.

There are examples of Interrupt and DMA for UART/USART in the ST tutorials and examples, here are some I've used (STM32 Education MOOC might be best):

With Receive interrupt you add a tiny bit of code that will upon each interrupt will read the receive register into a buffer, where your non-interrupt code can later process it. The buffer should be large enough to hold all receive data that could be received before your non-interrupt code can handle it.

The code to do this may depend on the STM32 you selected and the UART channel you connected. Here is a snippet from some STM32L496 code (without the recommended ring buffers).

#define MDiag_Transmit_Immediate(puData) HAL_UART_Transmit(&huart2,puData,sizeof(puData)-1,HAL_MAX_DELAY) //Transmit sizeof string without timeout
 
typedef void (*PF_vCallbackPointerV)(void);//Generic Void Function Pointer for Callbacks
typedef void (*PF_vCallbackUartH)(struct __UART_HandleTypeDef *huart); /*!< Function pointer with Passed Uart Handle */
extern UART_HandleTypeDef huart2;
 
typedef struct {
	uint32_t _uCnt_RxErr;
	uint32_t _uCnt_RxData;
	uint32_t _uCnt_RxUnknown;
	uint32_t _uCnt_TxErr;
	uint32_t _uCnt_TxData;
	uint32_t _uCnt_TxUnknown;
	uint8_t	 _uRxData;
	bool	 _bRxData;
} SUART_Diag;
SUART_Diag sUart_Diag;
 
//Define UART2 Handler Routines:
void vCallback_Uart2_Rx(UART_HandleTypeDef *pHUart) //USART_ISR_RXNE(RxData) & USART_CR1_RXNEIE(RxIrqEnabled)
{
	if(pHUart == &huart2)
	{
		sUart_Diag._uCnt_RxData++;
		sUart_Diag._uRxData = (uint8_t)READ_REG(pHUart->Instance->RDR); sUart_Diag._bRxData = true;//Read RxData (Clears Interrupt)
		// ToDo: Add data to RingRx
	}
	else
	{
		sUart_Diag._uCnt_RxUnknown++;
	}
}
//void vCallback_Uart2_Tx(UART_HandleTypeDef *pHUart)
//{
//	if(pHUart == &huart2){	sUart_Diag._uCnt_TxData++;	/*Handle Tx/RingTx*/ 	}
//	else		 		{	sUart_Diag._uCnt_TxUnknown++;						}
//}
void vUSART_InitIrq(void)//Use Local Function Pointers
{	//&huart2
	//see: void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
	printf("UART: Enable Rx Irq\n");
	huart2.RxISR = vCallback_Uart2_Rx; //Check: UART_IT_RXNE=Receive Data Register Not Empty Flag
 	__HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE);
 
	//printf("UART: Enable Tx Irq\n");
 	//pHUart->TxISR = vCallback_Uart2_Tx; //Check: TBD
 	//__HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE);
 
	printf("UART: Init Done\n");
}
 
//void vCallback_USART2(UART_HandleTypeDef *huart);
 
bool bRxProcess(void)
{
	uint8_t	uRxData;
	if(sUart_Diag._bRxData)
	{
		LD2_On();
		__disable_irq(); //Don't allow interrupts during autonomous action:
		uRxData	= sUart_Diag._uRxData;
		sUart_Diag._bRxData = false;
		__enable_irq();
		printf("Rx[%c]=0x%02x\n", uRxData, uRxData);
 
		switch(uRxData){
			case 'r': case 'R': vResetNow(); break;//Reset
			default: break;//No Action
		}
 
		return(true);
	}
	return(false);
}

Without knowing more that's all I can offer, and really I don't have much time as busy at work.

  • STM32 you are using
  • UART connected/circuit
  • Project setup using STM32CubeMX and STM32CubeIDE? Versions?
  • Target baudrate? Fastest throughput required?
  • Diagnostics method? (Variables read at breakpoints? UART for Diagnostics using printf? Other?)

Good luck. Have a good read of the MOOCs...

Paul

Paul

Paul1
Lead
  • We were posting at same time, not for your second post...

Are you using STM32CubeMX to setup the chip and generate initial code?

I wouldn't expect need to set the Word length and the like if you use MX.

At least use MX to generate a sample project, then look at code it generated to see if you missed anything.

There are soooooo many registers I won't try to guess what you have set.

Paul

Paul1
Lead

The delay isn't a valid solution. It will limit your baudrate and cause more overruns .... Unless your are only processing hand typing as UART Rx.

Paul

I'm using STM32L072CZT6 and yes, I generated the code with STM32CubeMX. I've used this MCU before and UART like this time: generating with STM32CubeMX (last version, I guess) and writing code with STM32CubeIDE; and it's the first problem I've had.