【嵌入式Linux】i.MX6ULL 外部中断服务函数的初始化

news2024/10/10 8:18:47

文章目录

  • 1. Cortex-A7 中断系统
    • 1.1 分析
    • 1.2 具体处理流程
  • 2. 外部中断服务函数的初始化
    • 2.1 基本流程分析
    • 2.2 具体代码分析
      • 2.2.1. 定义中断处理类型和结构体
      • 2.2.2. 初始化中断系统
      • 2.2.3. 注册中断处理函数
      • 2.2.4. 具体的中断处理逻辑
      • 2.2.5. 默认的中断处理函数
  • 3. 完整代码

本文章结合了正点原子的 i.mx6u嵌入式Linux开发指南和笔者的理解。

1. Cortex-A7 中断系统

1.1 分析

1. 中断向量表:

  • Cortex-A7 也有中断向量表,位于代码的最前面。
  • 包含 8 个异常中断,每个中断对应一个向量地址和中断模式。
  • 表 17.1.2.1 列出了这 8 个中断:
    • 复位中断 (Reset):特权模式 (SVC)
    • 未定义指令中断 (Undefined Instruction):未定义指令中止模式 (Undef)
    • 软中断 (Software Interrupt, SWI):特权模式 (SVC)
    • 指令预取中止中断 (Prefetch Abort):中止模式
    • 数据访问中止中断 (Data Abort):中止模式
    • 未使用 (Not Used):未使用
    • IRQ 中断 (IRQ Interrupt):外部中断模式 (IRQ)
    • FIQ 中断 (FIQ Interrupt):快速中断模式 (FIQ)

2. Cortex-A7 中断向量表与 Cortex-M 的区别:

  • Cortex-M 中断向量表列举了芯片的所有中断向量,包括外设中断。
  • Cortex-A7 中断向量表只列出了 8 个基本中断,其中 IRQ 中断包含了所有外部中断。
  • 也就是说,Cortex-A7 中,所有外部中断都通过 IRQ 中断进行处理。

3. IRQ 中断处理:

  • 当任意一个外部中断发生时,都会触发 IRQ 中断。
  • IRQ 中断服务函数需要读取指定的寄存器来判断具体是哪个外部中断发生了。
  • 根据具体的中断做出相应的处理。

4. 外部中断与 IRQ 中断的关系:
在这里插入图片描述

  • 图中左侧的 Software0_IRQn~PMU_IRQ2_IRQ 都是 I.MX6U 的外部中断,它们都属于 IRQ 中断。
  • 当任意一个外部中断发生时,IRQ 中断会被触发。
  • 在 IRQ 中断服务函数中需要判断是哪个外部中断发生了,并进行相应的处理。

1.2 具体处理流程

  1. 某个外部中断发生。
  2. IRQ 中断被触发。
  3. IRQ 中断服务函数执行。
  4. IRQ 中断服务函数调用 C 语言中断处理函数。
  5. C 语言中断处理函数根据中断号判断是哪个外部中断发生了。
  6. C 语言中断处理函数执行相应的处理逻辑。
  • IRQ 中断就像一个“总开关”,而外部中断就像“子开关”。当某个子开关打开时,会触发总开关,然后需要根据子开关的具体情况进行处理。
  • 前面的文章我们已经对IRQ中断服务函数进行了初始化,设置在IRQ中断服务函数中执行C语言的中断服务函数:
ldr r2, =system_irqhandler	/* 加载C语言中断处理函数到r2寄存器中*/
blx r2						/* 运行C语言中断处理函数,带有一个参数,保存在R0寄存器中 */

下面我们就开始在C语言中,根据不同的中断号进行不同的中断服务函数初始化和处理。

2. 外部中断服务函数的初始化

2.1 基本流程分析

  1. 定义中断处理类型和结构体
  2. 初始化中断系统
  3. 注册中断处理函数
  4. 具体的中断处理逻辑
  5. 默认的中断处理函数

2.2 具体代码分析

2.2.1. 定义中断处理类型和结构体

此步骤定义了中断处理函数的类型别名 system_irq_handler_t 和中断处理函数结构体 sys_irq_handle_t

typedef void (*system_valve_handler_t)(unsigned int gicciar, void *param);

typedef struct _sys_irq_handle{
    system_valve_handler_t irqHandler; // 中断处理函数
    void *usrparam;                    // 中断处理函数的参数
} sys_irq_handle_t;

/*中断处理函数表*/
static sys_irq_handle_t irqTable[NUMBER_OF_INT_VECTORS];

解释

  • system_irq_handler_t 是一个函数指针类型,指向的函数用于处理中断,接收中断号和用户参数。
  • sys_irq_handle_t 结构体包含一个中断处理函数和一个用于传递给该函数的用户参数。
  • irqTable是一个结构体数组,包含所有外部中断的结构体,共NUMBER_OF_INT_VECTORS=160个。

2.2.2. 初始化中断系统

初始化中断系统包括 GIC 初始化和中断向量表的初始化。

/*初始中断向量表*/
void system_irqtable_init(void)
{
    irqNesting = 0;//中断计数器清0
    unsigned int i;
    for(i=0; i<NUMBER_OF_INT_VECTORS; i++){
        irqTable[i].irqHandler = default_irqhandler;
        irqTable[i].usrparam = NULL;
    }
}

void int_Init(void)
{
    GIC_Init(); // 初始化GIC
    system_irqtable_init();
    __set_VBAR(0x87800000); // 中断向量偏移设置
}

解释

  • GIC_Init() 调用是用来初始化通用中断控制器(Generic Interrupt Controller)。
  • system_irqtable_init() 初始化中断处理函数表,为每个可能的中断分配默认处理函数。
  • __set_VBAR(0x87800000) 设置中断向量基地址寄存器(VBAR)。

2.2.3. 注册中断处理函数

此步骤允许用户为特定的中断号注册自定义的处理函数。

void system_register_irqhandler(IRQn_Type irq, system_irq_handler_t handler, void *param)
{
    irqTable[irq].irqHandler = handler;
    irqTable[irq].usrparam = param;
}

解释

  • 通过指定的 irq 中断号,用户可以将自定义的处理函数 handler 和参数 param 注册到中断处理函数表 irqTable 中。

2.2.4. 具体的中断处理逻辑

  • 该部分是实际的中断处理逻辑,由具体的中断处理函数 system_irqhandler 实现。
  • system_irqhandler实际上由IRQ中断调用,完成了选择不同外部中断函数进行处理中断的功能。
void system_irqhandler(unsigned int gicciar)
{
    irqNesting++; // 中断计数器
    uint32_t intNum = gicciar & 0x3FF; // 从低10位获取中断ID
    if(intNum >= NUMBER_OF_INT_VECTORS) return; // 检查中断ID是否正常
    irqTable[intNum].irqHandler(intNum, irqTable[intNum].usrparam); // 根据中断号,选取中断处理函数执行
    irqNesting--; // 中断执行完,中断计数器-1
}

解释

  • irqNesting 记录当前正在处理的中断嵌套层数。
  • 通过 gicciar & 0x3FF 提取中断号,并检查其有效性,然后调用相应的中断处理函数。

2.2.5. 默认的中断处理函数

提供一个默认的中断处理函数,当没有特定的处理函数注册时使用。

void default_irqhandler(unsigned int gicciar, void *param)
{
    while(1); // 死循环,用于捕捉未处理的中断
}

解释

  • 这是一个防止未注册中断导致系统异常退出的安全措施。如果执行到此函数,表明发生了未注册处理函数的中断。

3. 完整代码

bsp_int.c

#include "bsp_int.h"
static unsigned int irqNesting;//中断计数器,用于嵌套

/*中断处理函数表*/
static sys_irq_handle_t irqTable[NUMBER_OF_INT_VECTORS];
/*初始中断向量表*/
void system_irqtable_init(void)
{
    irqNesting = 0;//中断计数器清0
    unsigned int i;
    for(i=0; i<NUMBER_OF_INT_VECTORS; i++){
        irqTable[i].irqHandler = default_irqhandler;
        irqTable[i].usrparam = NULL;
    }
}

/*注册中断处理函数*/
void system_register_irqhandler(IRQn_Type irq, system_irq_handler_t handler, void *param)
{
    irqTable[irq].irqHandler = handler;
    irqTable[irq].usrparam = param;
}

//中断初始化函数
void int_Init(void)
{
    GIC_Init();//初始化GIC
    system_irqtable_init();

    __set_VBAR(0x87800000);//中断向量偏移设置

}


/*具体的中断处理函数,IRQ_Handler会调用此C函数*/
void system_irqhandler(unsigned int gicciar)
{
    irqNesting++;//中断计数器
    uint32_t intNum = gicciar & 0x3FF;//从低10位获取中断ID
    //检查中断ID是否正常
    if(intNum >= NUMBER_OF_INT_VECTORS) return;
    //根据中断号,选取中断处理函数执行
    irqTable[intNum].irqHandler(intNum, irqTable[intNum].usrparam);
    irqNesting++;//中断执行完,中断计数器-1
}


//默认中断处理函数
void default_irqhandler(unsigned int gicciar, void *param)
{
    while(1);
}

bsp_int.h

#ifndef __BSP_INT_H
#define __BSP_INT_H

#include "imx6u.h"

// 这段代码定义了一个类型别名 system_irq_handler_t,
// 用于表示一个指向中断处理函数的指针。
// 该函数指针指向的函数接收两个参数:
// 中断号
// 和一个指向任意类型数据的指针,用于传递额外的参数。
typedef void (*system_irq_handler_t)(unsigned int gicciar, void *param);

//中断处理函数结构体
typedef struct _sys_irq_handle{
    system_irq_handler_t irqHandler;//中断处理函数
    void *usrparam;//中断处理函数的参数
}sys_irq_handle_t;

void int_Init(void);
void system_irqtable_init();
void default_irqhandler(unsigned int gicciar, void *param);
void system_register_irqhandler(IRQn_Type irq, system_irq_handler_t handler, void *param);

#endif // !__BSP_INT_H

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1862982.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

django学习入门系列之第三点《案例 小米商城二级菜单》

文章目录 样例划分区域搭建骨架logo区域完整代码 小结往期回顾 样例 划分区域 搭建骨架 <!-- 二级菜单部分 --> <div class"sub-header"><div class"container"><div class"logo">1</div><div class"sea…

[word] Word表格怎么填充序列号? #微信#微信#笔记

Word表格怎么填充序列号&#xff1f; Word表格怎么填充序列号&#xff1f;在Excel中填充序列号是很轻松的事情&#xff0c;在Word表格中填充序列号就没那么简单&#xff0c;但是还是有小技巧&#xff0c;可以实现Word表格序号填充&#xff0c;还能自动更新。 1、插入序号 先…

JAVAEE之网络原理_传输控制协议(TCP)的滑动窗口、流量控制、拥塞控制、延迟应答、捎带应答机制

前言 在前面几节&#xff0c;我们讲解了TCP协议的基本概念、报文格式。还介绍了确认应答机制、超时重传、连接管理机制&#xff0c;在本节中 我们将会继续介绍TCP协议的其他机制。 一、滑动窗口机制&#xff08;效率机制&#xff09; 在前面的章节中我们讨论了确认应答策略&…

C++ ─── vector的实现

知识点&#xff1a; ① 因为vector是模版&#xff0c;所以声明和定义都放在.h中&#xff0c;防止出现编译错误 .h不会被编译&#xff0c;在预处理中.h在.cpp中展开所以在编译时只有.cpp 而 .cpp顺序编译&#xff0c;只会进行向上查找&#xff0c;因此至少有函数的声明。 ②memc…

【Linux】进程 | 控制块pcb | task_struct | 创建子进程fork

目录 Ⅰ. 进程的概念&#xff08;Process&#xff09; 1. 什么是进程&#xff1f; 2. 多进程管理 3. 进程控制块&#xff08;PCB&#xff09; task_struct 的结构 Ⅱ. 进程查看与管理 1. 使用指令查看进程 2. /proc 查看进程信息 3. 获取进程 ID 4. 创建子进程 原因…

在Ubuntu22.04 使用stable-diffusion-webui 秋叶整合包

背景 众所周知&#xff0c;赛博菩萨已经发布了windows下的整合包&#xff0c;开箱即用&#xff0c;且集成度较高。 那我为啥非要在Ubuntu下使用呢&#xff1f; 当然是因为主力机就是Ubuntu系统啦。而且涉及到sd webui API 的调用&#xff0c;在Ubuntu 下调试更加方便一点。 那…

PG实践|内置函数之GENERATE_SERIES之深入理解

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、腾讯云优秀创作者、ACDU成员 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注…

2024年第十五届蓝桥杯青少组大赛8月24日开启

据蓝桥杯青少组官网显示&#xff0c;2024年第十五届蓝桥杯青少组大赛8月24日开启。 蓝桥杯青少组历届题库地址&#xff1a;http://www.6547.cn/question/cat/2 蓝桥杯青少组历届真题下载&#xff1a;http://www.6547.cn/wenku/list/10

【神经网络】CNN网络:深入理解卷积神经网络

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步&#xff01; CNN网络&#xff1a;深入理解…

VideoLLaMA 2:多模态视频理解新突破,音频理解能力再升级,挑战 GPT-4V

前言 近年来&#xff0c;人工智能技术飞速发展&#xff0c;尤其是大模型的出现&#xff0c;为视频理解和生成领域带来了前所未有的机遇。然而&#xff0c;现有的视频大模型&#xff08;Video-LLM&#xff09;在处理视频中复杂的时空信息和音频信息方面仍存在不足&#xff0c;例…

【C++11(二)】lambda表达式和可变参数模板

一、可变参数模板 C11的新特性可变参数模板 能够让您创建可以接受 可变参数的函数模板和类模板 // Args是一个模板参数包&#xff0c;args是一个函数形参参数包 // 声明一个参数包Args...args&#xff0c;这个参数包中可以包含0到任意个模板参数。 template <class ...Arg…

笔记101:OSQP求解器的底层算法 -- ADMM算法

前言1&#xff1a;这篇博客仅限于介绍拉格朗日乘子法&#xff0c;KKT条件&#xff0c;ALM算法&#xff0c;ADMM算法等最优化方法的使用以及简版代码实现&#xff0c;但不会涉及具体的数学推导&#xff1b;不过在下面我会给出具体数学推导的相关文章和截图&#xff0c;供学有余力…

Elasticsearch:使用 Llamaindex 的 RAG 与 Elastic 和 Llama3

这篇文章是对之前的文章 “使用 Llama 3 开源和 Elastic 构建 RAG” 的一个补充。我们可以在本地部署 Elasticsearch&#xff0c;并进行展示。我们将一步一步地来进行配置并展示。你还可以参考我之前的另外一篇文章 “Elasticsearch&#xff1a;使用在本地计算机上运行的 LLM 以…

在线epub阅读器epub;在线图书阅读器;专门为epub定制的阅读器;免费在线电子图书epub阅读器

背景&#xff1a;不记得某时某刻了&#xff0c;就是当时想要使用电脑阅读epub图书&#xff0c;也找了好些个在线epub阅读器&#xff0c;但总有一些不如意的地方&#xff0c;如某些功能需要会员之类的&#xff0c;突发临想的就想到自己开发一个&#xff0c;就此&#xff0c;一个…

大模型RAG技术:构建高效、可信赖的知识检索系统

前言 LLM 问题 幻觉&#xff1a;在没有答案的情况下提供虚假信息。 过时&#xff1a;当用户需要特定的当前响应时&#xff0c;提供过时或通用的信息。 来源&#xff1a;从非权威来源创建响应。由于术语混淆&#xff0c;不同的培训来源使用相同的术语来谈论不同的事情&#…

C# Onnx Yolov8-OBB 旋转目标检测 行驶证副页条码+编号 检测,后续裁剪出图片并摆正显示

C# Onnx Yolov8-OBB 旋转目标检测 行驶证副页条码编号 检测&#xff0c;后续裁剪出图片并摆正显示 目录 效果 模型信息 项目 代码 下载 效果 模型信息 Model Properties ------------------------- date&#xff1a;2024-06-25T10:59:15.206586 description&#xff1a;…

第一课:SSH协议、SSHD守护进程、Openssh软件包

第一节课 6月12日 ssh协议 关键问题 一、ssh、sshd、openssh的概念和区别&#xff1f; 二、ssh是基于什么架构&#xff1f;B/S还是C/S&#xff1f; 三、用户远程连接服务器经历哪些过程&#xff1f; 四、如何查看openssh软件包是否安装&#xff1f; 五、rpm和yum的区别&#xf…

node带参数命令

不带参数命令示例&#xff1a; node /www/wwwroot/server 带参数命令示例&#xff1a; node /www/wwwroot/server arg1 arg2 arg3 在启动页进行参数处理&#xff1a; // 获取启动参数(除去前2个默认参数&#xff0c;示例&#xff1a;node /www/wwwroot/server arg1 arg2 …

SAP ABAP 之容器

文章目录 前言一、案例介绍/笔者需求二、自定义容器 a.实例化对象 b.自定义容器效果演示 c.Copy Code 三、自适应容器 a.常用 必须 参数理解 b.METRIC 度量单位 c.RATIO 百分比尺寸 d.STYLE 容器…

WMV 视频格式怎么转换?WMV 视频为什么不流行了?

目前有越来越多的视频格式类型&#xff0c;如常见的 MP4、FLV、AVI 等等&#xff0c;而技术的演变也逐渐让一些常见的视频格式变的越来越少了。 今天我们一起来聊下 WMV 这个视频格式&#xff0c;让我们看看它的发展以及为什么现在越来越少人使用了。 什么是 WMV 视频格式&…