【嵌入式Linux】i.MX6ULL GPIO 中断服务函数注册与编写

news2024/10/6 14:25:37

文章目录

  • 1 外部中断初始化与中断服务函数
    • 1.2 外部中断初始化函数 `exti_init`
      • 1.2.1 GPIO引脚配置
      • 1.2.2 中断使能与注册
      • 1.2.3 `GIC_EnableIRQ()`函数的分析
    • 1.3 中断服务函数 `gpio1_io20_irqhandler`
      • 1.3.1 消抖处理
      • 1.3.2 中断事件处理
      • 1.3.3 清除中断标志
  • 2 BUG处理
    • 2.1 问题描述
    • 2.2 解决过程
    • 2.3 解决方式

  • 本文章结合了正点原子的 i.mx6u嵌入式Linux开发指南和笔者的理解。
  • 前面我们进行了编写GPIO 中断管理与配置函数,下面将具体使用这些GPIO 中断管理与配置函数来进行一个具体的中断初始化,以及中断服务函数的编写

1 外部中断初始化与中断服务函数

这段代码主要用于初始化特定的GPIO端口(GPIO1_IO18)作为外部中断,并定义中断服务函数来处理中断事件。以下是每个部分的详细说明:

1.2 外部中断初始化函数 exti_init

1.2.1 GPIO引脚配置

key_config.direction = kGPIO_DigitalInput;
key_config.interruptMode = kGPIO_IntFallingEdge;
gpio_init(GPIO1, 18, &key_config);

设置GPIO1_IO18为数字输入并配置为下降沿触发中断。

1.2.2 中断使能与注册

GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);
system_register_irqhandler(GPIO1_Combined_16_31_IRQn, gpio1_io18_irqhandler, NULL);
gpio_int_enable(GPIO1, 18);

在GIC(通用中断控制器)中使能对应的中断,并注册中断服务函数gpio1_io18_irqhandler

1.2.3 GIC_EnableIRQ()函数的分析

/*  
 * 使能指定的中断
 */
FORCEDINLINE __STATIC_INLINE void GIC_EnableIRQ(IRQn_Type IRQn)
{
  	GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);
  	gic->D_ISENABLER[((uint32_t)(int32_t)IRQn) >> 5] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}

这段代码定义了一个名为 GIC_EnableIRQ 的函数,用于启用指定的中断。

  • 函数首先获取 GIC 控制器基地址。

    • __get_CBAR() 函数返回 GIC 控制器基地址,并将其与 0xFFFF0000UL 进行按位与运算,得到 GIC 控制器基地址的最高 16 位。
    • Cortex-A7 Technical ReferenceManua.pdfP138
      在这里插入图片描述
      在这里插入图片描述
  • 然后,函数计算出要操作的寄存器地址。

    • ((uint32_t)(int32_t)IRQn) >> 5 将中断号右移 5 位,得到中断号所在的寄存器索引。
  • 最后,函数设置该寄存器中的相应位,从而启用该中断。

    • ((uint32_t)(int32_t)IRQn) & 0x1FUL 将中断号与 0x1FUL 进行按位与运算,得到中断号在寄存器中的位索引。
    • 然后,将 1UL 左移 位索引 位,得到一个掩码,并将其写入 D_ISENABLER 寄存器中,从而启用该中断。
  • D_ISENABLER 寄存器是 GIC 分发器中的一组寄存器,用于控制每个中断的启用状态。
    ARM Generic Interrupt Controller(ARM GIC控制器)V2.0.pdfP93
    在这里插入图片描述

    • 每个寄存器包含 32 个 Set-enable 位,分别对应于 32 个中断。
    • 当 Set-enable 位被设置为 1 时,对应中断会被启用,这意味着 GIC 会将该中断转发到 CPU。
    • 当 Set-enable 位被设置为 0 时,对应中断会被禁用,这意味着 GIC 不会将该中断转发到 CPU。

    根据中断 ID (m),对应 GICD_ISENABLER 寄存器的编号 (n) 可以通过 n = m DIV 32 计算得到,也就是IRQn) >> 5

    • 对应 GICD_ISENABLER 寄存器的偏移地址为 0x100 + (4*n),这里不用手动计算,通过gic->D_ISENABLER·就可以得到。
    • 对应 GICD_ISENABLER 寄存器中需要设置的位的编号为 m MOD 32,也就是IRQn & 0x1FUL

1.3 中断服务函数 gpio1_io20_irqhandler

1.3.1 消抖处理

delay(10);

简单的延时用于消除由于机械或电气噪声产生的误触发。

1.3.2 中断事件处理

if(gpio_pin_read(GPIO1, 18) == 0){
    state = !state;
    beep_switch(state);
}

读取GPIO1_IO18的状态,如果为低电平(按键被按下),则切换状态并控制蜂鸣器的开关状态。

1.3.3 清除中断标志

gpio_int_flagClear(GPIO1, 18);

完成事件处理后,清除中断标志以准备接收下一个中断。

2 BUG处理

2.1 问题描述

程序烧写后,发现当尝试按下按键,进入按键中断处理函数时,灯会一直保持在按键按下那一刻的状态,程序卡死。

2.2 解决过程

  • 查看反汇编文件,发现bss段放在了程序起始地址,导致中断向量表的位置不对了(之前说过,应该放在程序的起始位置)

BSS 段(Block Started by Symbol)是程序内存中用于存储未初始化全局变量和静态变量的区域。

在这里插入图片描述

2.3 解决方式

_start:中,将bss段初始化放到中断向量表初始化后面

_start:
    @ 在处理器启动时执行一次,用于初始化中断向量表
    ldr pc, =Reset_Handler     @ 复位中断服务函数
    ldr pc, =Undefined_Handler @ 未定义指令中断服务函数
    ldr pc, =SVC_Handler       @ SVC中断服务函数
    ldr pc, =PreAbort_Handler  @ 预取终止
    ldr pc, =DataAbort_Handler @ 数据终止
    ldr pc, =NotUsed_Handler   @ 未使用
    ldr pc, =IRQ_Handler       @ IRQ中断服务函数
    ldr pc, =FIQ_Handler       @ FIQ中断服务函数

@ 复位中断服务函数
Reset_Handler:
    @ 0.禁止IRQ中断
    @ 方式:修改PSTATE处理器状态寄存器
    @ Change PE State (CPS) 用于修改处理器状态寄存器 (PSTATE) 中的某些位
    @ PSTATE 是一个特殊的寄存器,它包含了处理器当前的运行状态信息,包括:
    @ A (Application) 位: 控制应用程序模式下的中断是否允许。
    @ I (IRQ) 位: 控制 IRQ 中断是否允许。
    @ F (FIQ) 位: 控制 FIQ 中断是否允许。
    @ M (Mode) 位: 控制处理器当前运行的模式。
    cpsid i

    @ 1.关闭I/D Cache, MMU
    @ 方式:修改SCTLR寄存器
    @ (System Control Register,可以通过 CP15 协处理器访问)
    @ SCTLR寄存器:
        @ bit0:MMU 
        @ bit1:对齐控制 
        @ bit2:D Cache 
        @ bit11:分支预测控制 
        @ bit12:I Cache
    MRC p15, 0, r0, c1, c0, 0   @ Move to Register from Coprocessor(这个形式操作的是SCTLR寄存器)
    bic r0, r0, #(1<<12)        @ 关闭I Cache(bic:Bit Clear)
    bic r0, r0, #(1<<11)        @ 关闭分支预测
    bic r0, r0, #(1<<2)         @ 关闭D Cache
    bic r0, r0, #(1<<1)         @ 关闭对齐控制
    bic r0, r0, #(1<<0)         @ 关闭MMU
    MCR p15, 0, r0, c1, c0, 0   @ Move to Coprocessor from Register

#if 0
    @ 2.设置中断向量偏移
    @ 方式:修改VBAR寄存器
    @ (Vector Base Address Register,可以通过 CP15 协处理器访问)
    ldr r0, =0x87800000
    dsb
    isb
    MCR p15, 0, r0, c12, c0, 0  @ 设置VBAR寄存器为0x87800000
    dsb
    isb
#endif

.global _bss_start             @ 声明_bss_start符号为全局可见
_bss_start:                    @ 定义_bss_start标签
    .word _bss_start           @ 将_bss_start标签的地址存储为一个字(4字节)

.global _bss_end               @ 声明_bss_end符号为全局可见
_bss_end:                      @ 定义_bss_end标签
    .word _bss_end             @ 将_bss_end标签的地址存储为一个字(4字节)
    @ 3.清除bss段
    @ 方式:使用循环逐个清除
    ldr r0, _bss_start         @ 将_bss_start地址加载到r0寄存器
    ldr r1, _bss_end           @ 将_bss_end地址加载到r1寄存器
    mov r2, #0                 @ 将0存储到r2寄存器
bss_loop:
    stmia r0!, {r2}            @ 存储r2寄存器的值到r0指向的内存地址,并自增r0
    cmp r0, r1                 @ 比较r0和r1的值
    ble bss_loop               @ 如果r0小于等于r1,则跳转到bss_loop标签(继续循环)

    @ 4.设置处理器进入IRQ模式
    @ 方式:修改cpsr寄存器
    @ (Current Program Status Register,当前程序状态寄存器)
    @ 它包含了处理器状态和控制信息,例如 APSR、指令集状态、IT 块状态、字节序和当前处理器模式。 
    mrs r0, cpsr               @ 读取CPSR寄存器的值到r0寄存器
    bic r0, r0, #0x1f          @ 通过位清除操作,清除r0寄存器的低5位
    orr r0, r0, #0x12          @ 使用IRQ模式
    msr cpsr, r0               @ 将r0寄存器的值写回CPSR寄存器
    ldr sp, =0x80600000        @ 设置IRQ下的sp指针

    @ 5.设置处理器进入SYS模式
    @ 方式:修改cpsr寄存器
    @ (Current Program Status Register,当前程序状态寄存器)
    @ 它包含了处理器状态和控制信息,例如 APSR、指令集状态、IT 块状态、字节序和当前处理器模式。 
    mrs r0, cpsr               @ 读取CPSR寄存器的值到r0寄存器
    bic r0, r0, #0x1f          @ 通过位清除操作,清除r0寄存器的低5位
    orr r0, r0, #0x1f          @ 使用SYS模式
    msr cpsr, r0               @ 将r0寄存器的值写回CPSR寄存器
    ldr sp, =0x80400000        @ 设置SYS下的sp指针

    @ 6.设置处理器进入SVC模式
    @ 方式:修改cpsr寄存器
    @ (Current Program Status Register,当前程序状态寄存器)
    @ 它包含了处理器状态和控制信息,例如 APSR、指令集状态、IT 块状态、字节序和当前处理器模式。 
    mrs r0, cpsr               @ 读取CPSR寄存器的值到r0寄存器
    bic r0, r0, #0x1f          @ 通过位清除操作,清除r0寄存器的低5位
    orr r0, r0, #0x13          @ 使用SVC模式
    msr cpsr, r0               @ 将r0寄存器的值写回CPSR寄存器
    ldr sp, =0x80200000        @ 设置SVC下的sp指针

    @ 7.使能IRQ中断
    @ 方式:修改PSTATE处理器状态寄存器
    @ Change PE State (CPS) 用于修改处理器状态寄存器 (PSTATE) 中的某些位
    @ PSTATE 是一个特殊的寄存器,它包含了处理器当前的运行状态信息,包括:
    @ A (Application) 位: 控制应用程序模式下的中断是否允许。
    @ I (IRQ) 位: 控制 IRQ 中断是否允许。
    @ F (FIQ) 位: 控制 FIQ 中断是否允许。
    @ M (Mode) 位: 控制处理器当前运行的模式。
    cpsie i

    @ 8.跳转到main函数的入口
    b main                     @ 跳转到main函数的入口

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

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

相关文章

【开源项目】自然语言处理领域的明星项目推荐:Hugging Face Transformers

在当今人工智能与大数据飞速发展的时代&#xff0c;自然语言处理&#xff08;NLP&#xff09;已成为推动科技进步的重要力量。而在NLP领域&#xff0c;Hugging Face Transformers无疑是一个备受瞩目的开源项目。本文将从项目介绍、代码解释以及技术特点等角度&#xff0c;为您深…

泰迪智能科技大数据挖掘企业服务平台典型合作案例介绍

泰迪大数据挖掘企业服务平台 是一款通用的、企业级、智能化的数据分析模型构建与数据应用场景设计工具&#xff0c;能够一体化地完成数据集成、模型构建、模型发布&#xff0c;为数据分析、探索、服务流程提供支撑&#xff0c;提供完整的数据探索、多数据源接入、特征处理、模型…

编程设计思想

健康检查脚本 nmap:扫描端口 while true do healthycurl B:httpPORT/healthy -i | grep HTTP/1.1 | tail -n 1 | awk {print $2} done 批量操作类型脚本&#xff08;记录每一步日志&#xff09; 将100个nginx&#xff1a;vn推送到harbor仓库192.168.0.100 根据镜像对比sha值…

高效修复机床导轨磨损,保障加工精度!

机床导轨是支承和引导运动构件沿着一定轨迹运动的传动装置&#xff0c;在机器设备中是个十分重要的部件&#xff0c;在机床中是常见的部件。机床的加工精度与导轨精度有直接的联系&#xff0c;且导轨一旦损坏&#xff0c;维修较复杂且困难。我们简单总结了以下几点对于机床导轨…

rocketMQ消息中间件,onMessage报错,MessageExt of onessage method is not supported

本地启动不会报错&#xff0c;生产者和消费者都运行的好好的&#xff0c;但是打包之后就不断的报错误&#xff0c; 起初以为是maven出现了问题&#xff0c;但是刷新和重写都不管用&#xff0c;并且打的jar包解压后发现类里 有这个类和方法。最后认为是打包出现问题 解决方式&am…

SEO之竞争对手研究

初创企业搭建网站的朋友看1号文章&#xff1b;想学习云计算&#xff0c;怎么入门看2号文章谢谢支持&#xff1a; 1、我给不会敲代码又想搭建网站的人建议 2、新手上云 竞争对手研究是市场竞争研究的重要部分&#xff0c;对判断特定关键词竞争程度及了解行业整体情况非常有价值。…

AutoStudio: 开源 AI 漫画创作神器

AutoStudio是一个用于生成系列连续且一致的图片系统&#xff0c;可用于漫画创作&#xff0c;其核心由四个 Agent 组成&#xff1a; 主题管理器&#xff1a;理解用户对话&#xff0c;跟踪角色信息。 布局生成器&#xff1a;确定图像中角色的位置。 监督者&#xff1a;给出改进…

昇思25天学习打卡营第3天|张量Tensor

张量Tensor 概念创建张量&#xff08;4种方式&#xff09;张量的属性张量索引张量运算Tensor与NumPy转换 概念 张量&#xff08;Tensor&#xff09;是一种特殊的数据结构&#xff0c;与数组和矩阵非常相似。张量是MindSpore网络运算中的基本数据结构。 创建张量&#xff08;4…

离线安装docker-v26.1.4,compose-v2.27.0

目录 ​编辑 1.我给大家准备好了提取即可 2.安装docker和compose 3.解压 4.切换目录 5.执行脚本 6.卸载docker和compose 7.执行命令 “如果您在解决类似问题时也遇到了困难&#xff0c;希望我的经验分享对您有所帮助。如果您有任何疑问或者想分享您的经历&#xff0c;…

【Academy】测试WebSockets安全漏洞Testing for WebSockets security vulnerabilities

测试WebSockets安全漏洞Testing for WebSockets security vulnerabilities 概述WebSockets是什么?HTTP和WebSockets有什么区别&#xff1f;如何建立WebSocket连接&#xff1f;WebSocket消息看起来像什么&#xff1f; 操纵WebSocket流量拦截和修改WebSocket消息重放和生成新的W…

揭示优化Prompt的秘诀:如何让API表现媲美网页版

为什么用GPT API&#xff08;GPT-3.5-turbo&#xff09;进行程序分析时&#xff0c;效果好像比网页版的GPT-3.5差一点&#xff1f;这可能有几个原因&#xff0c;咱们细说一下。 1. Prompt不同 这是最常见的问题之一。API调用时的指令&#xff08;prompt&#xff09;往往比较简…

【C#】找不到属性集方法。get只读属性用了反射设置setValue肯定报错

欢迎来到《小5讲堂》 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 背景 找不到属性集方法。get只读属性用了反射设置setValue肯定报错 报错…

Spring Boot 接口一个 JSON 字符串用两个对象去接收,这能行吗?

文章目录 需求场景解决方案Step 1: 创建 Person 和 Address 类Step 2: 创建 PersonWithAddress 类Step 3: 自定义转换器Step 4: 配置转换器Step 5: 使用 RequestBody 接收 JSON 数据 结论 &#x1f389;欢迎来到SpringBoot框架学习专栏~ ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#…

若依项目实战------企业人力资源管理平台

一、数据库名称规范化及建表相关 1.术语名称 1.系统名称&#xff1a;企业人力资源管理平台英文翻译&#xff1a;Enterprise Human Resource Management Platform缩写&#xff1a;EHR 2.员工信息管理&#xff08;Employee Information Management 缩写&#xff1a;EIM&#…

Vue3抽屉(Drawer)

效果如下图&#xff1a;在线预览 APIs 参数说明类型默认值必传width宽度&#xff0c;在 placement 为 right 或 left 时使用string | number378falseheight高度&#xff0c;在 placement 为 top 或 bottom 时使用string | number378falsetitle标题string | slotundefinedfalse…

Docker(八)-Docker运行mysql8容器实例

1.运行mysql8容器实例并挂载数据卷 -e:配置环境变量 --lower_case_table_names1 设置忽略表名大小写一定要放在镜像之后运行mysql8容器实例之前&#xff0c;先查看是否存在mysql8镜像以及是否存在已运行的mysql实例docker run -d -p 3306:3306 --privilegedtrue -v 【宿主机日…

Jenkins流水线发布,一篇就解决你的所有疑惑

这次搭建的项目比较常规,前端是react写的,后端是springboot,并且由于是全栈开发,所以是在同一个项目中。接下来我演示下怎么用jenkins进行自动化发布。 1.jenkins必装插件 这里用到的是jenkinsFile主要是基于Groovy这个沙盒,有些前置插件。这里使用maven进行打包,所以需…

公益培训|半导体与集成电路项目制培训项目

关于我们 硬蛋产业学院&#xff0c;基于硬蛋创新(http://00400.HK)在芯片产业的资源和技术优势&#xff0c;引进全球领先的芯片应用技术&#xff0c;为国内培养芯片应用技术人才&#xff0c;助力芯片应用产业发展。 硬蛋产业学院在国家各主管部门、广东省、深圳市及社会各界的大…

一码多址与同义词解决方案

随着地址库中的数据不断的丰富&#xff0c;地址库中一码多址和同义词的数据也会越来越多&#xff0c;一码多址和同义词在统一地址管理平台中的概念并不相同。 一码多址指的是多个地址编码相同&#xff0c;例如通过民政地址找到编码&#xff0c;再通过编码找到房产地址描述。 本…

使用Python和jieba库生成中文词云

使用Python和jieba库生成中文词云 在文本分析和数据可视化的领域中&#xff0c;词云是一种展示文本数据中关键词频率的直观方式。Python作为一种强大的编程语言&#xff0c;提供了多种库来帮助我们生成词云&#xff0c;如wordcloud和jieba。在本文中&#xff0c;我们将通过一个…