cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F427 Missed Interrupt

kevinhuang
Associate II
Posted on September 25, 2014 at 02:35

Greetings,

I'm using an STM32F427VI MCU to generate a 1 Hz pulse (50% duty cycle) with its RTC controller. For the most part, it seems like it works just fine, however during testing, the code will occasionally fail to toggle the GPIO pin. Here is the code for configuring the RTC:

void
rtc_config(
void
)
{
NVIC_InitTypeDef nvic;
RTC_InitTypeDef rtc;
EXTI_InitTypeDef exti;
/* Enable PWR Domain */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE);
/* Explicitly reset the domain to reset the RTC registers */
RCC_BackupResetCmd(ENABLE);
RCC_BackupResetCmd(DISABLE);
/* Using custom board with 2 MHz oscillator */
RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div30);
/* Enable RTC Clock */
RCC_RTCCLKCmd(ENABLE);
/* Wait for RTC APB registers synchronisation */
RTC_WaitForSynchro();
/* 
* Assuming 2 MHz HSE with prescaler dividing at 30 
*
* RTC_CLK = 2 / 30 = 640 KHz
*
* 640 KHz / ((127 + 1) * (2499 + 1)) 
*/
rtc.RTC_HourFormat = RTC_HourFormat_24; 
rtc.RTC_AsynchPrediv = 127;
rtc.RTC_SynchPrediv = 2499;
RTC_Init(&rtc);
/* RTC must go through EXTI line */
EXTI_ClearITPendingBit(EXTI_Line22);
exti.EXTI_Line = EXTI_Line22;
exti.EXTI_Mode = EXTI_Mode_Interrupt;
exti.EXTI_Trigger = EXTI_Trigger_Rising;
exti.EXTI_LineCmd = ENABLE;
EXTI_Init(&exti);
/* Configure NVIC */
nvic.NVIC_IRQChannel = RTC_WKUP_IRQn;
nvic.NVIC_IRQChannelPreemptionPriority = 0;
nvic.NVIC_IRQChannelSubPriority = 0;
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);
/* Configure source */
RTC_WakeUpClockConfig(RTC_WakeUpClock_CK_SPRE_16bits);
RTC_SetWakeUpCounter(0x0);
RTC_ITConfig(RTC_IT_WUT, ENABLE);
RTC_WakeUpCmd(ENABLE);
}
void
RTC_WKUP_IRQHandler(
void
)
{
if
(RTC->ISR & 0x400)
{
/* Clear WUTF flag */
RTC->ISR &= ~(0x400);
EXTI->PR = EXTI_Line22;
GPIOC->ODR ^= GPIO_Pin_13; 
// Toggle pin here
}
}

The code works 99% of the time. Using an oscilloscope, I can see a 1 Hz 50% duty cycle pulse coming out of pin PC However, the interrupt will randomly fail to be called (at least it seems), so the pin fails to toggle. Reproducing this error is difficult, because I can't seem to figure out a way to trigger it, and it happens at random intervals (sometimes 2 min, sometimes 40 min). I've checked all the other possible interrupt sources in my code to make sure the RTC_WKUP interrupt is given the absolute highest priority, but that doesn't seem to fix the issue. I've also browsed the STM32F427 errata sheets, but nothing stood out to me as possibly causing this. I don't know how to debug this, has anyone seen something similar or know what might be causing it? #interrupt #rtc #stm32f4
7 REPLIES 7
Posted on September 25, 2014 at 03:29

Ok, so it doesn't really ''miss'' them, rather it just stops calling altogether?

So when it stops toggling the pin, what exactly is the processor doing? If you stop execution in the debugger, where is it? What's in the RTC and NVIC registers once it stops? If you breakpoint the interrupt then do you observe it being called, or not?

Make this into a concise stand-alone example, does it still stop randomly? Consider if you have other code causing it to fail. Consider if you have a stack issue.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
kevinhuang
Associate II
Posted on September 25, 2014 at 22:30

The processor continues on like normal, as if the interrupt had been called. I've placed breakpoints inside the interrupt handler and confirmed that it's being called. Given the random nature of the missed interrupt, it's difficult to get a breakpoint when the GPIO fails to toggle. I did hook up an oscilloscope and managed to capture the output on there though: http://i.imgur.com/1PKOsyE.jpg. The PPS looks normal until the these random moments when the pin fails to toggle. 

I do have a large number of peripherals firing their interrupts repeatedly, but I checked their preemptive/sub- priority levels and made sure to give the rtc_wkup interrupt handler the highest priority level, so I don't think anything else is getting in the way?

Posted on September 26, 2014 at 08:33

> 

RTC->ISR &= ~(0x400);

1. RTC_ISR bits are of rc_w0 type, i.e. you ought to

RTC->ISR = ~(0x400)

2. Try to read back and confirm the bit has been cleared before you exit the ISR, i.e.

while

(RTC->ISR & 0x400)
; JW
Posted on September 26, 2014 at 14:00

The library does some more gyrations,

void RTC_WKUP_IRQHandler(void)
{
if (RTC_GetITStatus(RTC_IT_WUT) != RESET)
{
RTC_ClearITPendingBit(RTC_IT_WUT);
EXTI_ClearITPendingBit(EXTI_Line22);
GPIOC->ODR ^= GPIO_Pin_13; // Toggle pin here
}
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on September 26, 2014 at 14:49

And how is it exactly different from our OP's code, and how does it help to solve his problem?

[EDIT] Oh I see - it is aimed at preserving the INIT bit. That would be a good thing, but, as I said above, the rest of the bits in this registers are NOT to be cleared by RMW, which may create a hazard, should multiple interrupt sources be enabled. In other words, this library function is IMO buggy. Yet still, *if* my guess is right and OP's problem stems from the RTC hardware clearing the bit slower than the processor succeeds in re-firing the interrupt (resulting in that short spiky pulse which can be seen on the attached scope trace), using it can help only coincidentally (e.g. if the ''library'' function is compiled into a function call which delays the ISR exit from the RTC_ISR register write).

JW

Posted on September 26, 2014 at 16:44

The guys who coded the Standard Peripheral Library have significantly more insight into the silicon implementation than I do, but their implementation is more nuanced than the OP, and the RTC operates in a much slower clock domain than other parts of the design. Calling subroutines, and sequencing the way they do may account for race/pipeline hazards just banging the registers does not achieve.

Testing it with code as used by ST might permit us to see if it's really an interrupt preemption problem or something else. I'm tending to the ''something else'' because I'm hard pressed to see how a system could jam up for 500ms and someone not realize that via other means.

Also there are better ways to generate a 1 Hz 50/50 waveform than this, but I presume this is to illustrate the IRQ handler is being called, and presumably doing something more useful in the real application. So again I'll suggest breaking this into a stand-alone implementation and determining if that also fails, or not.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on September 29, 2014 at 10:18

> Testing it with code as used by ST might permit us to see if it's really an interrupt preemption problem or something else.

As I've said above, the ''library'' code might mask the problem simply by generating longer/slower code.

It's not *preemption* problem, it's the problem of interrupt sources being physically cleared slower than the software effectively exits the ISR.

JW