You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让RP2040的中断正常工作?ARM汇编中断循环问题求助

RP2040汇编中断循环退出问题解决

问题描述

作为硬件开发新手,我尝试用ARM汇编实现RP2040的GPIO中断功能,但触发中断后会持续进入中断循环无法退出,推测是未正确清除中断标志,排查一周仍无进展,相关代码如下:

#include "hardware/regs/addressmap.h"
#include "hardware/regs/io_bank0.h"
#include "hardware/regs/timer.h"
#include "hardware/regs/m0plus.h"
  
  
  .syntax unified
  .cpu cortex-m0plus
  .thumb
  .global main_asm
  .align 4


  .equ GPIO_BTN_MSK, 0x00040000
  .equ GPIO_BTN, 20

  .equ GPIO_LED, 25

  .equ GPIO_DIR_IN, 0
  .equ GPIO_DIR_OUT, 1

  .equ GPIO_ISR_OFFSET, 0x74



main_asm:
  bl install_btns
  bl install_gpio_isr
  bl install_leds

loop:
  bl btn_released
  b loop


install_btns:
  push {lr}

  movs r0, #GPIO_BTN
  bl asm_gpio_set_irq
  movs r0, #GPIO_BTN
  movs r1, #GPIO_DIR_IN
  bl asm_gpio_set_dir

  pop {pc}


install_leds:
  push {lr}

  movs r0, GPIO_LED 
  bl asm_gpio_init
  movs r0, #GPIO_LED
  movs r1, #GPIO_DIR_OUT
  bl asm_gpio_set_dir

  pop {pc}



install_gpio_isr:

  ldr r2, =(PPB_BASE + M0PLUS_VTOR_OFFSET)
  ldr r1, [r2]
  ldr r2, =GPIO_ISR_OFFSET
  add r2, r1
  ldr r0, =gpio_isr

  str r0, [r2]

  ldr r0, =0x1
  lsls r0, #13
  ldr r1, =(PPB_BASE + M0PLUS_NVIC_ICPR_OFFSET)
  str r0, [r1]

  ldr r1, =(PPB_BASE + M0PLUS_NVIC_ISER_OFFSET)
  str r0, [r1]

  bx lr



.thumb_func
gpio_isr:
  push {lr}

  ldr r2, =(IO_BANK0_BASE + IO_BANK0_PROC0_INTS2_OFFSET)
  ldr r1, [r2]
  ldr r3, =GPIO_BTN_MSK
  ands r1, r3
  cmp r1, r3
  bne not_btn
btn:
  bl btn_pushed 
  b end_interrupt
not_btn:
  Bl btn_released

end_interrupt:
  
  ldr r0, =0x1
  lsls r0, #20  
  ldr r1, =(IO_BANK0_BASE + IO_BANK0_INTR2_OFFSET)
  str r0, [r1] 

  pop {pc}

.align 4

.data

问题分析与修复

核心问题是中断标志位的掩码定义和清除操作完全错误,另外需辅助检查中断触发配置:

1. 修正中断状态掩码定义

RP2040的IO_BANK0_PROC0_INTS2寄存器对应GPIO16~23的中断状态,其中GPIO16对应寄存器的位0,GPIO17对应位1,以此类推,GPIO20对应位4。当前定义的GPIO_BTN_MSK = 0x00040000是位18,完全不匹配,正确定义应为:

.equ GPIO_BTN_MSK, 0x10  @ 1 << 4,对应GPIO20在PROC0_INTS2中的位

2. 修正中断标志清除操作

清除RP2040 GPIO中断时,需向IO_BANK0_INTR2寄存器的对应位写1(写1清除)。GPIO20对应该寄存器的位4,而非位20,因此中断处理函数中的清除代码要修改:

end_interrupt:
  ldr r0, =0x1
  lsls r0, #4  @ 对应GPIO20在INTR2中的位4
  ldr r1, =(IO_BANK0_BASE + IO_BANK0_INTR2_OFFSET)
  str r0, [r1] 

  pop {pc}

3. 检查中断触发方式配置

确认asm_gpio_set_irq函数是否正确配置了GPIO20的中断触发条件:

  • 如果配置为电平触发,若按键持续处于触发电平(比如按键按下未松开),中断会反复触发
  • 建议配置为边沿触发(上升沿/下降沿),避免电平触发导致的重复中断

修复后的核心代码片段

调整后的关键定义和中断处理函数:

.equ GPIO_BTN_MSK, 0x10  @ 修正GPIO20的中断状态掩码

...

.thumb_func
gpio_isr:
  push {lr}

  ldr r2, =(IO_BANK0_BASE + IO_BANK0_PROC0_INTS2_OFFSET)
  ldr r1, [r2]
  ldr r3, =GPIO_BTN_MSK
  ands r1, r3
  cmp r1, r3
  bne not_btn
btn:
  bl btn_pushed 
  b end_interrupt
not_btn:
  bl btn_released

end_interrupt:
  ldr r0, =0x1
  lsls r0, #4  @ 修正中断标志清除的位偏移
  ldr r1, =(IO_BANK0_BASE + IO_BANK0_INTR2_OFFSET)
  str r0, [r1] 

  pop {pc}

内容的提问来源于stack exchange,提问作者Oliver Mitchell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 12:45:00