So I wrote a program for the STM32F103C8T6
microcontroller in C, using the RTC (Real Time Clock) and a display module.
The RTC and the display both work fine, but when I try to update the display from inside the RTC interrupt handler, it doesn't work.
When I write something to the display from within the main()
, it works just fine.
The interrupt handler works as well, so I figured that the problem lied within the function that writes to the display.
This function uses small delays to bit-bang the communication with the display controller.
I previously used the SysTick
to generate the delays like this:
void delay(uint32_t n){
uint32_t start = systick_count;
while (systick_count - start < n);
return;
}
But somehow, inside the interrupt handler of the RTC it doesn't work. So I replaced my delay function with this one, not using the SysTick:
for (; i>0; i--) {
for (int j = 0; j < 72; ++j) {
__asm__ __volatile__("nop\n\t":::"memory");
}
}
and now everything works just fine.
I'm trying to understand, why the SysTick
apparently doesn't work inside the RTC interrupt handler.
I figured that maybe it's caused by the Interrupt priorities, but according to the datasheet, by default the SysTick Interrupt
's priority is higher than the RTC interrupts priority.
Maybe someone can explain, why this happens?
EDIT1: Ok, so I’ve read a bit more about the interrupt priorities, and it seems that i need to configure the NVIC_IRQChannelPreemptionPriority correctly. I’ll try this as soon as I can...
With regard to the delay inside the interrupt, I know that's not the right way to do It, but I still wanted to understand the program's behaviour
EDIT2: I just tried changing the interrupt priorities in the following way:
// set RTC interrupt priority to 15 (lowest)
NVIC_SetPriority(RTC_IRQn, 15);
// set interrupt priority of SysTick to 0 (highest)
NVIC_SetPriority(SysTick_IRQn, 0);
and now the SysTick delay works within the RTC interrupt handler.
Your way of implementing delay using SysTick is the same as HAL_Delay
in HAL library coming from ST. The way it works is that SysTick continually increments (typically in 1ms intervals) a variable - systick_count
in your case - that is compared against a local variable inside delay function - start
in your case.
Two things to note here:
systick_count
needs to be made volatile to force re-reading of its value before each comparison. It's modified by interrupt and not inside that function. Your compiler may choose to optimize this portion of the code.
The SysTick interrupt needs to be "running" when the delay function is called. If it's not e.g. because you're in a higher priority (numerically lower) interrupt, then you're in a deadlock and the delay function will never finish because the counter will never be incremented by SysTick that never happens. Regarding this point - don't assume things and rely just on the datasheet. Go ahead and actually verify that it's running while in delay. Either check NVIC register values at the moment of calling the delay function or simply set a breakpoint in SysTick while you're in the RTC interrupt - it should hit that breakpoint while you're in the delay function. If it doesn't- you probably need to adjust interrupt priorities.
Regarding the whole idea of putting a delay in your interrupts - it is generally considered bad practice. Interrupts are supposed to be used to do very small portions of work very quickly such as setting a flag that something needs to be done in the main program code or putting received byte in a queue for later processing. While this may not seem obvious in a simple program where you only have one interrupt (two if you count Systick), it'll very quickly become problematic once you add more interrupts and will run into issues such as losing information because your interrupts block each other and they don't get called quickly enough.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With