JeffB
JeffB

Reputation: 406

Interrupt is pending, but my interrupt routine is not called

Summary: I've configured a GPIO as an interrupt. I can see from all of the registers that it appears to be triggering, but my interrupt routine is never called.

Details: I'm using a Nucleo F446 board, and the documentation specifies that PC13 should be the input for the push button. I'd like to trigger an interrupt when this happens (I know that this isn't the best way to handle a button; I was having trouble with a more complex system and reduced it to this simplified example). I'm doing this on bare metal and not using any existing libraries.

push button GPIO description

PC13 comes into EXTI13:

EXTI muxes

I see that this is interrupt #40 from the microcontroller reference manual:

interrupt vector table

I'm configuring the microcontroller as follows (using pseudo-c here for simplicity):

  1. Enable clocks for GPIOC block, SYSCFG

      RCC_AHB1ENR |= GPIOC_EN
      RCC_APB2EN |= SYSCFG_EN
    
  2. Enable external interrupts for GPIO C13 (it is by default an input)

external interrupt enable select

    SYSCFG_EXTICR4 |= (PCx << 4)
  1. Set pin 13 of the interrupt mask, event mask, and rising trigger selection registers:

     EXTI_IMR |= 1 << 13
     EXTI_EMR |= 1 << 13
     EXTI_RTSR |= 1 << 13
    
  2. Enable IRQ 40

     NVIC_ISER1 |= 1 << 8
    
  3. Set up interrupt vector (here is a disassembly)

     08000000 <_reset-0x124>:
     ...
     80000e0:       08000621        .word   0x08000621
    
    
     08000620 <exti15_10_handler>:
      8000620:       4906            ldr     r1, [pc, #24]   ; (800063c <exti15_10_handler+0x1c>)
    

I have the main code in a loop printing a number of register values, which I will describe in a moment, to the serial port. I've implemented exti15_10_handler to turn on an LED and go into an infinite loop, so I should know when it is called, because it will also stop the printing. When I press and release the button, I see the following:

  1. In GPIOC_IDR (the GPIO input register), I can see bit 13 change, which tells me the GPIO block is working.
  2. In EXTI_PR (external interrupt pending), I see the value of bit 13 switch from 0 to 1 and stays there.
  3. In NVIC_ISPR1 (interrupt set pending), bit 8 (corresponding to interrupt 40) switches from 0 to 1 and stays there.
  4. However, NVIC_IABR0 (interrupt active bit register) does not change.
  5. Interrupt is not called, as I see no change in the LED and the board does not hang.

I'm sure I'm forgetting to enable something, but after dredging through the reference manuals and a bunch of code examples, I'm just not seeing it. I did try the following:

asm volatile ("cpsie i" : : : "memory");

To set the interrupt flag (which I think should have been on already). I'm curious if this looks familiar to anyone.

Upvotes: 1

Views: 2056

Answers (1)

JeffB
JeffB

Reputation: 406

This is a pretty unsatisfying result. While looking at the disassembly of the interrupt vector table, I noticed:

 8000000:       20020000        .word   0x20020000
 8000004:       08000124        .word   0x08000124
 8000008:       08000595        .word   0x08000595
 800000c:       08000595        .word   0x08000595

The second entry is supposed to be my reset vector

            .section .interrupt_vector
            .word _estack    // Stack pointer
            .word _reset

Although _reset is a thumb function, it is not encoded with the LSB set to indicate that. If I change the line to:

   .word _reset + 1

...or put .thumb_func immediate before my reset handler in my startup code, it works correctly every time.

Upvotes: 0

Related Questions