[国嵌攻略][050][2440按键中断编程]

程序结构优化

1.把不同的功能放到不同的文件里面

2.一般在bootloader中不使用MMU,所以关掉MMU

 

按键初始化

1.打开开发板的原理图,找到按键

2.把对应的GPIO配置成中断,对中断源进行初始化

 

初始化中断控制器

1.SUBMASK和MASK必须要保证没有屏蔽中断,GPIO是不属于子中断,所以不用设置SUBMASK,MODE和Priority保存默认值即可,设置INTMSK(0x4A000008)

2.EINT4_7对应4个中断,分开设置需要设置EINTMASK(0x560000A4)。注意,设置EINTMASK寄存器必须要在INTMASK之前设置

3.在核心预处理时,关闭了中断,在这里需要打开中断

 

中断处理

1.当中断产生时,会跳转到中断向量表,执行ldr pc, _irq

 

2.保存环境

2.1.当前lr指向pc+8的位置,当中断返回时需要返回到lr-4的位置,算出lr的值,sub lr, lr, #4

2.2.保存寄存器到堆栈,stmfd sp!, {r0-r12, lr}

2.3.调用中断处理函数,handle_int

2.4.从堆栈恢复寄存器,ldmfd sp!, {r0-r12, pc}^

2.5.handle_int需要做:1.判断中断源 2.根据中断源,执行不同的中断处理。INTOFFSET(0x4A000014)标明了那个中断源产生了中断

 

3.清除中断,在恢复环境之前先要清除SRCPND(0x4A000000)和INTPND(0x4A000010)对应位的请求,保证下次中断能被处理。如果下次中断到来,发现SRCPND和INTPND对应位为1,表示上次中断还没有被处理,忽略这次中断请求。如果用到是子中断需要清零SUBSRCPND,如果用到的是EINT4-ENT23那么要清除EINTPEND(0x560000A8)。注意,要清除中断时要往对应位上写入1

 

4.注意在irq模式中设置的sp栈指针是r13_irq,而初始化栈sp指针是r13_svc。所以在初始化栈指针是要对r13_irq和r13_svc都要设置地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/********************************************************************
*名称:irq
*功能:中断处理
*********************************************************************/
irq:
    //保存环境
    sub lr, lr, #4            //三级流水线,pc指向指定的地址与当前执行指令的地址偏移+8
    stmfd sp!, {r0-r12, lr}   //保存r0-r12和lr寄存器的值到栈中
     
    //处理中断
    bl process_int
     
    //恢复环境
    ldmfd sp!, {r0-r12, pc}^   //从栈中载入r0-r12和lr寄存器的值,^表示把spsr恢复到cpsr

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/********************************************************************
*名称:int
*作者:D
*时间:2015.11.10
*功能:中断控制器
********************************************************************/
 
/********************************************************************
*                            宏定义
********************************************************************/
#define SRCPND 0X4A000000     //中断源请求寄存器
#define INTPND 0X4A000010     //中断请求寄存器
#define INTMSK 0x4A000008     //中断掩码寄存器
#define EINTMASK 0x560000A4   //外部中断掩码寄存器
#define EINTPEND 0x560000A8   //外部中断请求寄存器
 
.text
/********************************************************************
*名称:init_int
*功能:初始化中断
*********************************************************************/
.global init_int
init_int:
    //屏蔽中断
    ldr r0, =INTMSK
    mvn r1, #0   //屏蔽中断,设置INTMSK[31-0]:0xFFFFFFFF
    str r1, [r0]
     
    //关闭中断
    mrs r0, cpsr
    orr r0, r0, #0x000000C0   //关闭中断,设置cpsr[7-6]:11
    msr cpsr, r0
     
    mov pc, lr
     
/********************************************************************
*名称:enable_int
*功能:打开中断
*********************************************************************/
.global enable_int
enable_int:
    //使能中断
    ldr r0, =EINTMASK
    ldr r1, [r0]
    bic r1, r1, #0x00000900   //使能外部中断,设置外部中断掩码EINT8:0 EINT11:0
    str r1, [r0]
     
    ldr r0, =INTMSK
    ldr r1, [r0]
    bic r1, r1, #0x00000020   //使能中断,设置中断掩码EINT8_23:0
    str r1, [r0]
     
    //打开中断
    mrs r0, cpsr
    bic r0, r0, #0x000000C0   //打开中断,设置cpsr[7-6]:00
    msr cpsr, r0
     
    mov pc, lr
     
/********************************************************************
*名称:process_int
*功能:处理中断
*********************************************************************/
.global process_int
process_int:
    mov ip, lr   //保存链接寄存器,嵌套调用保存返回地址
     
    //读取中断源
    ldr r0, =EINTPEND   //读取外部中断请求,如果中断从INTOFFSET中读取,子中断从SUBSRCPND
    ldr r1, [r0]
     
    //处理中断源
    cmp r1, #0x00000100   //如果是EINT8,调用EINT8中断处理
    beq eint8_process
    cmp r1, #0x00000800   //如果是EINT11,调用EINT11中断处理
    beq eint11_process
    b end_process_int     //如果都不是,结束中断处理
     
eint8_process:
    bl on_led    //点亮led
    b end_process_int
     
eint11_process:
    bl off_led   //熄灭led
    b end_process_int
 
end_process_int:
    //清除中断源
    ldr r0, =EINTPEND
    ldr r1, [r0]
    str r1, [r0]              //清除外部中断请求
     
    ldr r0, =SRCPND
    ldr r1, [r0]
    orr r1, r1, #0x00000020   //清除中断源请求,设置EINT8_23:0,如果是子中断还要清除SUBSRCPND
    str r1, [r0]
     
    ldr r0, =INTPND
    ldr r1, [r0]
    orr r1, r1, #0x00000020   //清除中断请求,设置EINT8_23:0
    str r1, [r0]
     
    mov lr, ip   //恢复链接寄存器,嵌套调用恢复返回地址
    mov pc, lr

 

注意:在函数嵌套调用中要先把lr保存到ip中,在函数中被调用其他函数时会改变,当外部函数返回时,需要从ip中恢复lr,用于返回到外部函数被调用处

 

r0-r15寄存器作用

r0-r3

用作传入函数参数,传出函数返回值。在子程序调用之间,可以将 r0-r3 用于任何用途。被调用函数在返回之前不必恢复 r0-r3。如果调用函数需要再次使用 r0-r3 的内容,则它必须保留这些内容。

r4-r11

被用来存放函数的局部变量。如果被调用函数使用了这些寄存器,它在返回之前必须恢复这些寄存器的值。

r12

是内部调用暂时寄存器 ip。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复 r12。

r13

是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。

r14

是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复

r15

是程序计数器 PC。它不能用于任何其它用途。

注意:在中断程序中,所有的寄存器都必须保护,编译器会自动保护R4~R11

posted @   盛夏夜  阅读(270)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示