嵌入式-中断

中断是什么?

CPU在处理当前任务时,因为内部或外部事件的发生(中断源),暂停当前任务的执行(上下文切换保存执行状态),
转而执行与事件相关的程序(中断服务程序),处理完成后再放回原任务的过程(恢复执行状态)。

中断的种类?

1.同步中断:也即是我们通常所说的异常(),是在CPU执行特定指令时出现的非法情况,它的产生是由于前面的CPU操作引起的,是同步发生的;如除零异常;
2.异步中断:主要是由外部事件触发的,这就是我们常说的中断,它的发生不可预料的,是异步的;比如键盘中断;
3.软中断:在大多数硬件体系结构中,都提供软中断的功能,主要用于进入管理模式等的手段。如kill(pid, SIGUSR1)、raise()
4.自定义中断

中断是怎么发生的?

1.外部中断:外部中断通常用于处理外部引脚状态变化的事件,如按键触发;
2.定时器中断:定时器中断用于定时执行特定任务,例如定时采集传感器数据;
3.串口中断:串口中断用于处理串口接收和发送的异步事件。如程序错误引发的异常;

中断工作原理?以 ARM Cortex-M 为例

中断向量表

  1. 这是一个存储在内存中的表,它将每个中断号映射到对应的ISR地址。
  2. 当中断发生时,CPU会查询这个表,找到对应的服务例程并执行。

嵌套向量中断控制器(NVIC)

中断嵌套

sensor传感器中断完整流程

1.设备树注册中断;

点击查看代码
&i2c1 {
    sensor@48 {
        compatible = "mycompany,my-sensor";
        reg = <0x48>;

        interrupt-parent = <&gpio1>;
        interrupts = <12 IRQ_TYPE_EDGE_RISING>; // GPIO1_12 上升沿触发

        status = "okay";
    };
};

驱动程序将从这里解析中断信息并注册;

2.驱动中中断注册流程

  • 匹配 of_device_id,绑定 platform 驱动
点击查看代码
static const struct of_device_id sensor_dt_ids[] = {
    { .compatible = "mycompany,my-sensor" },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sensor_dt_ids);

static struct i2c_driver my_sensor_driver = {
    .probe    = my_sensor_probe,
    .remove   = my_sensor_remove,
    .driver   = {
        .name = "my_sensor",
        .of_match_table = sensor_dt_ids,
    },
};
module_i2c_driver(my_sensor_driver);

  1. 在 probe 中解析中断并注册中断处理函数
点击查看代码
static irqreturn_t sensor_irq_handler(int irq, void *dev_id)
{
    struct my_sensor_data *data = dev_id;

    // 简单处理:设置标志位或唤醒等待队列
    data->irq_flag = true;
    wake_up(&data->wait_queue);

    return IRQ_HANDLED;
}

static int my_sensor_probe(struct i2c_client *client,
                           const struct i2c_device_id *id)
{
    struct my_sensor_data *data;
    int irq;
    
    data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
    i2c_set_clientdata(client, data);
    
    // 解析中断号
    irq = of_irq_get(client->dev.of_node, 0);
    if (irq < 0)
        return dev_err_probe(&client->dev, irq, "Failed to get IRQ\n");

    data->irq = irq;

    // 初始化等待队列(可选)
    init_waitqueue_head(&data->wait_queue);

    // 注册中断处理程序
    return devm_request_threaded_irq(&client->dev,
                                     irq,
                                     NULL,  // top-half (快速中断处理) 可设为 NULL
                                     sensor_irq_handler, // bottom-half (可睡眠)
                                     IRQF_TRIGGER_RISING | IRQF_ONESHOT,
                                     "my_sensor_irq",
                                     data);
}

3.硬件触发中断(sensor 发出信号) 例如某个 sensor 检测到数据准备好了,它将 GPIO 输出由低变高(或高变低),触发对应的 GPIO 控制器中断, Linux 内核通过中断控制器(如 GIC)调用已注册的 ISR 函数;

4.中断处理函数响应

点击查看代码
static irqreturn_t sensor_irq_handler(int irq, void *dev_id)
{
    struct my_sensor_data *data = dev_id;

    // 常见操作:
    // 1. 设置标志位
    // 2. 唤醒等待队列
    // 3. 调度工作队列或 tasklet 进一步处理
    // 4. 读取 sensor 寄存器确认中断源

    sensor_read_data(data);  // 通常读取中断状态寄存器

    return IRQ_HANDLED;
}

多数 sensor 在帧同步点(如帧尾或帧头)产生中断,用于通知驱动新帧就绪;

为什么需要中断?(原因分析)

  1. 实时性高:事件一发生就立刻响应
    如:Sensor 数据采集完成、中断引脚拉高;CPU 马上响应 → 保证实时数据处理(如帧同步、运动检测)

  2. 省资源、省功耗
    不用轮询 GPIO 或 I2C:不再每几毫秒主动去检查一次状态;CPU 可空闲/休眠,直到被中断唤醒 → 适用于移动设备

  3. 减少 CPU 占用,提高系统效率
    如果没有中断,只能不停轮询 sensor 状态;大量空转循环会占用 CPU、延迟其他任务

  4. 硬件必须:某些 sensor(如摄像头)必须基于帧中断(VSYNC)做控制
    Camera sensor 帧同步信号用于驱动 frame buffer、ISP 等同步控制

中断调试中断常见问题

问题 原因
中断不触发 中断未使能 / 中断源未配置 、GPIO 配置错误;中断类型设置不正确;外设未连接或异常
中断触发但不进入 ISR 中断优先级设置问题 / ISR 名错误 / ISR 没注册成功;probe() 中逻辑错误
中断反复触发不清除 中断标志位未清除

参考链接:
https://www.cnblogs.com/swk0918/category/1936804.html (宝藏博主-嵌入式100题合集)
https://www.cnblogs.com/swk0918/p/14453309.html
https://cloud.tencent.com/developer/article/2204914
https://developer.aliyun.com/article/1458003
http://www.weboch.com.cn/ARM/interrupt-mechanism.asp
https://zhuanlan.zhihu.com/p/664890195

posted @ 2025-06-30 11:12  chivalrySun  阅读(90)  评论(0)    收藏  举报