汇编写启动代码之关看门狗、设置栈、调用C、开关icache
关看门狗(watch dog timer)
在正常情况下,系统软件每过一段时间会自动进行一次喂狗(即将看门狗定时器置0重新定时)。但是如果设备跑飞,死机,系统无法自动喂狗。那么等到看门狗定时器计时时间到了,就会自动将设备复位。在一些特殊环境下的无人值守设备中,这种自动发现问题然后复位的技术就很重要。
那为什么要关看么狗?
答:我们在启动代码处,不方便喂狗,所以索性把看门狗关了,等以后需要的时候再开启。
物理特性:定时器,硬件上就是SOC的内部外设,所以不需要原理图分析
关键寄存器:WTCON(0xE2700000),其中bit5位开关。
#define WTCON 0xE2700000
.........省略别的代码
//第一步关看门狗 ldr r0, =WTCON ldr r1, =0x0 str r1, [r0]
设置栈
- 由于C语言的局部变量是存在栈中的,所以调用C语言的前提是设置好栈。
- 在单片机中,硬件一开始已经设置了一个栈,所以我们可以直接用C语言。
- 在应用程序中,我们编写的C语言程序其实不是全部,编译器在链接的时候会自动添加一个头,这个头通过汇编帮C语言设置的了栈。
- 在嵌入式程序中,必须自己手动的用汇编编写栈。
注意:在ARM的37个寄存器中,每个模式下都有自己独立的SP寄存器(r13),这样各个模式下的栈不会互相产生干扰。
由于我们的板子在系统复位后默认为SVC模式,所以我们只需要在此模式下,用汇编设置SP就可以了。
#define SVC_STACK 0xD0037D80
//设置栈 ldr sp, =SVC_STACK //从这里开始可以调用C语言了 bl led_blink //运用bl来调用C语言中的函数
在.c文件中写一个led_blink文件
#define GPJ0CON 0xE0200240 #define GPJ0DAT 0xE0200244 #define rGPJ0CON *((volatile unsigned int *)GPJ0CON) #define rGPJ0DAT *((volatile unsigned int *)GPJ0DAT) void delay(void); //该函数要实现led闪烁的效果 void led_blink(void) { rGPJ0CON = 0x11111111; rGPJ0DAT = (1<<3)|(1<<4)|(1<<5); while(1) { //led点亮 rGPJ0DAT = (0<<3)|(0<<4)|(0<<5); delay(); //led灭 rGPJ0DAT = (1<<3)|(1<<4)|(1<<5); delay(); } } void delay(void) { volatile unsigned int i = 1000000; while(i--); }
关icache
cache:高速缓存
- 容量:CPU<寄存器<cache<DDR
- 速度:CPU>寄存器>cache>DDR
- 由于DDR的速度远远不及CPU,所以加上cache可用于做缓冲,否则CPU的速度会被DDR严重拖慢。
- 现在几乎所以的CPU都带cache的
//第三步:开/关icache mrc p15,0,r0,c1,c0,0; //读出cp15的c1到r0中 bic r0, r0, #(0<<12) //bit12置0,关icache // orr r0, r0, #(1<<12) //bit12置1,开icache mrc p15,0,r0,c1,c0,0;