3
\$\begingroup\$

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:

ore

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?

\$\endgroup\$
5
  • \$\begingroup\$ Is it possible that you are reading the data register (maybe in the first IF block) before the ISR gets to the OVE handler? Since this could clear the flag... \$\endgroup\$ Mar 25, 2016 at 23:47
  • \$\begingroup\$ @TisteAndii Thanks for the thought! That flag is supposed to be cleared by a read to SR followed by a read to DR. My code doesn't touch the DR until after it enters the IF blocks. As a test, I looked at the SR at the very top of my ISR. The USART_FLAG_ORE was set, implying that USART_IT_ORE should have been set, but the USART_GetITStatus() function still returned a negative... \$\endgroup\$
    – bitsmack
    Mar 26, 2016 at 0:07
  • \$\begingroup\$ @TisteAndii And, as another test, I read the SR multiple times. The USART_FLAG_ORE bit wasn't cleared by any of the reads. \$\endgroup\$
    – bitsmack
    Mar 26, 2016 at 0:09
  • \$\begingroup\$ What version of STDPeriph are you using? Maybe you could try USART_IT_ORE_RX instead of USART_IT_ORE in GetITStatus(). The latter seems to be a legacy definition in one library i found \$\endgroup\$ Mar 26, 2016 at 0:25
  • \$\begingroup\$ @TisteAndii USART_IT_ORE is the one used in my version of the SPL (v3.5.0). I did a search through the library for USART_IT_ORE_RX and came up with zero hits. I have found a workaround and posted it an an answer. Would you look at it and see if it tells you anything? Thanks again. \$\endgroup\$
    – bitsmack
    Mar 26, 2016 at 0:43

2 Answers 2

6
\$\begingroup\$

Having gone through the definitions in stm32f10x_usart.h and Get_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.

UART interrupts

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 thing Get_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 to Get_ITStatus(), is EIE (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:

EIE defs

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.

\$\endgroup\$
0
\$\begingroup\$

I've found a workaround. This doesn't directly answer the question, but hopefully it will help until someone gives a better answer :)

It turns out that even though the USART_IT_ORE doesn't get set, the USART_FLAG_ORE bit does. If I modify the ISR to check for the Flag bit (using USART_GetFlagStatus(USART_FLAG_ORE)) instead of the IT bit (USART_GetITStatus(USART_IT_ORE)) then the ISR behaves just fine.

Interestingly, both USART_FLAG_ORE and USART_IT_ORE are cleared with the same sequence of events. They get cleared together. So I didn't have to change any more of my code...

\$\endgroup\$
2
  • \$\begingroup\$ I've gone through Get_ITStatus() and I think I know why it happens that way. You'll have to verify though. Typing an answer... \$\endgroup\$ Mar 26, 2016 at 1:30
  • \$\begingroup\$ I'm not sure but you may be accidentally clearing ORE with this method. ALWAYS do the flag clear procedure right before enabling any specific interrupt. You never know what state it might be in for whatever reason, and end up with a spurious interrupt as soon as that enable is set! \$\endgroup\$
    – Daniel
    Mar 26, 2016 at 8:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.