s5p6818裸机-irq中断

2023-05-16

前言

本次学习的目的是通过按按键触发按键中断,调用相关的中断服务函数,实现蜂鸣器鸣响。通过裸机学习能使自己对SoC的运行环境,开发环境有更好的了解。

软件实现流程

1)在start.S启动汇编中实现中断向量表,及irq处理函数
2)实现irq中断结构体数组,irq通用中断服务函数注册函数(中断号和中断服务函数的联系)
3)实现gic中断控制器初始化函数
4)实现gpio初始化函数,复用-中断配置

流程具体

1、异常向量表和IRQ_Handler一般都在start.S里面编写,因为需要做一些中断触发时保护现场和恢复现场的工作。

_start:
    /*DDR范围:0x40000000~0x80000000 1GB*/

    /*异常向量表 */
    ldr pc, =Reset_Handler      /* 复位中断 					*/	
    ldr pc, =Undefined_Handelr  /* 未定义中断 					*/
    ldr pc, =SVC_Handelr        /* SVC(Supervisor)中断 		*/
    ldr pc, =PrefAbort_Handler  /* 预取终止中断 					*/
    ldr pc, =DataAbort_Handler  /* 数据终止中断 					*/
    ldr pc, =NotUsed_Handler    /* 未使用中断					*/
    ldr pc, =IRQ_Handler        /* IRQ中断 					*/
    ldr pc, =FIQ_Handler        /* FIQ(快速中断)未定义中断 			*/
IRQ_Handler:
    ldr sp,=0x7FC00000 /*设置irq模式的sp指针 */
    /*保护现场 */
    push {lr}
    push {r0-r3,r12}   
    mrs r0, spsr   /*访问SPSR寄存器,保存cpsr */
    push {r0}
/****************************************************** */

    mrc p15,1,r1,c15,c3,0 /*读取GIC的CPU接口端基地址 GICC_CTLR*/
    ldr r0, [r1,#0xC]   /*基地址偏移0xC,访问GICC_IAR寄存器 */
                        /*GICC_IAR能够获取到中断ID号 */
    push {r0,r1}
    cps #0x3           /*进入svc模式 */
    push {lr}       /*保存svc的lr寄存器 */

    //ldr r2, =system_irqhandler 
    blx system_irqhandler            /*跳转到c程序的中断处理函数中,带上一个参数r0(中断ID)*/

    pop {lr}   /*lr出栈 */
    cps #0x2   /*进入irq模式 */
    pop {r0,r1}
    str r0, [r1,#0x10]  /*中断执行完成,把中断ID写入EOIR寄存器 */

    /*恢复现场 */
    pop {r0}
    msr spsr, r0  /*恢复cpsr */
    pop {r0-r3,r12}
    pop {lr}
/********************************** */
    subs pc, lr, #4 /*返回触发中断时,下一条指令的位置 */

其中恢复现场的subs pc, lr, #4 是因为cpu是三级流水线工作的,取址,译址,执行。比如当前第一条指令是执行,第二条指令是译址,第三条指令是取址,那么当中断触发时,pc所指向的是取址,而恢复现场则需要从第二条指令那里开始恢复即pc-4的位置。

2、实现irq中断结构体数组,(中断号和中断服务函数的联系)

/*中断服务函数的形式*/
typedef void (*system_irq_handler_t)(unsigned int giccIar,void *param);

/*中断服务函数结构体*/
typedef struct _sys_irq_handle
{
    system_irq_handler_t irqhandler;    /*中断服务函数*/
    void *userParam;                    /*中断服务函数参数*/
}sys_irq_handle_t;

static sys_irq_handle_t irqTable[160]; /*数组大小为160,每一个元素的下标对应一个中断ID*/

有了这个结构体数组,就实现了中断号和中断服务函数的联系了,下一步就是把中断服务函数往里面注册就可以了。

3、irq通用中断服务函数注册函数

/*给指定的中断号注册中断服务函数 */
void system_register_irqhandler(IRQn_Type irq, system_irq_handler_t handler, void *userParam)
{
    irqTable[irq].irqhandler = handler;
    irqTable[irq].userParam = userParam;
}

这个就是往结构体里面注册中断服务函数了,自己编写好最终的中断服务函数,作为参数handler往里面存。

4、上面start.S的IRQ_Handler会跳进这个函数,根据中断ID执行最终的中断服务函数

/*具体的中断服务函数*/
void system_irqhandler(unsigned int giccIar)
{
    unsigned int intNum = giccIar & 0x3FF;  /*GICC_IAR的bit[9:0]为中断ID*/
    if(intNum < NUMBER_OF_INT_VECTORS)
    {
        irqNesting++;
        irqTable[intNum].irqhandler(intNum, irqTable[intNum].userParam);
        irqNesting--;
    }
    else
        return;
}

5、gic的初始化
参考数据手册,得到需要用到的寄存器GICD_TYPER、GICD_ISCENABLERn、GICC_PMR、GICC_BPR、GICD_CTRL、GICC_CTRL、GICD_ISENABLERn、GICD_IPRIORITYRn,寄存器的具体作用我在下面代码里面也作了注释,或者去查看手册。

/*GIC初始化*/
void GIC_init(void)
{
    unsigned int i;
    unsigned int irqRegs;

    /*读取bit[0:4]为N,支持的中断ID最大值:(32(N+1)-1=159)*/
    irqRegs = (GIC->D_TYPER & 0x1F) + 1; 

    /*关闭所有SGI,PPI,SPI中断*/
    for(i=0; i<irqRegs; i++) 
        GIC->D_ISCENABLERn[i] |= 0xFFFFFFFF; 

    /*设置支持32个优先级,即bit[7:0]=11111000*/
    GIC->C_PMR |= (0xFF << 3);  
    //GIC->C_PMR |= 0xFF;

    /*设置5级抢占优先级bit[2:0]=2,即所有中断优先级位都为抢占优先级*/
    GIC->C_BPR |= (2<<0);

    /*使能组0的中断分发控制*/
    GIC->D_CTRL |= (0x1<<0);

    /*使能组0的中断发送到CPU Core的中断请求信号*/
    GIC->C_CTRL |= (0x1<<0);
}

/*使能指定中断,并设置优先级*/
void GIC_EnableIRQ(IRQn_Type IRQn, unsigned int pri)
{
    /*IRQn/32: 取到0~4寄存器里对应的寄存器*/
    /*IRQn%32: 取到对应寄存器里相应的bit*/
    GIC->D_ISENABLERn[IRQn/32] |= (1<<(IRQn%32));
    GIC->D_IPRIORITYRn[IRQn/4] &= ~(0xFF<<((IRQn%4)*8));
    GIC->D_IPRIORITYRn[IRQn/4] |= (pri<<((IRQn%4)*8));      /*设置指定中断的优先级*/
    //GIC->D_ITARGETSRn[21] &= (~(0xFF<<16));
    //GIC->D_ITARGETSRn[21] |= (0x1<<16);    /*设置指定中断的CPU接口*/
}

6、gpio的中断设置
通过查看数据手册得到需要使用的寄存器有GPIOXINTENB、GPIOXDETENB、GPIOXDETMODE0、GPIOXDETMODE1、GPIOXDETMODEEX、GPIOXDET,具体功能也是在下面代码的注释里面有说明

/*使能GPIO口的中断功能*/
void gpio_intEnable(GPIO_Type *base, int pin)
{
    base->GPIO_INTENB |= (1<<pin);  /*中断使能*/
    base->GPIO_DETENB |= (1<<pin);  /*检测使能*/
}

/*设置gpio的中断配置功能*/
/*GPIOXDETMODE0或者GPIOXDETMODE1需要跟GPIOXDETMODEEX配合一起使用,
因为配置中断检测方式即高/低电平触发,上升/下降沿触发等需要用到3bit数来配置,
其中高1bit由GPIOXDETMODEEX提供,低2bit由GPIOXDETMODE0或者GPIOXDETMODE1提供*/

void gpio_intconfig(GPIO_Type *base, int pin, GPIO_Interrupt_Mode_t intmode)
{
    volatile unsigned int *DetMode;
    unsigned int pin_t;

    pin_t = pin;

    if (pin<16)
    {
        DetMode = &(base->GPIO_DETMODE0); /*0~15引脚*/
    }
    else
    {
        DetMode = &(base->GPIO_DETMODE1); /*16-31引脚*/
        pin_t -= 16;
    }
    switch(intmode)
    {
        case GPIO_IntLowLevel:
            base->GPIO_DETMODEEX &= ~(1<<pin);    /*000的高(1-bit)*/
            *DetMode &= ~(3<<(2 * pin_t));        /*000的低(2-bit)*/
            break;
        case GPIO_IntHighLevel:
            base->GPIO_DETMODEEX &= ~(1<<pin);                                      /*001的高(1-bit)*/
            *DetMode = (*DetMode & (~(3<<(2 * pin_t)))) | (1<<(2 * pin_t));         /*001的低(2-bit)*/             
            break;
         case GPIO_IntFallingEdge:
            base->GPIO_DETMODEEX &= ~(1<<pin);                                      /*010的高(1-bit)*/
            *DetMode = (*DetMode & (~(3<<(2 * pin_t)))) | (2<<(2 * pin_t));         /*010的低(2-bit)*/       
            break;
        case GPIO_IntRisingEdge:
            base->GPIO_DETMODEEX &= ~(1<<pin);                                      /*011的高(1-bit)*/
            *DetMode = (*DetMode & (~(3<<(2 * pin_t)))) | (3<<(2 * pin_t));         /*011的低(2-bit)*/
            break;
         case GPIO_IntFallingorRisingEdge:
            base->GPIO_DETMODEEX |= (1<<pin);   /*100的高(1-bit)*/
            *DetMode &= ~(3<<2 * pin_t);        /*100的低(2-bit)*/
            break;   
        default:
			break;

    }
}

/*清除中断标注位*/
void gpio_clearintflags(GPIO_Type *base, int pin)
{
    base->GPIO_DET |= (1<<pin);	/*往里面写1即可清除标志位*/
}

小结

总体来说整个中断的执行顺序大概是:按下按键 -> 触发irq中断信号 -> gic控制器 -> CPU -> 异常向量表 -> IRQ异常处理 -> 执行最终的中断服务程序

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

s5p6818裸机-irq中断 的相关文章

随机推荐

  • Autoware1.14运行官网Demo 适配镭神激光雷达

    项目场景 xff1a Autoware1 14 运行官网demo 适配镭神16线激光雷达 运行官网Demo 1 创建 autoware文件夹 xff0c 下载官网数据包 xff0c 并解压 span class token function
  • 磁盘问题--系统盘出现只读现象( read-only file system)

    一 说明现象原因 1 问题现象 xff0c 创建文件或者创建目录都只读 touch cannot touch file test read only file system 2 问题说明 当文件系统自身的校验机制发现文件系统存在问题时 xf
  • 第十一周作业-必做3

    题目描述 xff1a Julius Caesar 曾经使用过一种很简单的密码 对于明文中的每个字符 xff0c 将它用它字母表中后 55 位对应的字符来代替 xff0c 这样就得到了密文 比如字符 A 用 F 来代替 如下是密文和明文中字符
  • 实现用python简易演奏《数鸭子》

    前几天上课老师给我们讲了两个模块 xff0c 然后利用这两个模块来模拟钢琴键盘去简单地演奏 数鸭子 今天来分享给大家 模块1 xff1a winsound 模块2 xff1a keyboard winsound xff1a winsound
  • 控制台报错整理

    一 无法将 npm 项识别为 cmdlet 函数 脚本文件或可运行程序的名称 请检查名称的拼写 xff0c 如果包括路径 xff0c 请确保路径正确 xff0c 然后再试一次 情景 在第一次初启项目时 xff0c 安装好node xff0c
  • git常用命令

    安装git 在git的官网下载需要的版本 安装完成后需要设置用户的用户名和邮箱 git config global user name 34 Your Name 34 例如 xff1a config global user name 34
  • 表格td实现可编辑

    html xff08 elementUi中的表格 xff0c 传入位置和当前值 xff09 methods xff08 生成input xff0c 将当前输入的value值等于当前单元格的值 xff09 handleChangeCorrec
  • vue开发实例

    1 利用三元表达式实现对元素样式动态赋值 2 vue中 实现点击下载图片
  • Elementui 踩过的坑

    select下拉框 这个是Elementui 官网 Select选择器的基础用法 xff0c 现在想要更改它本身自带的默认样式 lt template gt lt el select v model 61 34 value 34 place
  • WSL2图形化界面踩坑记录

    问题 xff1a 启动xfce4时 xff0c 报错 xff1a xfsm manager load session Something wrong with home shenshiyi cache sessions xfce4 sess
  • CSP M1-A 咕咕东的奇遇

    题意 xff1a 字母a z首尾相接成环 xff0c 开始时指针指向a xff0c 圆环可以顺时针或者逆时针旋转 xff0c 给定一个字符串 xff0c 计算旋转依次得到该字符串的每一个字符最少需要转多少格 Input 一个字符串 长度 l
  • pycharm的python库在哪?pip下载的文件放在哪?一个方法,都能找到

    1 打开cmd命令行 2 标题输入pip install xxx库 xff08 1 xff09 如果没下载过 xff0c 那么将正常下载 xff08 2 xff09 若下载过了 xff0c 就会显示你下载的目录 这个目录 c users x
  • 数据库面试知识点

    1 事务及其四个特性 事务是用户定义的一个操作序列 xff0c 这些操作要么全做要么全不做 xff0c 是一个不可分割的工作单位 事务四个特性 xff1a 原子性 一致性 隔离性和持续性 原子性 xff1a 事物中包括的操作要么都做 xff
  • 第六次模拟测试-6

    题目描述 xff1a 石头剪刀布是常见的猜拳游戏 石头胜剪刀 xff0c 剪刀胜布 xff0c 布胜石头 如果两个人出拳一样 xff0c 则不分胜负 一天 xff0c 小A和小B正好在玩石头剪刀布 已知他们的出拳都是有周期性规律的 xff0
  • kali linux教程:配置 Kali 的 apt 命令在线安装包的源为阿里云

    配置 apt 国内源 因为 Kali 自带的源是国外的 xff0c 经常会因为网络问题 xff0c 而无法安装戒更新软件包 而且国外的源速度很慢 所以我们直接使用国内的源 xff0c 方便快速 点击终端按钮戒者右键桌面选择 open in
  • 相关分析和回归分析

    1 相关分析 相关分析是研究两个或两个以上处于同等地位的随机变量间的相关关系的统计分析方法 例如 xff0c 人的身高和体重之间 xff1b 空气中的相对湿度与降雨量之间的相关关系都是相关分析研究的问题 2 回归分析 相关分析与回归分析之间
  • Linux(Debian)下快速安装JDK

    Linux下快速安装JDK 一 前言 linux系统的debain发行版本 博主使用电脑mac 二 Linux系统下载jdk 1 下载JDK上传到linux系统 1 下载jdk版本到自己电脑上 JDK下载地址 下载JDK的Oracle账号
  • LINK1104 无法打开文件“libboost_atomic-vc142-mt-gd-x64-1_76.lib”

    问题描述 LNK1104 无法打开文件 libboost atomic vc142 mt gd x64 1 76 lib 可能原因 xff1a 相应的包没有安装 xff0c 可以再电脑上搜一下 xff0c 是否搜索到 xff0c 如果搜索到
  • Could not get JDBC Connection; nested exception is java.sql.SQLNonTransientConnectionException异常处理

    org springframework jdbc CannotGetJdbcConnectionException Could not get JDBC Connection nested exception is java sql SQL
  • s5p6818裸机-irq中断

    前言 本次学习的目的是通过按按键触发按键中断 xff0c 调用相关的中断服务函数 xff0c 实现蜂鸣器鸣响 通过裸机学习能使自己对SoC的运行环境 xff0c 开发环境有更好的了解 软件实现流程 1 xff09 在start S启动汇编中