day11 ARM混合调用案例、ARM核 异常处理流程、软件处理异常
2017-06-16 17:20
1276 查看
回顾:
面试题:谈谈对ARM处理器的认识
1.常见的处理器
2.ARM定义
3.ARM版本
4.ARM流水线
5.ARM工作模式
6.ARM工作状态
7.ARM寄存器
8.ARM异常
9.ARM异常处理流程
10.ARM指令之分支跳转
11.ARM指令之数据处理指令
数据传送指令
算数运算指令
位运算指令
比较测试指令
ARM核内部玩
12.ARM指令之加载存储指令:ldr/str
ARM核和外设数据通信
13.ARM指令之栈操作指令:push/pop(满减栈)
14.ARM指令之状态寄存器操作指令:mrs/msr
15.ARM伪指令:adr/ldr
16.ARM伪操作:各种...
17.ARM混合调用之函数传递参数的两种方式方法
默认寄存器:r0/r1/r2/r3,返回值用r0
强制使用栈:asmlinkage
18.ARM混合调用之C调用汇编的变量或者函数
参考案例:
mkdir /opt/arm/day11/1.0 -p
cd /opt/arm/day11/1.0
vim add.s 添加如下内容
.text
.arm
.global add @声明全局标签add,类似C的一个全局函数
.global yy @声明全局标签yy,类似C的全局变量
@类似C语言函数定义
@调用:ret=add(100,200)对应的汇编:r0=100,r1=200
@调用时使用的跳转指令为bl add
@ret=300=r0
add:
add r0,r0,r1 @r0=r0+r1=100+200=300
mov pc, lr @实现返回
@类似C语言变量定义
yy:
.word 0x1234
.end
保存退出
vim main.c 添加如下内容
extern int add(int, int);//声明
extern int yy; //声明
int main(void)
{
int ret;
ret = add(100, 200); //对应的汇编为bl add
//r0=100,r1=200
//ret=r0
ret = yy;
}
arm-cortex_a9-linux-gnueabi-as -g -o add.o add.s
arm-cortex_a9-linux-gnueabi-gcc -nostdlib -g -c main.c -o main.o
arm-cortex_a9-linux-gnueabi-ld -nostdlib
-nostartfiles -o main main.o add.o -emain
测试:
qemu-arm -g 1234 main
arm-cortex_a9-linux-gnueabi-gdb main
(gdb)target remote localhost:1234
(gdb)l
(gdb)b
(gdb)s
(gdb)info reg //查看传递的参数100,200
...
(gdb)p ret //查看变量ret的值,默认是10进制显示
(gdb)p /x ret //查看变量ret的值,按16进制显示
总结:C调用汇编注意事项
1.汇编的"变量"和"函数"要用.global进行全局化
2.汇编的函数一定要用mov pc, lr进行返回
3.C在调用之前,记得用extern进行声明
19.ARM混合调用之汇编调用C的变量或者函数
参考案例:
mkdir /opt/arm/day11/2.0
cd /opt/arm/day11/2.0
vim add.c 添加如下内容
int g_data = 10000; //全局变量
//全局函数
int add(int a, int b)
{
return a+b;
}
保存退出
vim main.s 添加如下内容
.text
.arm
.global main @程序入口函数
.extern add @声明
.extern g_data @声明
main:
mov r0, #100 @传递的第一个参数,给add函数的a
mov r1, #200 @传递的第二个参数,给add函数的b
bl add @调用add函数
ldr r2, =g_data @将C的全局变量g_data的首地址给r2
@r2=&g_data
ldr r3, [r2] @r3=10000
b .
.end
保存退出,编译,测试
总结:汇编调用C的注意事项
1.C只要保证被调用的变量和函数是全局即可
千万不能用static修改
2.汇编调用之前记得要用.extern进行声明
3.汇编调用C的函数用bl指令
20.ARM核异常处理的流程
20.1.ARM异常的总体流程
以UART控制器给CPU核发送IRQ中断信号为例
1.UART控制器接收到数据首先UART控制器
给中断控制器发送中断电信号
2.中断控制器对此中断信号进行一番的判断
最终中断控制器给CPU核发送IRQ中断信号
当然也可以给CPU核发送FIQ中断信号
3.CPU核一旦接收到IRQ中断信号,立刻触发了
IRQ中断异常,CPU核立马要处理IRQ中断异常
4.CPU核首先硬件上自动做:
备份CPSR到SPSR_IRQ
设置CPSR的:
MODE=XXXXX
T=0
F=1
I=1
保存返回地址LR_IRQ=PC-4
设置PC=0x18,让CPU核跑到0x18地址去运行
0x18地址可以放置自己的软件程序
至此开启了软件处理IRQ异常的流程
5.软件处理IRQ异常的流程:
如何编程实现完全由程序员"自行决定"
6.软件处理IRQ异常以后,最终CPU核要返回到
原先被打断的地方继续执行,返回需要软件
实现,只需做两件事:
CPSR=SPSR_IRQ 原先被打断的程序的状态恢复
PC=LR_IRQ 返回到原先被打断的地方继续执行
7.总结:对于处理异常,软件只负责实现第5和6两个步骤即可
第5步做的事就是在异常对应的入口地址放置添加
自己的软件代码(根据用户需求来定)
第6步做的是就是CPSR=SPSR_IRQ和PC=LR_IRQ
20.1.ARM核异常返回的软件编程代码实现(针对第6步):
1.软中断异常返回指令:
例如:
...
sub r1, r1, #4
swi
add r0, r0, #1
bic r0, r0, #0xf
...
分析过程:
1.当CPU执行swi指令时,触发软中断异常
2.CPU核硬件上做:
备份
设置MODE/T/I/F
lr_swi=pc-4(pc=bic)
=add
设置pc=0x08 //CPU核跑到0x08地址去运行
//正式开启了软件处理软中断
异常的流程
3.软件处理软中断异常最终返回,CPU核只需返回到
add指令继续运行,对应的代码:
movs pc, lr
此代码实现两个功能:
cpsr=spsr_swi
pc=lr_swi=add
2.未定义指令异常
例如:
...
sub r0, r0, #1
lisi r0, r1
add r0, r0, #1
bic r0, r0, #0xf
...
分析:
1.当CPU执行lisi指令时,lisi指令CPU不识别
触发未定义指令异常
2.ARM硬件上做
备份
设置
lr_undef=pc-4(pc=bic)
=add
设置pc=0x04 //CPU核跑到0x04地址去运行
3.软件处理未定义指令异常最终返回,只需返回
到add继续执行即可,对应的软件代码:
movs pc, lr
3.FIQ/IRQ中断异常
例如:
...
sub r0, r0, #1
add r0, r0, #1
bic r0, r0, #0xf
cmp r0, r1
...
分析:
1.当CPU执行sub指令时,突然外设给CPU核
发送了一个IRQ或者FIQ中断信号,立马
触发一个FIQ或者IRQ中断异常
2.CPU核硬件上立马执行:
备份
设置
lr_irq/lr_fiq=pc-4(pc=cmp)
=bic
设置pc=0x1c/0x18 //软件继续处理FIQ、irq中断长
3.软件处理中断返回,返回到add执行继续执行
对应的代码:
subs pc, lr, #4
做:
cpsr=spsr_irq/spsr_fiq
pc=lr-4=bic-4=add
4.预取指令异常
例如:
...
sub r1, r1, #1
add r0, r0, #1
bic r0, r0, #0xf
cmp r0, r1
...
分析:
1.当CPU进行对sub取指时,压根就没有取到
当CPU执行时,没有合法的指令,就会触发
一个预取指令异常
2.CPU核硬件做:
备份
设置
lr_instr=pc-4(pc=bic)
=add
设置pc=0x0c
3.软件处理预期指令异常返回,理论上只需返回到
add指令继续执行,但是ARM公司建议取指失败没关系
建议再来一次,所以还是需要跑到sub指令运行
返回的代码:
subs pc, lr, #4
5.数据处理异常
例如:
...
ldr r1, [r0]
sub r1, r1, #0
add r0, r0, #1
bic r0, r0, #0x0f
cmp r0, r1
...
分析:
1.当CPU执行ldr以后,还要进行访存M,此时此刻
发生了CPU访存失败,就是没有找到要访问
的外设地址,发生了数据处理异常
2.CPU核硬件上做:
备份
设置
lr_data=pc-4(pc=bic)
=add
设置pc=0x10 //开启软件处理异常
3.软件处理异常完毕,理论上返回到sub指令
去运行,但是ARM公司建议,随着这次访存失败了
建议再来一次,只需在返回到ldr运行,返回代码:
subs pc, lr, #8
切记结论:
1.软中断异常返回代码:movs pc, lr
2.未定义指令异常返回代码:movs pc, lr
3.FIQ/IRQ异常返回代码:subs pc, lr, #4
4.预取指令异常返回代码:subs pc, lr,#4
5.数据处理异常返回代码:subs pc, lr,#8
20.2.软件处理异常的流程
1.明确:异常发生,异常的整个处理分两部分
硬件部分(ARM核硬件自动完成)
备份CPSR
设置CPSR
保存返回地址
设置PC为异常对应的入口地址,至此切换到软件部分
软件部分(程序员实现)
编写异常向量表的代码
编写保护现场的代码
根据用户需求编写异常的具体处理代码
编写恢复现场的代码
2.明确相关概念
异常向量表:本质上就是在异常的入口地址
放置添加自己的处理函数,处理
代码,参见vetor.bmp
保护现场:保护被打断的进程使用的寄存器数据
只需将被打断的进程使用的寄存器中的
数据进行压栈处理即可!
恢复现场:异常处理完毕,CPU要返回到原先被打断
的进程地方继续执行,执行之前先从
栈中把原先保存的数据再进行恢复
3.实战:以下位机的按键为例,掌握IRQ中断异常的
整个处理流程,按下按键,下位机通过UART
给上位机发送一句打印信息即可
3.1.分析用户需求
按下按键,下位机给上位机发送打印信息
3.2.掌握按键的硬件信息
1.打开底板原理图,以SW6按键为例
SW6按键连接到S5P6818的GPIOA28引脚
SW6按键不进行按下操作,GPIOA28为高电平
SW6按键按下操作,GPIOA28为低电平
GPIOA28引脚的状态是外设按键给S5P6818
2.画出一个简要的硬件连接示意图
3.分析软件操作的方式方法
由于按键的操作是随机的,软件又要确保
能够获取到GPIOA28的正确的电平状态,首先
想到采用轮训方式,CPU不干其他事情,一直
判断GPIOA28的电平是否变成了低电平,但是这么
做没问题,问题在于相当耗费CPU资源,大大降低了
CPU的利用率,对于这种外设,还要想到中断方式
来判断GPIOA28的电平是否有变化
4.明确:按键中断的处理流程
4.0.CPU核正在执行某个进程
4.1.突然按键SW6按下,按键对应的GPIOA28
引脚由高电平变成低电平,产生
一个下降沿电信号
4.2.此下降沿电信号跑到中断控制器
中断控制器立马硬件上要对此
电信号进行一番的判断
4.3.中断控制器首先判断GPIOA28引脚
中断功能是否使能
假如此引脚的中断功能禁止,中断控制器
直接将此下降沿电信号丢弃
假如此引脚的中断功能使能,中断控制器
继续对此电信号进行判断
4.4.中断控制然后判断此下降沿电信号是否
是有效的中断触发信号
明确:中断的触发电信号的方式有五种
高电平触发
低电平触发
下降沿触发
上升沿触发
双边沿触发(上升+下降都可以)、
假如中断控制器不识别下降沿中断电信号,
中断控制器同样直接丢弃
假如中断控制器认为此下降沿中断电信号
为有效的中断触发信号,中断控制器继续判断
4.5.假如下降沿电信号为有效的中断信号,中断控制器
继续判断此中断信号的优先级
中断控制器判断当前CPU核是否有处理的
中断,如果发现CPU核处理的中断优先级高于
当前按键SW6的中断优先级,中断控制器同样
直接丢弃SW6对应的下降沿中断信号
如果发现CPU核没有处理中断或者处理的
中断的优先级低于SW6按键的中断优先级
中断控制器继续判断
4.6.中断控制器然后判断SW6按键中断信号
到底给哪个CPU核发送中断电信号
给CPU0单独发?还是给全部的CPU核发送呢?
4.7.中断控制器最后判断SW6按键中断信号
到底以什么样的方式发送给CPU核
以IRQ形式呢?还是以FIQ形式呢?
只能选择其中一种方式,最终中断控制器
会给CPU核发送一个IRQ或者FIQ的中断信号
4.8.CPU核一旦接收到了IRQ或者FIQ中断
信号,立马触发一个IRQ或者FIQ中断异常
CPU核立马硬件上做:
备份
设置
保存
设置PC=0x18/0x1c
软件处理中断
4.10.软件处理中断
先写好异常向量表的代码
一旦异常发生,CPU核就去到0x18
或者0x1c地址去执行对应的处理代码
先保护现场,就是将被打断进程使用的
寄存器中的数据进行压栈保护,为了放置不被破坏
紧接着向上位机发送字符串
uart_puts("hello\n");
最后恢复现场,恢复到原先被打断进程的位置继续执行
别忘记从栈中将原先保存的进程数据进行恢复到寄存器中
5.打开S5P6818芯片手册P448,掌握中断控制器
极其内部特殊功能寄存器的硬件操作特性
1.每一个中断可以配置为GROUP0也可以配置为GROUP1
2.中断类型:
SGI:软中断,
中断编号:0~15
PPI:私有中断
中断编号:16~31
SPI:共享中断
中断编号:32~1019
GPIOA28属于共享中断
3.中断使能配置
GICD_ISENABLER0[15:0]:设置SGI
GICD_ISENABLER0[31:16]:设置PPI
从GICD_ISENABLER1这个寄存器开始
要设置SPI共享中断的使能或者禁止
并且GPIOA组的中断编号号为53
请问:GPIOA28对应的使能位是哪位?
明确:只要把GPIOA组使能,GPIOA28也就使能
GPIOA28属SGI,GPIOA也属于SGI,编号为53
而GICD_ISENABLER1对应的编号的个数为32
显然不够,往后推到GICD_ISENABLER2的bit[21]
3.硬件信息掌控完毕,编写ARM裸板程序,完成按键
中断的软件处理
ftp://ARM/day11/shell-vm-irq.rar
理顺代码的执行流程:
tftp 48000000 shell.bin
go 48000000 //CPU核跑到0x48000000运行(F->D->E->M->W)
-> b reset
1.设置CPU为SVC管理模式
2.修改异常向量表的起始入口地址
由0x00为0x48000000
3.初始化各个模式下的栈
注意:满减栈
-> bl main
xxx_init();//各种硬件初始化
//CPU核陷入一个死循环运行
while(1) {
...
}
突然有人按下SW6按键,最终千辛万苦中断信号
跑到了CPU核,CPU核各种处理,CPU核从
main函数中的while(1)中毫无条件的跑到
0x480000018地址(之前在go 480000000的时候
已经进行了修改)去运行
问:0x480000018对应的代码是:
答:ldr pc, _irq
1.保护现场
2.根据用户需求打印信息
3.恢复现场
总结:实际开发,ARM裸板编程对于中断要完成的工作:
1.明确:一个完整的中断处理编码工作如下:
1.编写中断控制器的初始化代码
2.编写异常向量表
b reset /*0x48000000*/
ldr pc, _undefined_instruction /*0x48000004*/
ldr pc, _software_interrupt /*0x48000008*/
ldr pc, _prefetch_abort /*0x4800000c*/
ldr pc, _data_abort /*0x48000010*/
ldr pc, _not_used /*0x48000014*/
ldr pc, _irq /*0x48000018*/
ldr pc, _fiq /*0x4800001c*/
3.编写保护现场的代码
push...
4.编写中断处理函数,根据用户需求完成代码
bl do_irq
5.编写恢复现场的代码
pop
2.但是将来不管是ARM裸板开发还是在linux系统下
开发,程序员只需完成第4步即可,其余部分都是
ARM公司和芯片厂家完成!
很简单只需编写一个SW6按键的中断处理函数,然后
一注册即可,将来就等着被调用!
面试题:谈谈对ARM处理器的认识
1.常见的处理器
2.ARM定义
3.ARM版本
4.ARM流水线
5.ARM工作模式
6.ARM工作状态
7.ARM寄存器
8.ARM异常
9.ARM异常处理流程
10.ARM指令之分支跳转
11.ARM指令之数据处理指令
数据传送指令
算数运算指令
位运算指令
比较测试指令
ARM核内部玩
12.ARM指令之加载存储指令:ldr/str
ARM核和外设数据通信
13.ARM指令之栈操作指令:push/pop(满减栈)
14.ARM指令之状态寄存器操作指令:mrs/msr
15.ARM伪指令:adr/ldr
16.ARM伪操作:各种...
17.ARM混合调用之函数传递参数的两种方式方法
默认寄存器:r0/r1/r2/r3,返回值用r0
强制使用栈:asmlinkage
18.ARM混合调用之C调用汇编的变量或者函数
参考案例:
mkdir /opt/arm/day11/1.0 -p
cd /opt/arm/day11/1.0
vim add.s 添加如下内容
.text
.arm
.global add @声明全局标签add,类似C的一个全局函数
.global yy @声明全局标签yy,类似C的全局变量
@类似C语言函数定义
@调用:ret=add(100,200)对应的汇编:r0=100,r1=200
@调用时使用的跳转指令为bl add
@ret=300=r0
add:
add r0,r0,r1 @r0=r0+r1=100+200=300
mov pc, lr @实现返回
@类似C语言变量定义
yy:
.word 0x1234
.end
保存退出
vim main.c 添加如下内容
extern int add(int, int);//声明
extern int yy; //声明
int main(void)
{
int ret;
ret = add(100, 200); //对应的汇编为bl add
//r0=100,r1=200
//ret=r0
ret = yy;
}
arm-cortex_a9-linux-gnueabi-as -g -o add.o add.s
arm-cortex_a9-linux-gnueabi-gcc -nostdlib -g -c main.c -o main.o
arm-cortex_a9-linux-gnueabi-ld -nostdlib
-nostartfiles -o main main.o add.o -emain
测试:
qemu-arm -g 1234 main
arm-cortex_a9-linux-gnueabi-gdb main
(gdb)target remote localhost:1234
(gdb)l
(gdb)b
(gdb)s
(gdb)info reg //查看传递的参数100,200
...
(gdb)p ret //查看变量ret的值,默认是10进制显示
(gdb)p /x ret //查看变量ret的值,按16进制显示
总结:C调用汇编注意事项
1.汇编的"变量"和"函数"要用.global进行全局化
2.汇编的函数一定要用mov pc, lr进行返回
3.C在调用之前,记得用extern进行声明
19.ARM混合调用之汇编调用C的变量或者函数
参考案例:
mkdir /opt/arm/day11/2.0
cd /opt/arm/day11/2.0
vim add.c 添加如下内容
int g_data = 10000; //全局变量
//全局函数
int add(int a, int b)
{
return a+b;
}
保存退出
vim main.s 添加如下内容
.text
.arm
.global main @程序入口函数
.extern add @声明
.extern g_data @声明
main:
mov r0, #100 @传递的第一个参数,给add函数的a
mov r1, #200 @传递的第二个参数,给add函数的b
bl add @调用add函数
ldr r2, =g_data @将C的全局变量g_data的首地址给r2
@r2=&g_data
ldr r3, [r2] @r3=10000
b .
.end
保存退出,编译,测试
总结:汇编调用C的注意事项
1.C只要保证被调用的变量和函数是全局即可
千万不能用static修改
2.汇编调用之前记得要用.extern进行声明
3.汇编调用C的函数用bl指令
20.ARM核异常处理的流程
20.1.ARM异常的总体流程
以UART控制器给CPU核发送IRQ中断信号为例
1.UART控制器接收到数据首先UART控制器
给中断控制器发送中断电信号
2.中断控制器对此中断信号进行一番的判断
最终中断控制器给CPU核发送IRQ中断信号
当然也可以给CPU核发送FIQ中断信号
3.CPU核一旦接收到IRQ中断信号,立刻触发了
IRQ中断异常,CPU核立马要处理IRQ中断异常
4.CPU核首先硬件上自动做:
备份CPSR到SPSR_IRQ
设置CPSR的:
MODE=XXXXX
T=0
F=1
I=1
保存返回地址LR_IRQ=PC-4
设置PC=0x18,让CPU核跑到0x18地址去运行
0x18地址可以放置自己的软件程序
至此开启了软件处理IRQ异常的流程
5.软件处理IRQ异常的流程:
如何编程实现完全由程序员"自行决定"
6.软件处理IRQ异常以后,最终CPU核要返回到
原先被打断的地方继续执行,返回需要软件
实现,只需做两件事:
CPSR=SPSR_IRQ 原先被打断的程序的状态恢复
PC=LR_IRQ 返回到原先被打断的地方继续执行
7.总结:对于处理异常,软件只负责实现第5和6两个步骤即可
第5步做的事就是在异常对应的入口地址放置添加
自己的软件代码(根据用户需求来定)
第6步做的是就是CPSR=SPSR_IRQ和PC=LR_IRQ
20.1.ARM核异常返回的软件编程代码实现(针对第6步):
1.软中断异常返回指令:
例如:
...
sub r1, r1, #4
swi
add r0, r0, #1
bic r0, r0, #0xf
...
分析过程:
1.当CPU执行swi指令时,触发软中断异常
2.CPU核硬件上做:
备份
设置MODE/T/I/F
lr_swi=pc-4(pc=bic)
=add
设置pc=0x08 //CPU核跑到0x08地址去运行
//正式开启了软件处理软中断
异常的流程
3.软件处理软中断异常最终返回,CPU核只需返回到
add指令继续运行,对应的代码:
movs pc, lr
此代码实现两个功能:
cpsr=spsr_swi
pc=lr_swi=add
2.未定义指令异常
例如:
...
sub r0, r0, #1
lisi r0, r1
add r0, r0, #1
bic r0, r0, #0xf
...
分析:
1.当CPU执行lisi指令时,lisi指令CPU不识别
触发未定义指令异常
2.ARM硬件上做
备份
设置
lr_undef=pc-4(pc=bic)
=add
设置pc=0x04 //CPU核跑到0x04地址去运行
3.软件处理未定义指令异常最终返回,只需返回
到add继续执行即可,对应的软件代码:
movs pc, lr
3.FIQ/IRQ中断异常
例如:
...
sub r0, r0, #1
add r0, r0, #1
bic r0, r0, #0xf
cmp r0, r1
...
分析:
1.当CPU执行sub指令时,突然外设给CPU核
发送了一个IRQ或者FIQ中断信号,立马
触发一个FIQ或者IRQ中断异常
2.CPU核硬件上立马执行:
备份
设置
lr_irq/lr_fiq=pc-4(pc=cmp)
=bic
设置pc=0x1c/0x18 //软件继续处理FIQ、irq中断长
3.软件处理中断返回,返回到add执行继续执行
对应的代码:
subs pc, lr, #4
做:
cpsr=spsr_irq/spsr_fiq
pc=lr-4=bic-4=add
4.预取指令异常
例如:
...
sub r1, r1, #1
add r0, r0, #1
bic r0, r0, #0xf
cmp r0, r1
...
分析:
1.当CPU进行对sub取指时,压根就没有取到
当CPU执行时,没有合法的指令,就会触发
一个预取指令异常
2.CPU核硬件做:
备份
设置
lr_instr=pc-4(pc=bic)
=add
设置pc=0x0c
3.软件处理预期指令异常返回,理论上只需返回到
add指令继续执行,但是ARM公司建议取指失败没关系
建议再来一次,所以还是需要跑到sub指令运行
返回的代码:
subs pc, lr, #4
5.数据处理异常
例如:
...
ldr r1, [r0]
sub r1, r1, #0
add r0, r0, #1
bic r0, r0, #0x0f
cmp r0, r1
...
分析:
1.当CPU执行ldr以后,还要进行访存M,此时此刻
发生了CPU访存失败,就是没有找到要访问
的外设地址,发生了数据处理异常
2.CPU核硬件上做:
备份
设置
lr_data=pc-4(pc=bic)
=add
设置pc=0x10 //开启软件处理异常
3.软件处理异常完毕,理论上返回到sub指令
去运行,但是ARM公司建议,随着这次访存失败了
建议再来一次,只需在返回到ldr运行,返回代码:
subs pc, lr, #8
切记结论:
1.软中断异常返回代码:movs pc, lr
2.未定义指令异常返回代码:movs pc, lr
3.FIQ/IRQ异常返回代码:subs pc, lr, #4
4.预取指令异常返回代码:subs pc, lr,#4
5.数据处理异常返回代码:subs pc, lr,#8
20.2.软件处理异常的流程
1.明确:异常发生,异常的整个处理分两部分
硬件部分(ARM核硬件自动完成)
备份CPSR
设置CPSR
保存返回地址
设置PC为异常对应的入口地址,至此切换到软件部分
软件部分(程序员实现)
编写异常向量表的代码
编写保护现场的代码
根据用户需求编写异常的具体处理代码
编写恢复现场的代码
2.明确相关概念
异常向量表:本质上就是在异常的入口地址
放置添加自己的处理函数,处理
代码,参见vetor.bmp
保护现场:保护被打断的进程使用的寄存器数据
只需将被打断的进程使用的寄存器中的
数据进行压栈处理即可!
恢复现场:异常处理完毕,CPU要返回到原先被打断
的进程地方继续执行,执行之前先从
栈中把原先保存的数据再进行恢复
3.实战:以下位机的按键为例,掌握IRQ中断异常的
整个处理流程,按下按键,下位机通过UART
给上位机发送一句打印信息即可
3.1.分析用户需求
按下按键,下位机给上位机发送打印信息
3.2.掌握按键的硬件信息
1.打开底板原理图,以SW6按键为例
SW6按键连接到S5P6818的GPIOA28引脚
SW6按键不进行按下操作,GPIOA28为高电平
SW6按键按下操作,GPIOA28为低电平
GPIOA28引脚的状态是外设按键给S5P6818
2.画出一个简要的硬件连接示意图
3.分析软件操作的方式方法
由于按键的操作是随机的,软件又要确保
能够获取到GPIOA28的正确的电平状态,首先
想到采用轮训方式,CPU不干其他事情,一直
判断GPIOA28的电平是否变成了低电平,但是这么
做没问题,问题在于相当耗费CPU资源,大大降低了
CPU的利用率,对于这种外设,还要想到中断方式
来判断GPIOA28的电平是否有变化
4.明确:按键中断的处理流程
4.0.CPU核正在执行某个进程
4.1.突然按键SW6按下,按键对应的GPIOA28
引脚由高电平变成低电平,产生
一个下降沿电信号
4.2.此下降沿电信号跑到中断控制器
中断控制器立马硬件上要对此
电信号进行一番的判断
4.3.中断控制器首先判断GPIOA28引脚
中断功能是否使能
假如此引脚的中断功能禁止,中断控制器
直接将此下降沿电信号丢弃
假如此引脚的中断功能使能,中断控制器
继续对此电信号进行判断
4.4.中断控制然后判断此下降沿电信号是否
是有效的中断触发信号
明确:中断的触发电信号的方式有五种
高电平触发
低电平触发
下降沿触发
上升沿触发
双边沿触发(上升+下降都可以)、
假如中断控制器不识别下降沿中断电信号,
中断控制器同样直接丢弃
假如中断控制器认为此下降沿中断电信号
为有效的中断触发信号,中断控制器继续判断
4.5.假如下降沿电信号为有效的中断信号,中断控制器
继续判断此中断信号的优先级
中断控制器判断当前CPU核是否有处理的
中断,如果发现CPU核处理的中断优先级高于
当前按键SW6的中断优先级,中断控制器同样
直接丢弃SW6对应的下降沿中断信号
如果发现CPU核没有处理中断或者处理的
中断的优先级低于SW6按键的中断优先级
中断控制器继续判断
4.6.中断控制器然后判断SW6按键中断信号
到底给哪个CPU核发送中断电信号
给CPU0单独发?还是给全部的CPU核发送呢?
4.7.中断控制器最后判断SW6按键中断信号
到底以什么样的方式发送给CPU核
以IRQ形式呢?还是以FIQ形式呢?
只能选择其中一种方式,最终中断控制器
会给CPU核发送一个IRQ或者FIQ的中断信号
4.8.CPU核一旦接收到了IRQ或者FIQ中断
信号,立马触发一个IRQ或者FIQ中断异常
CPU核立马硬件上做:
备份
设置
保存
设置PC=0x18/0x1c
软件处理中断
4.10.软件处理中断
先写好异常向量表的代码
一旦异常发生,CPU核就去到0x18
或者0x1c地址去执行对应的处理代码
先保护现场,就是将被打断进程使用的
寄存器中的数据进行压栈保护,为了放置不被破坏
紧接着向上位机发送字符串
uart_puts("hello\n");
最后恢复现场,恢复到原先被打断进程的位置继续执行
别忘记从栈中将原先保存的进程数据进行恢复到寄存器中
5.打开S5P6818芯片手册P448,掌握中断控制器
极其内部特殊功能寄存器的硬件操作特性
1.每一个中断可以配置为GROUP0也可以配置为GROUP1
2.中断类型:
SGI:软中断,
中断编号:0~15
PPI:私有中断
中断编号:16~31
SPI:共享中断
中断编号:32~1019
GPIOA28属于共享中断
3.中断使能配置
GICD_ISENABLER0[15:0]:设置SGI
GICD_ISENABLER0[31:16]:设置PPI
从GICD_ISENABLER1这个寄存器开始
要设置SPI共享中断的使能或者禁止
并且GPIOA组的中断编号号为53
请问:GPIOA28对应的使能位是哪位?
明确:只要把GPIOA组使能,GPIOA28也就使能
GPIOA28属SGI,GPIOA也属于SGI,编号为53
而GICD_ISENABLER1对应的编号的个数为32
显然不够,往后推到GICD_ISENABLER2的bit[21]
3.硬件信息掌控完毕,编写ARM裸板程序,完成按键
中断的软件处理
ftp://ARM/day11/shell-vm-irq.rar
理顺代码的执行流程:
tftp 48000000 shell.bin
go 48000000 //CPU核跑到0x48000000运行(F->D->E->M->W)
-> b reset
1.设置CPU为SVC管理模式
2.修改异常向量表的起始入口地址
由0x00为0x48000000
3.初始化各个模式下的栈
注意:满减栈
-> bl main
xxx_init();//各种硬件初始化
//CPU核陷入一个死循环运行
while(1) {
...
}
突然有人按下SW6按键,最终千辛万苦中断信号
跑到了CPU核,CPU核各种处理,CPU核从
main函数中的while(1)中毫无条件的跑到
0x480000018地址(之前在go 480000000的时候
已经进行了修改)去运行
问:0x480000018对应的代码是:
答:ldr pc, _irq
1.保护现场
2.根据用户需求打印信息
3.恢复现场
总结:实际开发,ARM裸板编程对于中断要完成的工作:
1.明确:一个完整的中断处理编码工作如下:
1.编写中断控制器的初始化代码
2.编写异常向量表
b reset /*0x48000000*/
ldr pc, _undefined_instruction /*0x48000004*/
ldr pc, _software_interrupt /*0x48000008*/
ldr pc, _prefetch_abort /*0x4800000c*/
ldr pc, _data_abort /*0x48000010*/
ldr pc, _not_used /*0x48000014*/
ldr pc, _irq /*0x48000018*/
ldr pc, _fiq /*0x4800001c*/
3.编写保护现场的代码
push...
4.编写中断处理函数,根据用户需求完成代码
bl do_irq
5.编写恢复现场的代码
pop
2.但是将来不管是ARM裸板开发还是在linux系统下
开发,程序员只需完成第4步即可,其余部分都是
ARM公司和芯片厂家完成!
很简单只需编写一个SW6按键的中断处理函数,然后
一注册即可,将来就等着被调用!
相关文章推荐
- ARM用户层发生异常后软硬件协同处理流程
- ARM异常处理流程
- ARM七种异常源和异常处理流程(四大步三小步)
- ARM用户层发生异常后软硬件协同处理流程
- ARM:ARM中断异常的处理流程
- ARM七种异常源和异常处理流程
- arm 硬件和软件对异常的处理
- Arm架构异常处理流程之缺页异常
- Arm架构异常处理流程之中断
- 【转帖】Windows异常处理流程 - 看雪软件安全论坛
- arm平台linux异常处理流程
- iOS 方法调用异常处理流程
- arm 异常处理
- 浅析达芬奇DM644x平台ARM中断处理流程
- 软件开发需要重视对异常的处理
- [原创] WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理
- ImageMagick 处理图片的开源软件 可通过命令行调用
- Windows异常处理流程
- WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理
- 调用webservices服务一个异常处理:org.xml.sax.SAXException: SimpleDeserializer encountered a child element, which is NOT expected, in someth