1

摘要: 我已将 GPIO 配置为中断。我可以从所有寄存器中看到它似乎正在触发,但我的中断例程从未被调用。

详细信息: 我使用的是 Nucleo F446 板,文档指定 PC13 应该是按钮的输入。我想在发生这种情况时触发中断(我知道这不是处理按钮的最佳方式;我在使用更复杂的系统时遇到了问题,并将其简化为这个简化的示例)。我在裸机上执行此操作,而不使用任何现有库。

按钮 GPIO 说明

PC13进入EXTI13:

EXTI 多路复用器

我看到这是微控制器参考手册中的中断#40:

中断向量表

我正在按如下方式配置微控制器(为简单起见,此处使用伪 C):

  1. 为 GPIOC 模块 SYSCFG 启用时钟

      RCC_AHB1ENR |= GPIOC_EN
      RCC_APB2EN |= SYSCFG_EN
    
  2. 为 GPIO C13 启用外部中断(默认为输入)

外部中断使能选择

    SYSCFG_EXTICR4 |= (PCx << 4)
  1. 设置中断屏蔽、事件屏蔽和上升触发选择寄存器的引脚 13:

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

     NVIC_ISER1 |= 1 << 8
    
  3. 设置中断向量(这里是反汇编)

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

我有一个循环中的主代码,将一些寄存器值打印到串行端口,稍后我将对其进行描述。我已经实现了 exti15_10_handler 来打开一个 LED 并进入一个无限循环,所以我应该知道它什么时候被调用,因为它也会停止打印。当我按下并释放按钮时,我看到以下内容:

  1. 在 GPIOC_IDR(GPIO 输入寄存器)中,我可以看到第 13 位发生了变化,这告诉我 GPIO 模块正在工作。
  2. 在 EXTI_PR(外部中断挂起)中,我看到第 13 位的值从 0 切换到 1 并保持在那里。
  3. 在 NVIC_ISPR1(中断设置挂起)中,第 8 位(对应于中断 40)从 0 切换到 1 并停留在那里。
  4. 但是,NVIC_IABR0(中断有效位寄存器)不会改变。
  5. 没有调用中断,因为我看到 LED 没有变化并且电路板没有挂起。

我确定我忘了启用某些东西,但是在仔细阅读了参考手册和一堆代码示例之后,我只是没有看到它。我确实尝试了以下方法:

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

设置中断标志(我认为应该已经打开了)。我很好奇这对任何人来说是否熟悉。

4

1 回答 1

0

这是一个相当不令人满意的结果。在查看中断向量表的反汇编时,我注意到:

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

第二个条目应该是我的重置向量

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

尽管 _reset 是一个 thumb 函数,但它没有使用 LSB 集进行编码以表明这一点。如果我将行更改为:

   .word _reset + 1

...或将 .thumb_func 放在我的启动代码中的重置处理程序之前,它每次都能正常工作。

于 2022-01-11T02:03:45.640 回答