day44-硬件学习之arm启动代码
一、跳转指令实现函数调用
- LR(链接寄存器):保留函数返回地址
1.1 bl指令
跳转指令bl,使LR保存当前函数进入前的下一条指令的地址,使函数调用后可以返回下一条指令的地址;
1.2 bx指令
跳到目标地址;
1.3 栈的使用方法
函数调用前,保护现场,调用后恢复现场 :
使用栈(先进后出的特性);
栈的使用方法:
1.3.1.空增
保护时,SP先写,再加;
恢复时,SP先减,再读;
1.3.2 满增
保护时,SP先加,再写;
恢复时,SP先读,再减;
1.3.3 满减
保护时,SP先减,再写;
恢复时,SP先读,再加;
1.3.4 空减
保护时,SP先写,再减;
恢复时,SP先加,再读;
1.4 ARM内核使用满减栈,使用方法
1.4.1 stmfd指令
入栈保护时,使用stmfd指令;
stmfd <c><Rn>{!}, <registers>:
其中:
- !是让栈指针的内容随程序发生变化
- 命令含义是把多个寄存器保存到Rn寄存器中
- 举例:stmfd sp!, {r0-r12, lr}
1.4.2 ldmfd指令
出栈恢复时,使用ldmfd指令;
如:ldmfd sp!, {r0-r12, lr}
二、汇编与C语言混合调用
注意:由主调者负责保护现场和恢复现场
2.1 汇编为主调
步骤:
- 首先确保SP指针有效
- 对函数声明:import(导入) export(导出)
- 保护现场
- 使用bl跳转
- 恢复现场
注意:
若参数4个以内,R0-R3传递参数;
若有第五个参数,只能用栈的方式来传参:
- stmfd sp!, {r4}
- ldmfd sp!, {r4}
main.c
start.s
2.2 c为主调
在汇编中,声明c的函数,import main
export asm_add
main.c
start.s
三、准备工作
3.1 切换模式
CPS命令修改CPSR寄存器的M[4:0]
如,CPS #<mode>
(但不支持keil)
解决方法:
(1) msr指令:读取cpsr、spsr寄存器
mrs r0, cpsr
(2) 于r0中,设置相关数据,设为User模式(10000)
bic r0, r0, #(0x1F << 0) //低5位清零 orr r0, r0, #0x10 //第5位置一
(3) msr指令:写入cpsr、spsr寄存器
msr cpsr_c, r0
(4)将User模式下的SP进行设置
ldr sp, =0x40001000 sub sp, sp, #1024
3.2 异常处理被占用(解决),初始化异常向量表
3.3 产生软件中断异常
加^,表示恢复执行前cpsr寄存器的值
四、IMX6ULL入门
- Windows编写代码
- Ubuntu编写代码
主要部分:
- 搭建编程环境
- 汇编点灯
- 下载程序
4.1 引脚的功能复用
- 说明哪些引脚归哪个外设使用
- PAD:引脚
- MUX:功能复用
以点亮LED为例:
GPIO1组的3号引脚
数据寄存器 GPIO data register(GPIOx_DR)
方向寄存器