裸机开发:ARMv7-A中断驱动LED/蜂鸣器实战

无操作系统(no OS)环境下实现按键中断驱动 LED/蜂鸣器响应的底层系统初始化与中断处理流程

特征 说明
架构 ARMv7-A(32 位),使用 cpsid imcr p15,...VBARGIC 等关键词明确指向 Cortex-A 系列(如 NXP i.MX6ULL、Raspberry Pi 早期裸机等)
运行环境 无操作系统(bare-metal),直接运行在硬件上,从 _reset_handler 开始执行
核心功能 按键(GPIO)触发中断 → 控制 LED 和蜂鸣器
中断控制器 使用 GIC(Generic Interrupt Controller),这是 Cortex-A 的标准中断控制器
启动流程 手动初始化 CPU 模式、栈、.bss、向量表、GIC、GPIO,完全自主控制启动过程
代码结构 包含汇编(start.s)、C 初始化函数、中断服务例程(ISR)注册机制

阶段 0:系统复位 & CPU 初始化

触发条件为上电或复位,入口函数为 _reset_handler(位于 start.s)。该阶段的主要目的是配置 CPU 基本工作状态,确保系统安全启动。

关键操作

禁用 IRQ 通过 cpsid i 指令实现,确保 CPU 内部禁止中断。

配置异常向量表基地址(VBAR)通过 mcr__set_VBAR 完成,必须在 IRQ 使能前设置。

切换 CPU 模式(如 IRQ 模式 cps #0x12 和 SYS/用户模式 cps #0x1F)。

初始化栈指针为每种 CPU 模式单独设置,例如 ldr sp, =0x82000000

清空 .bss 段通过循环写 0 实现,避免全局变量包含垃圾值。

注意事项

VBAR 设置必须在 IRQ 使能前完成。

栈指针需为每种模式独立初始化。
.bss 清零必须正确执行,否则可能导致未定义行为。


阶段 1:系统中断控制器初始化

触发条件为 main() 或初始化函数调用,主要函数为 system_interrupt_init()

关键操作

通过 __set_VBAR(0x87800000) 设置异常向量表入口地址。

初始化 GIC 中断控制器:

  • 禁止所有中断(GICD_CTLR = 0)。
  • 清除残留中断状态。
  • 设置默认优先级阈值。

注意事项

GIC 初始化必须在 IRQ 使能前完成。

VBAR 地址需与 _irq_handler 入口严格对应。


阶段 2:GPIO(按键)初始化

触发条件为 key_init() 调用,目的是配置引脚复用、中断触发及注册服务函数。

关键操作

引脚复用通过 IOMUXC_SetPinMux()UART1_CTS_B 改为 GPIO1_IO18

电气特性通过 IOMUXC_SetPinConfig() 设置驱动能力、上拉/下拉等。

配置 GPIO 为输入模式:GPIO1->GDIR &= ~(1<<18)

设置中断触发方式(如边沿触发):GPIO1->ICR2 = (3<<4)

启用 GPIO 内部中断:GPIO1->IMR = (1<<18)

注册中断服务函数:system_interrupt_register(GPIO1_Combined_16_31_IRQn, key_irq_handler)

注意事项

GIC 需通过 GIC_EnableIRQ() 允许中断转发至 CPU。

中断优先级通过 GIC_SetPriority() 设置,数值越低优先级越高。


阶段 3:按键触发 GPIO 中断

触发条件为用户按下按键,硬件自动检测电平变化并生成中断请求。

关键操作

GPIO 硬件比较采样电平与 ICR 配置的触发条件(如上升/下降沿)。

中断状态寄存器 ISR.bit18 置 1,触发组合中断线 GPIO1_IO16~31 至 GIC。

注意事项
ISR 为写 1 清零类型,处理完成后需手动清除。
IMR 必须置 1 以允许中断信号传递。


阶段 4:GIC 转发中断

GIC 判断中断源是否使能,并检查优先级是否允许进入 CPU。

关键操作

GIC 读取 ISENABLER 确认中断使能状态。

检查 IPRIORITYR 优先级是否高于 CPU 当前阈值。

拉低 CPU 的 IRQ 引脚信号。

注意事项

未调用 GIC_EnableIRQ() 将导致 CPU 无法接收中断。

优先级过低或阈值过高可能屏蔽中断。


阶段 5:CPU 进入 IRQ 模式

CPU 检测 IRQ 信号后自动保存现场并跳转至异常向量表。

关键操作

硬件自动完成:

  • 保存 SPSR_irq = CPSR
  • 保存 LR_irq = PC+4
  • 切换 CPSR.M 为 IRQ 模式。
  • 跳转至 VBAR + 0x18_irq_handler 入口)。

注意事项
_irq_handler 地址必须与 VBAR 设置一致。

IRQ 模式栈需预先初始化。


阶段 6:执行 IRQ 处理函数

处理流程为 _irq_handlersystem_interrupt_handler()key_irq_handler()

关键操作

汇编保存现场:stmfd sp!, {r0-r12, lr}

通过 Vector_table 调用 key_irq_handler() 执行用户逻辑(如 LED 翻转)。

清除 GPIO 中断标志:GPIO1->ISR |= (1 << 18)

恢复现场并返回:ldmfd sp!, {r0-r12, pc}^

注意事项

必须清除 ISR 标志以避免中断丢失。

保存和恢复现场需完整,防止寄存器污染。


阶段 7:中断处理完成返回

CPU 恢复至触发 IRQ 前的模式,用户程序继续执行。

关键操作

通过 ldmfd sp!, {r0-r12, pc}^ 恢复 CPSRPC

注意事项

返回指令需使用 ^ 以恢复 SPSR

中断处理函数应避免长时间阻塞。

相关推荐
秋深枫叶红3 小时前
嵌入式第四十九篇——ARM系列——IMX6ULL开发板
arm开发·嵌入式硬件
南烟斋..4 小时前
ARM Cortex-A7(IMX6ULL)嵌入式裸机开发指南:从点灯到中断
arm开发·单片机·嵌入式硬件
ArrebolJiuZhou4 小时前
03 rtp,rtcp,sdp的包结构
linux·运维·服务器·网络·arm开发
松涛和鸣4 小时前
59、 IMX6ULL按键驱动开发:轮询到中断的实现
linux·服务器·c语言·arm开发·数据库·驱动开发
切糕师学AI5 小时前
ARM Cortex-M 存储器映射
arm开发
VekiSon5 小时前
ARM架构——中断系统详解
c语言·arm开发·嵌入式硬件
ZL.zheng5 小时前
can范围唤醒的那些事?
arm开发
ShiMetaPi5 小时前
GM-3568JHF丨ARM+FPGA异构开发板应用开发教程:04 MIPI屏幕检测案例
arm开发·fpga开发·rk3568
代码游侠6 小时前
学习笔记——GPIO按键与中断系统
c语言·开发语言·arm开发·笔记·嵌入式硬件·学习·重构