I am using the UART4 module of an STM32F105. I'm using the RXNE ("RX Buffer Not Empty") interrupt to grab data as it comes in. It's working as expected.
When the RXNE interrupt is enabled it also enables the Overrun interrupt (ORE). This also appears to work as expected.
The ORE status flag is mapped as USART_FLAG_ORE
. The corresponding interrupt flag is USART_IT_ORE
. If the RXNE interrupt is enabled, when the Flag bit gets set it should cause the IT bit to also get set. Copied from the User Manual:
I'm handling the interrupt like so:
void usartISR(void)
{
// Did we receive data?
if(USART_GetITStatus(UART4, USART_IT_RXNE) == SET)
{
// Add it to the active buffer
}
// Did the receiver overrun?
else if(USART_GetITStatus(UART4, USART_IT_ORE) == SET)
{
// Clean up and clear the Overrun condition
}
// No other triggers have been enabled
else
{
ErrorHandler(ERR_BAD_INTERRUPT);
}
}
The problem happens if the ORE flag is already set when I enable the interrupt:
{
// The USART_FLAG_ORE bit is already set
// The following command causes an immediate vector to the ISR:
USART_IT_Config(UART4, USART_IT_RXNE, ENABLE);
}
The code vectors to the ISR, but the USART_IT_ORE
flag doesn't seem to get set. The ISR merrily skips to the end and calls the error handler. If I look into the USART_CR registers, none of the other interrupt events are enabled. If I bypass the error handler, the code repeatedly vectors to the ISR even though no IT flags are set.
Why is the ISR getting triggered without the USART_IT_ORE
flag getting set? Am I missing something obvious?
Best Answer
Having gone through the definitions in
stm32f10x_usart.h
andGet_ITStatus()
in the source, its evident that there are no actual UART 'interrupt flags'. There are only status flags in the status register. As you know, when an event occurs, the corresponding flag bit is set, whether interrupts are enabled or not. If the associated interrupt is enabled, then the MCU jumps to the relevant ISR, where the event may be handled.The image above shows that if the RXNE interrupt is enabled and the ORE flag is set, an interrupt is triggered, as it should be. In your code, you attempted to get the status of the 'interrupt flag' with
Get_ITStatus()
. However, the only thingGet_ITStatus()
does is: check if the associated status flag is SET && if the associated interrupt is enabled.Now, we know the first condition is true, since you SET the flag yourself and you have verified that it is indeed set. The second condition should be true as well--if the interrupt being checked were RXNEIE (since you enabled it). But the actual interrupt enable bit being checked, when
USART_IT_ORE
is passed toGet_ITStatus()
, isEIE
(Error Interrupt Enable). So since you didnt enable this interrupt,Get_ITStatus()
will always return RESET (0) for an Overrun error.Get_ITStatus()
is not completely incorrect though. The diagram above shows that when ORE, EIE and DMAR are set, an interrupt will be generated. According to the manual at the link you provided:This snippet provides additional confirmation. So it seems that the library authors only coded for this second possibility (though not correctly since DMAR isnt checked). Your work-around checks the status flag directly which is okay as long as you dont set EIE with RXNEIE, since you wouldnt know which source generated the Overrun Error.