如何让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
相关产品推荐
相关产品推荐

