cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103 strange behavior with RTC and NVIC pending bits

Zcool31
Associate

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.

3 REPLIES 3
TDK
Guru

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.

If you feel a post has answered your question, please click "Accept as Solution".

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.

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