OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4219|回复: 1

<新手向>第二期 裸机开发 P29-P32 第15.1-15.3讲 复位中断函数编写 随堂笔记

[复制链接]

5

主题

17

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
254
金钱
254
注册时间
2020-3-22
在线时间
35 小时
发表于 2020-4-1 16:12:10 | 显示全部楼层 |阅读模式
本帖最后由 YOKI 于 2020-4-1 16:20 编辑

/********************************************/
时间        :2020/03/31/
作者        :YOKI
导师        :正点原子 左忠凯
硬件        :正点原子 ALPHA I.MX LINUX 开发板
/*******************************************/
本讲 15.1-15.5 编写一个通过按键 KEY0 使用 UART_CTS 的 的中断代码
通过这个历程来学习 IMX6ULL 的中断系统。

重要知识点:
ARM Cortex-A7 构架 提供了 16个 32位 通用寄存器( R0-R15)和2个 程序状态寄存器
各寄存器的含义:
R0-R12      通用寄存器
R13         SP   SP指针
R14         LR   连接寄存器 (IRQ模式下)    存放 子函数的返回地址
R15         PC       程序计数器               将 LR 的值 传递给 PC 可实现程序跳转
CPSR        当前程序状态寄存器
SPSR        备份程序状态寄存器        

1、复位中断函数
复位中断函数是系统在上电 及复位后执行的第一个函数,包含了对系统进行初始化(系统的运行模式设置,中断向量表设置,中断偏移等)。
这些工作到要在 start.s 中进行。
2、中断服务的编写:
学习过 51 或者 STM32 的人 都知道 中断函数 是在 当前程序运行过程中,由中断事件(Event)触发后进入一段临时运行的程序,
这段程序执行完成后要回到中断发生前的程序运行状态继续执行原来的程序。这就要求,从当前程序进入到中断服务函数后首先要进行
的一件事是 保护现场 :保存当前程序运行的状态或数据 即保存CPU中相关寄存器的数据
本讲 15.1-15.5 编写一个通过按键 KEY0 使用 UART_CTS 的 的中断代码

1.1 中断向量表设置
_start:
/*****************************************/
/*中断向量表
/****************************************/
    ldr pc, =Reset_Handler                  @ 复位中断服务函数
    ldr pc, =Undefined_Handler            @ 未定义指令中断服务函数
    ldr pc, =SVC_Handler                     @ SVC 特权模式
    ldr pc, =Pre_Abort_Hanlder            @ 指令预取中止
    ldr pc, =Data_Abort_Handler          @ 数据中止
    ldr pc, =NotUsed_Handler              @ 未使用
    ldr pc, =IRQ_Interrupt_Handler      @ IRQ 外部中断
    ldr pc, =FIQ_Interrupt_Handler       @ FIQ 快速中断
/****************************************/
为什么要按照以上的顺序写,是因为厂商在在 ARM A7 中 对中断向量表进行了定义:
某个中断触发会默认跳转到对应的中断服务函数的入口地址
地址        中断              描述
0X00       Reset              复位中断
0X04       Undefined       未定义指令中断
0X08       SVC                特权模式
0X0C       Pre_Abort       指令预取中止
0X10       Data_Abort     数据中止
0X14       NotUsed         未使用
0X18       IRQ                外部中断
0X1C       FIQ                快速中断
@ 可以看到中断函数的地址出现在内存的最开始,所以要写在的 _start 的最前面
2 复位中断函数:

知识点:
@ CP15协处理器 指令
@ MRC : 将 CP15协处理器 的寄存器数据 写到 ARM 寄存器
@ MCR : 将 ARM 处理器 的寄存器数据 写到 CP15 寄存器
@ MRC : 读 CP15 寄存器    MCR 写 CP15 寄存器
@ 使用格式:
@ MCR{cond},<opc1>,<Rt>,<CRn>,<CRm>,<opc12>
@ cond :指令执行的条件码 (若为空则为无条件执行)
@ <opc1>:协处理器要执行的操作码
@ <Rt>: ARM 源/目标 寄存器
@ <CRn>:CP15协处理器的 目标 寄存器
@ <CRm>:CP15协处理器 的 附加目标寄存器(若不需要附加则写c0,否则结果不可预知)
@ <opc12>: 可选的特定操作码,不需要时写 0

MCR{cond},<opc1>,<Rt>,<CRn>,<CRm>,<opc12>
MRC p15,    0,    r0,  c1,   c0,     0      
@ 从CP15的 C1寄存器 内的值 写到 ARM的R0寄存器 中
@ 含义 写SCTRL 寄存器(系统控制寄存器)
@ Cortex-A7 Technical ReferenceManua.pdf P59 P138

@ SCTLR 寄存器 部分bit含义
@   bit0:   开启/关闭 MMU            写 1 关闭
@   bit1:   开启/关闭 对齐             写 1 关闭
@   bit2:   开启/关闭 D Cache        写 1 关闭
@   bit11:  开启/关闭 分支预测      写 1 关闭
@   bit12:  开启/关闭 I Cache        写 1 关闭
@ Cortex-A7 Technical ReferenceManua.pdf  P141

@ MMU         虚拟内存管理单元
@ D Cache     数据高速缓存
@ I Cache     指令高速缓存
@ Cache 是高速缓存

@ 从容量来说 CPU < 寄存器 < Cache < DDR (内存片)
@ 从速度来说 CPU > 寄存器 > Cache > DDR
@ 这一部分涉及到计算机的相关知识,简单说一下
@ CPU的在处理数据上来说速度是最快的,但是它的容量有限,
@ 有自己装过电脑的都知道 DDR 是内存的意思(严格来说叫 DDR SDRAM)既然有个RAM 大家就知道这是个 随机存储器
@ CPU 容量有限 所以指令和数据都存在 DDR 里面,但是 DDR 对 CPU 而言速度太慢了,所以中间加了一个高速缓存 Cache
@ 按照 数据 和 指令分开的原则分成了  数据高速缓存(D Cache)和指令高速缓存(I Cache)
@ 至于复位后为什么要关闭 MMU 和 I/D Cache 需要大神来解答一下了(我查了一下说是为了提高效率)

@ 暂且先记住这是 系统复位 的一个过程

2复位中断函数编写
Reset_Handler:
@ 使用 CP15协处理器 指令 操作修改 SCTLR 寄存器 ,采用 读——改——写 的方式
    MRC p15,0,r0,c1,c0,0             @ 读取 SCTLR 的数据到 R0寄存器  (CP15协处理器)
    bic r0,#(1 << 12)                  @ 关闭 I Cache  (bic 清零指令)
    bic r0,#(1 << 11)                  @ 关闭 分支预测
    bic r0,#(1 << 2)                    @ 关闭 D Cache
    bic r0,#(1 << 1)                    @ 关闭 对齐
    bic r0,#(1 << 0)                    @ 关闭 MMU
    MCR p15,0,r0,c1,c0,0             @ 将 R0寄存器 的数据写入 SCTLR (CP15协处理器)
@ 这一段就是使用 CP15协处理器指令对 SCTLR 进行修改了
@ 先将 SCTLR 的数据到 R0寄存器
@ 然后 对相关位 写1 关闭 功能
@ 最后 将 R0寄存器 的数据写入 SCTLR

接下来 设置中断向量偏移
    ldr r0,=0x87800000               @ 向 r0 寄存器 写入 新的中断向量地址
    dsb                              @ 数据同步隔离
    isb                              @ 指令同步隔离 等待前面的指令执行完毕
    MRC p15,0,r0,c1,c0,0             @ 将 r0 中的地址写入寄存器 VBAR=0X87800000
    dsb                              @ 数据同步隔离
    isb                              @ 指令同步隔离 等待前面的指令执行完毕
@ 为什么要设置中断向量偏移?
@ 前面说过 ARM的指令从内存 0X00开始执行
    地址        中断              描述
    0X00       Reset           复位中断
    0X04       Undefined       未定义指令中断
    0X08       SVC             特权模式中断
    0X0C       Pre_Abort       指令预取中止
    0X10       Data_Abort      数据中止
    0X14       NotUsed         未使用
    0X18       IRQ             外部中断
    0X1C       FIQ             快速中断
@ 可以看到从 0X00 开始到 0X1C 这些地址是 中断向量的入口
@ 但是_start: 从 0X87800000 开始(可以查看前面的 反汇编 xxx.bis 文件)
@ 87800000 <_START>:
@ 那么就需要通过 设置中断向量偏移 的方法 对这个地址偏差进行矫正

@ 中断向量偏移 设置完成后接下来就是  清除BSS段 (略)和各个运行模式下 SP指针的设置
@ 设置处理器进入IRQ 模式
    mrs r0, cpsr                    @ 读取 CPSR 数据到 R0
    bic r0, r0, #0X1F               @ 清除 R0 的低5位 bit4-bit0 :写入二进制数据(1 1111)
    orr r0, r0, #0X12               @ 设置 R0 的低5位 bit4-bit0 :按 位 或 (1 0010)即设置为IRQ 模式
    msr cpsr, r0                    @ 将 R0 中数据传回 CPSR 寄存器
    ldr sp, =0X80600000             @设置 IRQ 模式下 sp 指针

@ 参考:《正点原子I.MX6U Linux 嵌入式驱动开发指南 》第6章 Cortex-A7 MPCore构架 P258  表6.3.2.2
@ cpsr的低5位 [bit4-bit0]
    0X10000       User            用户模式
    0X10001       FIQ             快速中断模式
    0X10010       IRQ             一般中断中断模式                          
    0X10011       SVC             SVC超级管理员 特权模式                    
    0X10110       Monitor         MON 监控模式
    0X10111       Abort           ABT 中止模式
    0X11010       Hyp             HYP模式(超级监听模式)
    0X11011       Undefin         未定义
    0X11111       Systerm         SYS 模式
一般把SVC模式放到最后,各个运行模式下 SP指针的设置完成之后跳转到 C语言 执行
/**********************************************************************************************/
个人总结:  复位中断函数的编写
复位中断函数是系统在上电 及复位后执行的第一个函数,包含了对系统进行初始化(系统的运行模式设置,中断向量表设置,中断偏移等)。
这些工作到要在 start.s 中进行,
1、在 _start: 的开头 加载中断向量表
2、编写复位中断函数
    2.1、通过CP15协处理器的有关指令 设置 SCTRL 寄存器(系统控制寄存器)来关闭 MMU 和 I/D Cache
    2.2、设置中断向量偏移
    2.3、设置各运行模式下的 SP指针
    2.4、进入 SVC 特权模式
    2.5、跳转到 C 语言函数
为了防止复位过程中 其他中断的影响可以在 复位中断服务函数开始前 关闭 IRQ 等复位工作完成后再开启 IRQ
这一篇是补了 复位函数 的一篇帖子,关于 MMU 和I/D Cache 的部分知识自己查了一些资料,但是还是遗留了一个问题:
为什么在复位时要关闭 MMU和I/D Cache ?
从查到的资料看这些设备都是为了提高系统运行速度而设置的,为什么要在复位中断中将这些设备关闭?
以上注释和代码都是在学习 《正点原子 linux 第二期 裸机开发视频 P29~P31 第15.1-15.3讲 系统中断 》 过程中
跟着 左萌主 学习并加入了一点点自己的思考写成的,作为一个小菜鸡,我大着胆子发出来跟大家一起记录学习
如果有帮助请大家自行参考、下载,如果 转载 请注明出处,并在论坛和我联系。如果有错误请大神指正!左萌主赛高!

/*********************************************************************************************/

作者        :YOKI
导师        :正点原子 左忠凯 (请允许我叫你一声导师吧)
硬件        :正点原子 ALPHA I.MX LINUX 开发板
/*********************************************************************************************/

9_interrupt.rar

278.12 KB, 下载次数: 0

工程文件包

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

88

主题

7377

帖子

5

精华

资深版主

Rank: 8Rank: 8

积分
14980
金钱
14980
注册时间
2013-11-13
在线时间
1823 小时
发表于 2020-4-2 09:38:38 | 显示全部楼层
因为MMU和I/DCache会带来缓存一致性的问题,这个不好处理,一般linux系统会帮我们处理好,但是写裸机的话用户很难对其做处理。比如Cortex-M7内核支持cache,结果导致了很多问题的发生
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-25 10:05

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表