2018-07-31 11:06 AM
Dear Sir/Madam:
I use three uart of stm32f4 : uart1, uart2 and uart6
I have some problems . when uart1 has overrun error,
all system get stuck there. I read some websites about this.
they mention that in the hal lib, clear ORE does not work, they said, only reading uart data register , this bit will clear. I do that, still do not work:
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
...
tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE);
tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
/* UART Over-Run interrupt occurred ----------------------------------------*/
if((tmp1 != RESET) && (tmp2 != RESET))
{
#if 1// I add this , but it does not work, system still hang/stuck when ore happens,
// any clue?
uint8_t sysRxChar; // clear the regular interrupt
sysRxChar = (uint8_t) huart->Instance->DR;
#endif
// if does not really clear big
__HAL_UART_CLEAR_OREFLAG(huart);
huart->ErrorCode |= HAL_UART_ERROR_ORE;
}
...
}
reference link is:
https://github.com/particle-iot/firmware/pull/796/commits/677b4b114b9b6503dcd10ddb83d128c9a65d6640
https://github.com/particle-iot/firmware/issues/776
thanks
roseanne
2018-08-06 12:42 PM
Dear Clive:
thanks for your quick response. based on your advice,
I will use timer1 with higher priority than uart, once system tasks level hang, in the timer1 interrupt routine, first check each uart status and then clear that uart and restart it on the task level . in this way, I could avoid system hang because uart interrupt routine hold all system.
thanks
brb once I do some tests.
roseanne
2018-08-06 01:07 PM
SysTick is probably easier because it likely already fired up and configured in a way to make HAL Ticks advance at the highest priority/preemption level. A "watchdog" here would be to load/check a count variable, and clear it, every 1ms and have a routine in the USART IRQ Handler(s) than increments the count. In case of an interrupt storm this counter would then peg full-scale in way that would be actionable within 1-2ms of onset.
2018-08-06 01:30 PM
Dear Clive:
thanks for your help.
I do not quite understand your last paragraph, would you please give a small examples . I guess that you want me to try to count times inside UART IRQ?
if so, how could I know a special UART get reentered forever?
I look back the hal uart IRQHandler as above, once an interrupt happens, only when UART_RECEIVE_IT or UART_TRANSMIT_IT are skipped without execution, the related interrupt handler will be kept reentered. In my updates, once the interrupt get called, no matter whether there is error or not error,
I let one of UART_RECEIVE_IT or UART_TRANSMIT_IT get executed and clear interrupt .
this is what I could do.
but if something happen , they are not any errors listed in this uart IRQ handler, above two functions are never called, the uart interrupt routine will be reentered forever again.
IN MY understand, once the uart IRQ handler get called, one of rx or tx interrupt bit has to be cleared. It means that one of UART_RECEIVE_IT or UART_TRANSMIT_IT
have to be called . in this way, the reenter of the uart IRQ handler could be avoid . am I correct?
thanks
roseanne
2018-08-06 01:43 PM
So, you increment an entry count in the handler, and look for stupidly high counts in the SysTick Handler... Numbers in this context would be >10000 or >100000, I'd suppose, because the system has gone off the rails, and this is all it is doing. Suggest you review the count during the integration period to see how bad it gets, but you should be able to catch within 1-2ms, so you have some chance of recovering the system before other critical tasks fail.
At 9600 baud you'd expect no more than 2-4 (IN/OUT) invocations in 1ms. (9600 baud = 1000 chars/per second, or 1 every ms)
volatile unsigned int entrycount = 0;
void USART1_IRQHandler(void)
{
entrycount++;
...
HAL_UART_IRQHandler(&hUart1);
}
void SysTick_Handler(void) // Called at 1ms (1 KHz)
{
HAL_IncTick();
if (entrycount > 10000) // Detect interrupt storm saturating processor
{
// Something gravely wrong with USART
// Clear errors, status, or reinitialize, or whatever to recover situation
}
entrycount = 0; // zero count for next 1ms integration period
}
2018-08-06 02:14 PM
Dear Clive:
I still could not get it how to do that inside UART IRQHander, since I have 3 uarts within one UART IRQhandler, every uart handler keep running with three uart interfaces, the interrupt handler kept calling , and switch between these interrupt and tasks happen a lot.
what I am doing is
in the while main loop
....
while(1)
{
start timer1<=============
switch(task)
{
case task1:
task1();
break;
case task2:
task2();
...
}
//switch
stop timer1<==================
}//while
...
//inside the timer1 handler,
// I set 2 second
// if it is over 2 second, above stop timer1 does not get execute
// the following interrupt happen
timer1_IRQHandle()
{
// check each uart status.
// if there is erro and also state is in busy
// this uart interrupt will be disable and cleanr
// and call:
UART_RECEIVE_IT // which will clear uart rv interrupt and call receive uar callback function
or
// the follow will disable interrupt and call interrupt callback
UART_Transmit_IT(Uart1Handle)
UART_EndTransmit_IT(Uart1Handle);
...
}
after above timer1 irq get executed, all stuck uart interrupt should be out and allow other task to continue running.
so whole system other tasks will continue running,maybe get a 1 or 2 second delay, but better than resetting whole system.
any comments for my solution?
also would like to understand your solution for detail.
thanks
roseanne
2018-08-06 02:23 PM
continue: except above the code added inside main loop, the following are for timer1 interrupt, my question is whether my judgment for tx and rx are correct?
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if ( htim->Instance == TIM1 )
{// this timer behavior as watchdog.
gbTimerExpire |= TIMER1_INT;
// check each uart and stop
// reset uart interrupt
//1. uart1 for sysbd
// for tx check?
if ( Uart1Handle->gState == HAL_UART_STATE_ERROR ||
Uart1Handle->gState == HAL_UART_STATE_BUSY_TX ||
Uart1Handle->gState == HAL_UART_STATE_BUSY ||
Uart1Handle->gState == HAL_UART_STATE_BUSY_TX_RX ||
Uart1Handle->gState == HAL_UART_STATE_TIMEOUT )
{
if ( Uart1Handle->ErrorCode != HAL_UART_ERROR_NONE )
{
// reset uart1
UART_Transmit_IT(Uart1Handle);
UART_EndTransmit_IT(Uart1Handle);
}
}
// for rx check?
else if ( Uart1Handle->RxState == HAL_UART_STATE_BUSY_RX ||
Uart1Handle->RxState == HAL_UART_STATE_BUSY_TX_RX )
{//rx
if ( Uart1Handle->ErrorCode != HAL_UART_ERROR_NONE )
{
// reset uart1
UART_Receive_IT(Uart1Handle);
}
}
// 2. uart2 for display
if ( Uart2Handle->gState == HAL_UART_STATE_ERROR ||
Uart2Handle->gState == HAL_UART_STATE_BUSY_TX ||
Uart2Handle->gState == HAL_UART_STATE_BUSY ||
Uart2Handle->gState == HAL_UART_STATE_BUSY_TX_RX ||
Uart2Handle->gState == HAL_UART_STATE_TIMEOUT )
{
if ( Uart2Handle->ErrorCode != HAL_UART_ERROR_NONE )
{
// reset uart2
UART_Transmit_IT(Uart2Handle);
UART_EndTransmit_IT(Uart2Handle);
}
}
else if ( Uart2Handle->RxState == HAL_UART_STATE_BUSY_RX ||
Uart2Handle->RxState == HAL_UART_STATE_BUSY_TX_RX )
{//rx
if ( Uart2Handle->ErrorCode != HAL_UART_ERROR_NONE )
{
// reset uart2
UART_Receive_IT(Uart2Handle);
}
}
// 3. uart6 for console
if ( Uart6Handle->gState == HAL_UART_STATE_ERROR ||
Uart6Handle->gState == HAL_UART_STATE_BUSY_TX ||
Uart6Handle->gState == HAL_UART_STATE_BUSY ||
Uart6Handle->gState == HAL_UART_STATE_BUSY_TX_RX ||
Uart6Handle->gState == HAL_UART_STATE_TIMEOUT )
{
if ( Uart6Handle->ErrorCode != HAL_UART_ERROR_NONE )
{
// reset uart6
UART_Transmit_IT(Uart6Handle);
UART_EndTransmit_IT(Uart6Handle);
sprintf(gbDbBuf, "uart6txerr:[0x%x]\r\n\0", Uart6Handle->ErrorCode);
dbPrintf(gbDbbuf);
}
}
else if ( Uart6Handle->RxState == HAL_UART_STATE_BUSY_RX ||
Uart6Handle->RxState == HAL_UART_STATE_BUSY_TX_RX )
{//rx
if ( Uart6Handle->ErrorCode != HAL_UART_ERROR_NONE )
{
// reset uart6
UART_Receive_IT(Uart6Handle);
}
}
}
....
2018-08-06 02:27 PM
Dear Clive:
sorry, I did not see your code until I click "more" , yes, I understand you now.
my questions are:
3. I have to keep all other tasks running
4. whether my solution have any problems , do you have any comments.
in our systems , all the three uarts are very busy all the times, I have to find stuck one and clear it right way without influencing other tasks and uarts.
thanks
roseanne
2018-08-06 02:46 PM
more : just saw stm32 hal : TIM1_BRK_TIM9_IRQn with TIM1 Break interrupt and TIM9 global interrupt
since Tim9 usage conflicts with our other usage, so I could not use TIM9,
but what does it mean TIM1 break interrupt?
thanks
roseanne
2018-08-06 03:24 PM
Dear Clive:
i think I could not use tim1
I try to use your sysstick
but I have a question
how do you reset count ?
if no interrupt renter
once the interrupt uart get executed
the counts always keep up no matter whether it is normal enter or keep stuck there
I never use this
see normal case
uart interrupt get executed, counter increased
see not normal case
the uart interrupt keep stuck inside irq also , counter also get increase
how do you dinstinqushi normal interrupt and stuck interrupt ?
there must be reset count in normal interrupt
thx
2018-08-06 05:26 PM
The count clears every milli-second.
For multiple USART create multiple instances of the counter.