2024-07-21 02:38 PM
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.
2024-07-21 03:48 PM
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.
2024-07-21 05:45 PM
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.
2024-07-22 12:47 AM
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