汇编写启动代码413

来源:互联网 发布:vs2015怎么用c语言 编辑:程序博客网 时间:2024/06/07 06:57

1.关看门狗(watch dog timer 看门狗定时器)//可硬件也可以软件

看门狗,又叫 watchdog timer,是一个soc内部的定时器电路, 一般有一个输入,叫喂狗,一个输出到MCU的RST端,MCU正常工作的时候,每隔一端时间输出一个信号到喂狗端,给 WDT 清零,如果超过规定的时间不喂狗,(一般在程序跑飞时),WDT 定时超过,就回给出一个复位信号到MCU,是MCU复位. 防止MCU死机. 看门狗的作用就是防止程序发生死循环,或者说程序跑飞。
工作原理:在系统运行以后也就启动了看门狗的计数器,看门狗就开始自动计数,如果到了一定的时间还不去清看门狗,那么看门狗计数器就会溢出从而引起看门狗中断,造成系统复位。所以在使用有看门狗的芯片时要注意清看门狗。
因为在启动代码段我们不方便去喂狗,所以为了偷懒我们就先关闭看门狗,在系统启动之后再考虑是否再开WDT,开了之后就要开始喂狗。在s5pv210的irom代码[BL0]已经关了开门狗,但是很多设备并没有关开门狗,所以那时候就需要自己关WDT。
此时我们只需要关WDT,所以只需要设置WTCON寄存器地址为0xE2700000
所以设置WTCON=0x00008001
程序:

#define WTCON  0xE2700000
ldr r0 =WTCON
ldr r1 =0x00008001

str r1 [r0] 

2,设置栈和调用c语言
“c语言运行时”需要一定的环境,这些条件由汇编来提供c语言运行时主要需要栈。
c语言的局部变量都是用栈来实现的,如果汇编部分没有给c预先设置合理的栈地址,那么c代码定义的局部变量就会落空
在应用程序中我们编写的c程序并不是全部,编译器(gcc)会在链接的时候给我们添加一个头,这就是一段引导c程序的汇编代码,
这个代码就帮我们设置了栈和其他运行时需要。
cpu模式和其他模式下的栈
在arm中有37个寄存器,每种模式下都有自己独立的sp寄存器(r13),如果所有模式都使用同一个sp,那么所有程序(操作系统内核,应用程序)都用一个栈,意味着一旦应用程序出错,那么整个系统都会崩溃,所以设置多个栈是必须的。
注意:系统在复位后默认进入的是svc模式
栈必须是当前一段可用的内存(可用就是这位置必须有被初始化过可以访问的内存,且这个地方只会被我们用作栈,不会被其他程序使用)
当cpu刚复位,外部的dram尚未初始化,目前可用的内存只有sram(因为它不需初始化就可使用),所以我们只能在sram中找一段内存来作为svc的栈。
在sram中 三星官方推荐我们使用svc srack这个地址空间
栈有四种:满减栈,满增栈,空减栈,空增栈。若cpu没有特殊要求 我们一般使用满减栈
所以设置栈的代码为:
ldr sp =0xdoo37d80
接下来就可以调用c语言了,使用bl xxx的方式来调用C中的函数xxx
分别编写start.s和led.c
start.s代码:

#define WTCON  0xE2700000.global _start_start:ldr r0, =WTCONldr r1, =0x00008001str r1, [r0] ldr sp, =0xd0037d80bl led_blinkb .
led.c文件代码:让三个led灭
#define GPJOCON 0xE0200240#define GPJ0DAT 0xE0200244void led_blink(void){unsigned int *p=(unsigned int *)GPJOCON;unsigned int *p1=(unsigned int *)GPJ0DAT;*p=0x00111000;while(1){*p1=0x38;}}
这时候makefile文件也应该有点更改,在第一行的依赖添加一个led.o,并且需要在
arm-linux-gcc 后面加上-nostdlib 
编译报错(实际上是连接阶段报错):undefined reference to `__aeabi_unwind_cpp_pr1'

解决:在编译时添加-nostdlib这个编译选项即可解决。nostdlib就是不使用标准函数库。标准函数库就是编译器中自带的函数库,用-nostdlib可以让编译器链接器优先选择我程序内自己写的函数库。

makefile文件代码:
led.bin: start.o led.o arm-linux-ld -Ttext 0x0 -o led.elf $^  #链接器链接文件到0x0地址arm-linux-objcopy -O binary led.elf led.bin #得到.bin文件arm-linux-objdump -D led.elf > led_elf.disgcc mkv210_image.c -o mkx210 ./mkx210 led.bin 210.bin %.o : %.Sarm-linux-gcc -o $@ $< -c -nostdlib   #编译start.o文件而不链接%.o : %.carm-linux-gcc -o $@ $< -c -nostdlib  #编译 mkv210_image.c而不链接clean:rm *.o *.elf *.bin *.dis mkx210 -f

神奇的volatile  
volatile的作用是让程序在编译时,编译器不对程序做优化。优化有时候是好的,但是有时候是自作聪明会造成程序不对,比如delay函数。如果你的一个变量是易变的,不希望编译器帮我们做优化,就在这个变量定义时加volatile。加不加有没有差别,取决于编译器。如果编译器做了优化则有差异;如果编译器本身没做优化,那就没有差别。
.汇编写启动代码之开iCache什么是cache,有什么用cache是一种内存,叫高速缓存。从容量来说:CPU < 寄存器 < cache < DDR从速度来说:CPU >  寄存器 > cache > DDRcache的存在,是因为寄存器和ddr之间速度差异太大,ddr的速度远不能满足寄存器的需要(不能满足cpu的需要,所以没有cache会拉低整个系统的整体速度)210内部有32KB icache和32kb dcache。icache是用来缓存指令的;dcache是用来缓存数据的。
cache的意义:指令平时是放在硬盘/flash中的,运行时读取到DDR中,再从DDR中读给寄存器,再由寄存器送给cpu。但是DDR的速度和寄存器(代表的就是CPU)相差太大,如果CPU运行完一句再去DDR读取下一句,那么CPU的速度完全就被DDR给拖慢了。解决方案就是icache。icache工作时,会把我们CPU正在运行的指令的旁边几句指令事先给读取到icache中(CPU设计有一个基本原理:代码执行时,下一句执行当前一句代码旁边代码的可能性要大很多)。当下一句CPU要指令时,cache首先检查自己事先准备的缓存指令中有没这句,如果有就直接拿给CPU,如果没有则需要从DDR中重新去读取拿给CPU,并同时做一系列的动作:清缓存、重新缓存。iROM中BL0对cache的操作首先,icache的一切动作都是自动的,不需人为干预。我们所需要做的就是打开/关闭icache。其次,在210的iROM中BL0已经打开了icache。所以之前看到的现象都是icache打开时的现象。汇编读写cp15以开关icachemrc p15,0,r0,c1,c0,0;// 读出cp15的c1到r0中bic r0, r0, #(1<<12)// bit12 置0  关icacheorr r0, r0, #(1<<12)// bit12 置1  开icachemcr p15,0,r0,c1,c0,0;//写r0的值到c1中实验验证 我们来看三种情况下的led闪烁频率代码实验现象:1 直接使用BL0中对icache的操作2 关icache3 开icache实验结果分析:结论1:irom中确实是打开了icache的。结论2:icache关闭确实比icache打开时led闪烁变慢,说明指令执行速度变慢。


0 0
原创粉丝点击