当前位置: 首页 > java >正文

像信号处理一样理解中断:STM32与RK3399中断机制对比及 Linux 驱动开发实战

ARM 处理器工作模式、异常向量表与中断机制解析 —— 结合 STM32 与 RK3399 中断对比及按键驱动实例

在嵌入式开发中,ARM 处理器的工作模式、异常向量表、中断向量表是理解中断系统的核心。不同的芯片如 STM32F407(Cortex-M4 内核)和 RK3399(Cortex-A72/A53 内核)在中断处理机制上既有共同点,又有明显区别。本文将系统讲解两者的关系,并通过 RK3399 的按键中断驱动实例来展示代码实现。

一、ARM 处理器的 7 种工作模式

ARM 架构下,CPU 运行时会根据不同的事件切换到不同的模式,共有 7 种:

  1. User 模式(USR):普通用户程序运行模式,无特权。
  2. FIQ 模式(FIQ):快速中断模式,响应高优先级中断。
  3. IRQ 模式(IRQ):普通中断模式,响应一般外设中断。
  4. Supervisor 模式(SVC):系统调用模式,执行 svc 指令时进入。
  5. Abort 模式(ABT):访问非法内存地址时进入。
  6. Undefined 模式(UND):执行未定义指令时进入。
  7. System 模式(SYS):与 User 模式类似,但具有特权,通常内核运行在此模式。

CPU 在不同模式下有独立的寄存器组和堆栈,从而实现快速上下文切换。

二、异常向量表

当 CPU 遇到异常或中断时,需要跳转到相应的入口函数。ARM 架构规定了异常向量表,通常放在固定地址(0x00000000 或 0xFFFF0000)。

ARMv7 的异常向量表示例:

地址偏移异常类型说明
0x00Reset上电复位
0x04Undefined Instruction未定义指令
0x08SWI (SVC)软件中断
0x0CPrefetch Abort预取异常
0x10Data Abort数据访问异常
0x14保留-
0x18IRQ普通中断
0x1CFIQ快速中断

三、中断向量表

ARM 架构的异常向量表里只有 IRQ/FIQ 两个入口,但一个芯片上可能有数百个外设中断源,因此需要中断控制器来管理。

  • STM32(Cortex-M 内核)
    使用 NVIC(Nested Vectored Interrupt Controller),中断向量表直接存放在 Flash 中,每个中断源对应一个函数入口地址,CPU 进入中断时会直接跳转。

  • RK3399(Cortex-A 内核)
    使用 GIC(Generic Interrupt Controller)。所有外设中断先统一进入 IRQ 入口,由 GIC 确定中断号,再由内核软件框架分发给具体的驱动 ISR。

四、STM32 与 RK3399 中断机制对比

特性STM32F407 (Cortex-M4)RK3399 (Cortex-A72/A53)
向量表每个外设独立入口,硬件自动分发统一入口,软件分发
中断控制器NVICGIC
压栈机制硬件自动保存寄存器内核汇编保存现场
使用场景MCU 裸机/RTOSSoC,运行 Linux/Android

五、RK3399 按键中断驱动实例

在 Linux 内核中,中断的处理方式非常类似信号处理:

  • 信号:由内核传递到用户态,由用户定义的 handler 来响应。
  • 中断:由硬件触发,进入内核,通过中断处理函数来完成响应。

下面通过一个按键中断驱动示例来讲解:

1. 编写步骤

  1. 确定按键 GPIO 引脚号,并将其配置为外部中断模式。
  2. 将 GPIO 引脚号转换为中断号。
  3. 定义中断处理函数。
  4. 注册中断(申请中断),绑定中断号与 ISR。
  5. 在模块卸载时释放中断。

2. 关键 API 函数

  • 申请中断request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
  • 释放中断free_irq(unsigned int irq, void *dev)
  • 定义中断处理函数irqreturn_t handler(int irq, void *dev_id)
  • GPIO 转中断号gpio_to_irq(unsigned int gpio)

3. 示例代码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/irqreturn.h>#define KEY_GPIO    23   // 假设按键接在 GPIO23
static int key_irq;      // 保存对应的中断号// 中断处理函数
static irqreturn_t key_irq_handler(int irq, void *dev_id)
{printk(KERN_INFO "Key interrupt triggered! irq=%d\n", irq);// 这里可以添加按键消抖、状态处理等逻辑return IRQ_HANDLED;
}// 模块加载函数
static int __init key_irq_init(void)
{int ret;// 将 GPIO 引脚转换为中断号key_irq = gpio_to_irq(KEY_GPIO);if (key_irq < 0) {printk(KERN_ERR "Failed to map GPIO to IRQ\n");return key_irq;}// 申请中断// IRQF_TRIGGER_FALLING 表示下降沿触发ret = request_irq(key_irq, key_irq_handler, IRQF_TRIGGER_FALLING,"key_irq_demo", NULL);if (ret) {printk(KERN_ERR "Failed to request IRQ\n");return ret;}printk(KERN_INFO "Key IRQ module loaded, GPIO=%d, IRQ=%d\n", KEY_GPIO, key_irq);return 0;
}// 模块卸载函数
static void __exit key_irq_exit(void)
{free_irq(key_irq, NULL);  // 释放中断printk(KERN_INFO "Key IRQ module unloaded\n");
}module_init(key_irq_init);
module_exit(key_irq_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("CSDN Example");
MODULE_DESCRIPTION("RK3399 Key Interrupt Demo");

4. 代码说明

  1. gpio_to_irq(KEY_GPIO):将 GPIO 引脚号转换为内核的中断号。
  2. request_irq():向内核注册一个中断,指定触发方式(上升沿、下降沿等)。
  3. key_irq_handler():中断处理函数,响应按键事件。
  4. free_irq():在驱动卸载时释放中断,避免资源泄漏。

六、总结

  1. ARM 处理器的 7 种模式、异常向量表是架构层面的规定。
  2. 中断向量表由芯片厂商扩展,用于分发多个外设中断。
  3. STM32 的 NVIC 是硬件直接跳转,RK3399 的 GIC 是统一入口再由软件分发。
  4. 在 Linux 下编写中断驱动的步骤包括:引脚到中断号映射、定义 ISR、申请中断、释放中断。
  5. 中断处理与用户态信号处理有异曲同工之妙,都是事件触发 → 注册回调 → 执行回调逻辑。

(完)

http://www.xdnf.cn/news/19521.html

相关文章:

  • 数组(4)
  • QMainWindow使用QTabWidget添加多个QWidget
  • 【数学建模学习笔记】数据标准化
  • LeetCode刷题记录----74.搜索二维矩阵(Medium)
  • 构建无广告私人图书馆Reader与cpolar让电子书库随身携带
  • 站在巨人的肩膀上:gRPC通过HTTP/2构建云原生时代的通信标准
  • Unity游戏打包——打包流程
  • 【C++】类型转换详解:显式与隐式转换的艺术
  • Vue2存量项目国际化改造踩坑
  • Ansible变量的定义与使用
  • 安卓11 12系统修改定制化_____常用的几种修改固件 实现指定 “运行内存” 显示
  • 【lucene】 中的impactsenum与impactsdisi有啥区别?
  • 拥抱智能高效翻译 ——8 款视频翻译工具深度测评
  • (附源码)留言系统的设计与实现
  • 标定分享3--lidar与rtk/ins标定外参工程实现分享
  • 变频器实习总结14 电子元件中的内部参考电压 Type-c口对于BMS开发的优点
  • Synchronized 概述
  • 平衡二叉树(一)
  • 2016考研数学(二)真题
  • sunset: noontide靶场
  • AlphaFold 2 本地部署与安装教程(Linux)
  • 高速CANFD通讯接口芯片ASM1042性能分析与5Mbps多节点测验
  • 包的相对导入
  • MPI-NCCL-TEST 训练自检,基础通信和可用的机器
  • 《Bishop PRML》10.1 (3) 理解VAE KL loss
  • 【贪心算法】day5
  • PPO、DPO和GRPO的区别
  • Python实现BP神经网络
  • 利用美团longcat.ai编写的C语言支持指定压缩算法通用ZIP压缩程序
  • 硬件工程师成长之路:从入门到精通的技术旅程