2

RTC alarm interrupt (IRQ number 41) is being called on my development board with STM32F411CEU MCU continuously without even initializing RTC. I have this default interrupt handler (I commented out the Default_Handler in startup_stm32F411ceux.s):

void Default_Handler(void)
{
    uint32_t irq_number = __get_IPSR() & IPSR_ISR_Msk;
    for(int i=0; i<nf::HAL_IRQ_map::n_interrupts;i++)
    {
        if(nf::HAL_IRQ_map::map[i].irq == irq_number)
        {
            nf::HAL_IRQ_map::map[i].irq_handler(nf::HAL_IRQ_map::map[i].params);
            break;
        }
    }

    HAL_NVIC_ClearPendingIRQ((IRQn_Type) irq_number);
}

On the first line I get the IRQ number and it's always 41 which means RTC alarm interrupt. On the last line I try to clear the IRQ, but the handler gets called continuously. My stack looks like this:

Default_Handler() at hal_irq_map.cpp:15 0x801d3e0   
<signal handler called>() at 0xfffffff9 
HAL_TIM_Base_Start_IT() at stm32f4xx_hal_tim.c:447 0x8016eec    
HAL_InitTick() at stm32f4xx_hal_timebase_tim.c:83 0x80131ea 
HAL_Init() at stm32f4xx_hal.c:176 0x8013448 
main() at main.c:95 0x8012696   

The interrupt gets called over and over again and the stack always looks like this (the program doesn't progress). HAL_Init() is on the first line of main(). I have Stm32CubeIDE and ST-LINK V2.

The questions:

Am I doing something wrong when trying to clear the interrupt?

Why is the RTC alarm interrupt being called without initializing?

EDIT:

I tried this:

    void Default_Handler(void)
{
    //Check if we handle the interrupt
    uint32_t irq_number = __get_IPSR() & IPSR_ISR_Msk;
    bool handled = false;
    for(int i=0; i<nf::HAL_IRQ_map::n_interrupts;i++)
    {
        if(nf::HAL_IRQ_map::map[i].irq == irq_number)
        {
            nf::HAL_IRQ_map::map[i].irq_handler(nf::HAL_IRQ_map::map[i].params);
            handled = true;
            break;
        }
    }
    if(!handled)
        HAL_NVIC_DisableIRQ((IRQn_Type) irq_number);
    HAL_NVIC_ClearPendingIRQ((IRQn_Type) irq_number);
}

Now I'm disabling the interrupt explicitly, but the same interrupt keeps still firing.

user785560
  • 111
  • 1
  • 9
  • you need to clear it at the source and the nvic most likely or just disable it in the nvic if you are not using it. – old_timer May 16 '20 at 19:35
  • 1
    how did the interrupt get enabled in the first place? – old_timer May 16 '20 at 19:35
  • I don't know. I don't enable RTC anywhere in my code. The only thing before HAL_Init() that I've changed is the link script: I wanted to leave a 16kB section for configuration so ISR vector sector starts at 0x08000000 and TEXT at 0x08008000 so I can write configuration at 0x08004000. But that shouldn't have any effect? Maybe my board is faulty... – user785560 May 17 '20 at 04:53
  • And did you change the Vector Table SCB->VTOR – theSealion May 20 '20 at 04:44
  • No, I didn't. I don't think I should? – user785560 May 21 '20 at 17:28

1 Answers1

1

The problem is "half" solved:

__get_IPSR() & IPSR_ISR_Msk doesn't seem to return the correct IRQ number. I'm now getting the IRQ number through HAL_NVIC_GetActive. I'm still new to ARM programming and didn't read the documentation well enough. "Active" IRQ means that it's being handled i.e. its' handler is currently being executed. "Pending" IRQ means that its' handler is to be called as soons as possible. So when you are in the default handler and you want to know which interrupt caused this call, you look for the "active" IRQ.

However, I still don't know why RTC alarm interrupt is pending and why it can't be disabled or cleared. I don't think it's ever even enabled.

Now my Default_Handler looks like this:

void Default_Handler(void)
{
    uint32_t irq_number;
    for(int i=0; i<50; i++)  // loop is for debugging only - comment out when not used
    {
        if(HAL_NVIC_GetActive((IRQn_Type) i))
        {
            irq_number = i;
            break;
        }
    }
    bool handled = false;
    for(int i=0; i<nf::HAL_IRQ_map::n_interrupts;i++)
    {
        if(HAL_NVIC_GetActive(nf::HAL_IRQ_map::map[i].irq))
        {
            nf::HAL_IRQ_map::map[i].irq_handler(nf::HAL_IRQ_map::map[i].params);
            handled = true;
            HAL_NVIC_ClearPendingIRQ(nf::HAL_IRQ_map::map[i].irq);
            break;
        }
    }
    if(!handled)
        for(;;); //sit here forever
}

When I looped through the IRQ numbers I found out that the actual active IRQ number was TIM1_UP_TIM10_IRQn. But why is Default_Handler being called instead of (the correct handler) TIM1_UP_TIM10_IRQHandler?

I thought maybe it's because I have defined Default_Handler myself. There's two lines in startup_stm32f411ceux.s:

.weak      TIM1_UP_TIM10_IRQHandler            
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler

TIM1_UP_TIM10_IRQHandler is defined .weak which means that if you define the handler yourself, it's strong definition and will be used instead. The meaning of the second line is a bit fuzzy to me, but I think it means that Default_Handler will be used instead as a handler if TIM1_UP_TIM10_IRQHandler is not defined. In my code there are strong definitions for both TIM1_UP_TIM10_IRQHandler and Default_Handler. For a reason that is unclear to me, the linker chooses Default_Handler as the handler for timer 1 update interrupt.

Trying to define my own Default_Handler weak with either pragma weak or __attribute__((weak)) didn't help. So I simply commented out .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler in startup_stm32f411ceux.s and now TIM1_UP_TIM10_IRQHandler was called correctly.

user785560
  • 111
  • 1
  • 9