Skip to main content
Visitor II
July 21, 2024
Question

STM32F103 strange behavior with RTC and NVIC pending bits

  • July 21, 2024
  • 2 replies
  • 961 views

Hello, everyone. I'm trying to use an STM32F103C6 to toggle some pins once per second. To this end, I have set up the RTC "seconds" event to fire on the appropriate interval.

When busy waiting until the `SECF` bit of `RTC_CRL` is set, it works just fine. But if I busy wait for the appropriate IRQ pending bit instead, it sometimes doesn't work. The specific situation when it works or doesn't is bewildering.

The code looks roughly like this:

while (true) {
while (!nvic.get_pending(Irq::rtc)) {}
nvic.clear_pending(Irq::rtc);
rtc.clear_secf();
// do other stuff
}

This works just fine if I compile with `-O1` or `-Os`, or if I leave the `RCC_CFGR` APB1 prescaler `PPRE1` value at its default. It does not work if I compile with `-O2` or higher, and set the APB1 prescaler `PPRE1` to `0b100` or greater.

The behavior I observe is as if the pending bit never gets set. But when debugging, I can print the value of the appropriate memory location and it is indeed set, then I can single-step past the loop and.

Another interesting fact is if I move the loop into a separate function and give it the attribute `[[gnu::noinline]]`, then it seems to work even with modified PPRE1 and compiled with `-O2` and above. This makes no sense to me at all.

I'm using arm-non-eabi-g++ version 13.2.1 to compile, and `st-flash` with `--format ihex`.

 

My eventual goal is to use `wfe` to sleep until RTC fires, and I first encountered this problem using `wfe` and setting `SEVEONPEND`. I also plan to run the MCU at 72Mhz, so setting the APB1 prescaler is important.

    This topic has been closed for replies.

    2 replies

    Super User
    July 21, 2024

    Sounds like a missing volatile qualifier on the register. How is the register read within nvic.get_pending defined?

    It's a little odd to block and wait for an IRQ rather than letting the IRQ happen and handling it within the IRQ handler.

    Zcool31Author
    Visitor II
    July 22, 2024

    Thanks for the suggestion.


    @TDK wrote:

    Sounds like a missing volatile qualifier on the register. How is the register read within nvic.get_pending defined?

     


    I can confirm they are defined as `uint8_t volatile array[8];` The code is:

     

    while (!(nvic.ispr[0] & 8u)) {}

     

    Interestingly, the codegen for this loop is the same across -O1, -O2, and -Os.

    Super User
    July 22, 2024

    Blue pill? Then it's highly unlikely it's an ST part.

    Write a minimal but complete compilable example exhibiting the problem and post.

    JW