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

硬件驱动——I.MX6ULL裸机启动(3)(按键设置及中断设置

重点:

1.GIC:(Generic  Interrupt  Controller)通用中断控制器,是ARM架构中用于管理中断的核心模块,主要用于现代多核处理器系统。它负责接收,分发并分发中断请求,减轻CPU负担,使其专注于计算任务。目前GIC有四个版本,V1~V4,现在只有V2~V4正在大量使用,IMX6ULL搭载的是V2的GIC控制器。

2.协处理器是一种专门用于辅助CPU执行特定任务的硬件模块,通过分担CPU的运算负荷来提升系统整体效率

AMR Cortex  A7内核配备了16个协处理器

3.将异常向量表重映射的原因:默认情况下,异常向量表在低地址(0x00000000),但系统运行时,可能需要把异常向量表放到其他的地址(比如更高的内存地址,放在操作系统或应用程序灵活管理内存空间),这样能更合理的利用内存,也便于对异常处理程序进行组织和管理。

重映射异常向量表的方法:通过协处理器(CP15)中的相关寄存器(比如向量基地址寄存器),将异常向量表的基地址修改为目标地址,是的处理器在处理异常时,能到新的地址去获得异常处理程序的入口

一.实现按键功能

相关代码:

#include "key.h"
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"
#include "core_ca7.h"void init_key(void)
{IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);   //设置IO复用功能IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF0B0);   //配置该引脚的电气属性struct GPIO_Type_t t ={.direction = gpio_input     };init_gpio(GPIO1,18,&t);        //按键为输出方式
}
int key_pressed(void)
{if(read_gpio(GPIO1,18) == 0)    //判断该引脚是高电平还是低电平,低电平为按下按键返回0,高电平为没按按键返回1{return 1;}else{return 0;}}
#ifndef __KEY_H__
#define __KEY_H__
#include "gpio.h"
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"extern void init_key(void);extern int key_pressed(void);
#endif
int main(void)
{enable_clocks();system_interrupt_init();init_beep();init_led();init_key();while(1){delay(0xFFFFF);}return 0;
}

汇编代码与上一节一样

二.中断

1.中断步骤:

        1)中断源发出中断请求;

        2)内核检查是否响应相应中断以及判断该中断是否屏蔽;

        3)内核检查中断的优先级;

        4)保护现场

        5)执行中断服务函数;

        6)恢复现场

2.GIC中断控制器

GIC:(Generic  Interrupt  Controller)通用中断控制器,是ARM架构中用于管理中断的核心模块,主要用于现代多核处理器系统。它负责接收,分发并分发中断请求,减轻CPU负担,使其专注于计算任务。目前GIC有四个版本,V1~V4,现在只有V2~V4正在大量使用,IMX6ULL搭载的是V2的GIC控制器。

GIC能处理1200个中断,分为三大类:

1.SPI:共享外设中断        32~1019

2.PPI:私有外设中断,内核与内核之间的通信中断        16~31号

3.SGI:软件产生中断        0~15号

IMX6ULL中有160个中断

IAR:中断通知寄存器        将中断编号传给内核

EOIR:中断结束寄存器        清除中断

3.协处理器(Techinal手册)

ARM内核支持16个协处理器,CP0~CP15,

SCTLR:映射异常向量表

VBVR:异常向量的基地址

mrc:用来读的目标寄存器(CP15)的值放到通用寄存器当中去

mcr:用来将通用寄存器里的值写到(CP15)目标寄存器当中去

MRC{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>
cond:指令执行的条件码,就是之前我们使用过的指令条件,eq,lt什么的。如果忽略的话就表
示无条件执行;

p15:表示要读取的是CP15当中的某个寄存器;

opc1:协处理器要执行的操作码1,其实就是一个数,要做什么将来查表;

Rt:ARM 目标寄存器,读出来的数据放到哪个ARM寄存器里。CP15

CRn:CP15 协处理器的目标寄存器,就是你要读取CP15的哪个寄存器(C0~C15);

CRm:协处理器中附加的目标寄存器或者源操作数寄存器,如果不需要附加信息就将CRm 设置
为 C0,否则结果不可预测。 

opc2:可选的协处理器特定操作码2,使用时查表。

4.实现的代码

#include "key.h"
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"
#include "core_ca7.h"
#include "interrupt.h"
#include "led.h"
void init_key(void)
{IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);   //设置IO复用功能IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF0B0);   //配置该引脚的电气属性struct GPIO_Type_t t ={.direction = gpio_input     };init_gpio(GPIO1,18,&t);        //按键为输出方式GPIO1->ICR2 |= (3 << 4);       //将GPIO1当中的18号引脚设置为下降沿触发方式  ICR为中断方式的寄存器GPIO1->IMR |= (1 << 18);       //将GPIO1当中的18号引脚置1,打开18号引脚的中断屏蔽寄存器     IMR为中断屏蔽寄存器system_interrupt_register(GPIO1_Combined_16_31_IRQn,key_interrupt_handler);GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);       //打开指定的中断,该位置打开编号为99的中断GIC_SetPriority(GPIO1_Combined_16_31_IRQn,0);   //设置中断优先级为0,即优先级最高
}void key_interrupt_handler(void)
{if((GPIO1->ISR &(1 << 18)) != 0)    //判断中断标记寄存器中产生中断是由GPIO1的18号引脚造成的{led_nor();GPIO1->ISR |= (1 << 18);        //清除中断标记寄存器}
}
int key_pressed(void)
{if(read_gpio(GPIO1,18) == 0)    //判断该引脚是高电平还是低电平,低电平为按下按键返回0,高电平为没按按键返回1{return 1;}else{return 0;}}
#include "interrupt.h"
#include "MCIMX6Y2.h"
#include "core_ca7.h"static irq_handler_t interrupt_vector_table[160];  //定义一个函数的指针的数组,用来存放中断void system_interrupt_init(void)
{GIC_Init();     //对GIC控制器进行初始化操作
}void system_interrupt_register(int num, irq_handler_t handler)  //注册中断服务函数
{interrupt_vector_table[num] = handler;      
}void system_interrupt_handler(int num)      //中断服务函数,num为哪一个中断发出的中断请求,传递其中断号
{if(interrupt_vector_table[num] != NULL)    //什么原因造成的中断,该处为中断编号为99的中断{interrupt_vector_table[num]();      //调用这个函数的指针数组}}
.global _start_start:ldr pc, =_reset_handlerldr pc, =_undefine_handlerldr pc, =_svc_handlerldr pc, =_prefetch_abort_handlerldr pc, =_data_abort_handlerldr pc, =_reserved_handlerldr pc, =_irq_handlerldr pc, =_fiq_handler_undefine_handler:ldr pc, =_undefine_handler_svc_handler:ldr pc, =_svc_handler_prefetch_abort_handler:ldr pc, =_prefetch_abort_handler_data_abort_handler:ldr pc, =_data_abort_handler_reserved_handler:ldr pc, =_reserved_handler
//在main函数当中初始化irq中断函数
_irq_handler:subs lr, lr, #4         //通过查表,将链接寄存器的值减4(异常状态返回地址)mrc p15, 4, r1, c15, c0, 0      //将GIC的基地址放到r1当中去add r1, r1, #0x2000         //得到的是C_CTLR的基地址ldr r0, [r1, #0x0C]         //将r1当中的基地址偏移0x0C的地址(C-IAR(发出中断请求的寄存器))存(读)到r0寄存器当中stmfd sp!, {r0-r12, lr}     //保护现场stmfd sp!, {r0, r1}         //将r0和r1入栈cps #0x1F                   //切换为system模式stmfd sp!, {lr}             //保护system模式下的lrbl system_interrupt_handler //调用C语言函数ldmfd sp!, {lr}             //恢复system模式下的lrcps #0x12                   //切换为irq模式ldmfd sp!, {r0, r1}         //将第38行的r0和r1出栈str r0, [r1, #0x10]         //将r0当中的值写到r1偏移0x10的地址上去(C_EOIR(清除中断标志的寄存器))ldmfd sp!, {r0-r12, pc}^    //恢复现场并且改变模式
_fiq_handler:ldr pc, =_fiq_handler_reset_handler:
/*     mrs r0,cpsrbic r0, r0, #0x1Forr r0, r0, #0x12   //irp(10010)bic r0, r0, #(1 << 7)       //打开irq中断msr cpsr, r0ldr sp, =0x86000000mrs r0,cpsrbic r0, r0, #0x1Forr r0, r0, #0x1F   //system(11111)msr cpsr, r0ldr sp, =0x84000000
*/cps #0x12           //irq(10010)模式ldr sp, =0x86000000 cps #0x1F           //system(11111)模式cpsie ildr sp, =0x84000000//先通过CP15写处理器打开设置基地址的选项,再通过映射异常向量表bl _enable_icahce       bl _set_vbar bl _bss_clear b main  //跳转至main函数当中//处理CP15协处理器(SCTLR)
_enable_icahce:         mrc p15, 0, r0, c1, c0, 0       //读目标寄存器的值放到通用寄存器r0上bic r0, r0, #(1 << 13)          //根据查表,将SCTLR的第13位清0,此位用来选择异常向量的基地址,目的是软件可以通过VBAR来重新设置这个基地址orr r0, r0, #(1 << 12)          //根据查表,将SCTLR的第12位置1,此位用来将指令cache进来打开,默认是关闭状态mcr p15, 0, r0, c1, c0, 0       //将修改后的目标寄存器的值重新写入目标寄存器bx lr
//设置异常向量表基地址(VBAR)
_set_vbar:ldr r0, =0x87800000              //将异常向量表的基地址存入到r0当中mcr p15, 0, r0, c12, c0, 0       //根据查表,将r0当中的基地址通过cp15协处理器写入CBAR当中,当作GIC的基地址bx lr_bss_clear:ldr r0, =__bss_startldr r2, =__bss_end
loop:mov r1, #0str r1, [r0]add r0, r0, #4cmp r0, r2blt loopbx lrfinished:b finished
#include "beep.h"
#include "led.h"
#include "key.h"
#include "core_ca7.h"
#include "interrupt.h"void enable_clocks(void)    //将所有时钟都打开
{CCM->CCGR0 = 0xFFFFFFFF;CCM->CCGR1 = 0xFFFFFFFF;CCM->CCGR2 = 0xFFFFFFFF;CCM->CCGR3 = 0xFFFFFFFF;CCM->CCGR4 = 0xFFFFFFFF;CCM->CCGR5 = 0xFFFFFFFF;CCM->CCGR6 = 0xFFFFFFFF;
}void delay(unsigned int n)
{while(n--);             //进行延时}int main(void)
{enable_clocks();system_interrupt_init();init_beep();init_led();init_key();while(1){delay(0xFFFFF);}return 0;
}


文章转载自:

http://kSxHq2Fo.ksggL.cn
http://dPvqZnd8.ksggL.cn
http://2CJn8H0v.ksggL.cn
http://oXwMxl46.ksggL.cn
http://aVINrh4W.ksggL.cn
http://AhuTScUQ.ksggL.cn
http://RJi00iLG.ksggL.cn
http://Ch436pD8.ksggL.cn
http://q419467b.ksggL.cn
http://ZcGOBZGm.ksggL.cn
http://1UFu4xbG.ksggL.cn
http://PtFRoUbQ.ksggL.cn
http://RIAUc1bl.ksggL.cn
http://PWstlFCg.ksggL.cn
http://e4BpLAAY.ksggL.cn
http://a8EvQPCL.ksggL.cn
http://BCE7wItP.ksggL.cn
http://Z7Q6BNVP.ksggL.cn
http://xVnoycMR.ksggL.cn
http://ncO7eu3y.ksggL.cn
http://z2UevMK6.ksggL.cn
http://e1EGHgDD.ksggL.cn
http://IaH6l06b.ksggL.cn
http://YJcq7k1S.ksggL.cn
http://OeDWReUo.ksggL.cn
http://xplMxDQh.ksggL.cn
http://rsRinoA4.ksggL.cn
http://QSIijXrL.ksggL.cn
http://arImQcGJ.ksggL.cn
http://00Ef2ngU.ksggL.cn
http://www.dtcms.com/a/387113.html

相关文章:

  • 深度学习基本模块:RNN 循环神经网络
  • 【深度学习】PixelShuffle处理操作
  • 10.1 - 遗传算法(旅行商问题C#求解)
  • Java 集合入门:从基础到实战的完整知识指南
  • 《过山车大亨3 完整版》PSXbox版下月推出 预告片赏
  • P1107题解
  • 多目标数据关联算法MATLAB实现
  • 战略推理AI Agents:组装LLM+因果推断+SHAP
  • 【CVPR 2016】基于高效亚像素卷积神经网络的实时单幅图像与视频超分辨率
  • 基于STM32的LED实战 -- 流水灯、呼吸灯、流水呼吸灯
  • 【数据结构】——队列,栈(基于链表或数组实现)
  • 任天堂官网更新!“任亏券”不支持兑换NS2专用游戏
  • 大模型数据整理器打包及填充、Flash Attention 2解析(97)
  • 48v转12v芯片48v转5v电源芯片AH7691D
  • Oracle Database 23ai 内置 SQL 防火墙启用
  • MySQL 31 误删数据怎么办?
  • 微前端面试题及详细答案 88道(09-18)-- 核心原理与实现方式
  • VBA技术资料MF362:将窗体控件添加到字典
  • 【Leetcode】高频SQL基础题--1321.餐馆营业额变化增长
  • Redis 中 Intset 的内存结构与存储机制详解
  • uniapp打包前端项目
  • cka解题思路1.32-3
  • 如何解决模型的过拟合问题?
  • 2025牛客周赛108场e题
  • 【课堂笔记】复变函数-2
  • 25、优化算法与正则化技术:深度学习的调优艺术
  • qt QCategoryAxis详解
  • 云游戏时代,游戏盾如何保障新型业务的流畅体验
  • 【Block总结】LRSA,用于语义分割的低分辨率自注意力|TPAMI 2025
  • PY32MD310单片机介绍 电机控制专用,内置三相半桥栅极驱动器