×
单片机 > 单片机程序设计 > 详情

tiny4412裸机程序——代码重定位

发布时间:2024-05-20 发布时间:
|

在前面介绍exynos4412芯片启动过程时,我们知道:一上电,exynos4412首先执行固化在iROM中的代码,iROM首先设置程序运行环境(比如关看门狗、关中断、关MMU、设置栈、设置栈、启动PLL等),然后根据OM引脚确定启动设备(NAND Flash/SD卡/其他),把BL1从里面读出存入iRAM的0x02021400地址处,然后开始启动BL1;BL1从SD卡适当的位置读入14K字节的数据,存在iRAM地址0x02023400处,所以BL2不能大于(14K–4) 字节,这里引出了为什么写这一节的原因:如果我们的程序很大,大于14K怎么办?


运行地址和链接地址:


运行地址是程序当前所处的地址,即程序在运行时,所处的当前地址。

链接地址是程序的链接地址,即程序运行时应该位于的运行地址。编译程序时,可以在链接脚本中指定程序的链接地址。


对于tiny4412而言,前面我们已经说过:启动时BL1只会从sd等启动设备中拷贝14K的代码到iRAM中,那么当我们的程序超过14K怎么办?那就需要我们在前14K的代码中将整个程序完完整整地拷贝到LPDDR等其他更大存储空间,然后再跳转到LPDDR中继续运行我们的代码,这个拷贝然后跳转的过程就叫重定位。


本章中讲解学习如何重定位,但是并不会涉如何使用到LPDDR,而是简单地将代码从iRAM的0x02023400处拷贝到iRAM的0x02026400处,然后跳转到0x02026400处继续运行我们的代码。


程序文件介绍:


1.start.S文件内容介绍:


.text

.global _start

_start:

//关闭看门狗;关于看门狗的设置可以查看Spec 1357页

ldr r0, =0x10060000 //将0x10060000数字保存到R0寄存器中

mov r1, #0x0 //将0x0数字保存到R1寄存器中

str r1, [r0] //将R1寄存器中的数字(0)保存到R0寄存器数字表示的地址中

//重定位整个代码到0x0202_6400地址处;这个地址位于iRAM里面

adr r0, _start //将_start标号(程序的开始地址)位于iRAM里的实际地址保存到R0寄存器中;也是开始拷贝程序的地址

ldr r1, =_start //获取链接地址;也就是想将程序运行的地址;将拷贝的程序从这个地址开始保存

ldr r2, =bss_start //将链接地址中的bss_start标识地址保存到R1寄存器中;也是拷贝程序结束的地址;R1-R2的大小也就是要

//重定位代码的大小

cmp r1, r2 //比较两个地址是否相等,如果相等在直接去清除bss段即可;

beq clear_bss //跳转到清零bss处

reload_loop:

ldr r3, [r0], #4 //将R0数字表示地址处的数据加载到R3寄存器中;并将R0+4

str r3, [r1], #4 //将R3中的数据保存到R1寄存器数字表示的地址中,并将R1+4

cmp r1, r2

bne reload_loop //循环拷贝

clear_bss: //将bss段清零

ldr r0, =bss_start //将bss段的开始地址保存到R0寄存器

ldr r1, =bss_end //将bss段的结束地址保存到R1寄存器

mov r2 ,#0x0 //将0数字保存到R2寄存器中

cmp r0, r1 //如果相等则表示bss清零完毕,跳转执行点亮LED

beq run_address

clear_loop:

str r2, [r0], #4 //将0保存到R0寄存器地址,并将R0+4

cmp r0, r1

bne clear_loop //如果不相等则表示没有清零完成

run_address: //点亮LED灯

ldr sp, =0x02027400 //设置栈

ldr pc, =main //使用绝对跳转指令

//bl main

halt_loop: //死循环

b halt_loop

程序中已经做了详细的注释,这里就不再详细介绍。


2.main.c文件详细介绍:


//定义两个宏,方便操作使用到的寄存器

#define GPM4_CON (*(volatile int *)0x110002E0)

#define GPM4_DAT (*(volatile int *)0x110002E4)

int main()

{

//设置GPM4_0引脚为输出

GPM4_CON &= ~0xFF; //GPM4CON寄存器的低8位清零

GPM4_CON |= 0x11; //GPM4CON寄存器的bit0/4置1,设置为输出引脚

//设置GPM4_0引脚为低电平

GPM4_DAT &= ~0x3; //GPM4DAT寄存器bit0/1清零,输出低电平

return 0;

}

程序中已经做了详细的介绍,这里不再介绍。


3.链接脚本:


SECTIONS {

. = 0x02026400; /* 链接地址 */

. = ALIGN(4);

.text :

{

*(.text)

}

. = ALIGN(4);

.rodata :

{

*(.rodata)

}

. = ALIGN(4);

.data :

{

*(.data)

}

. = ALIGN(4);

bss_start = .; /* bss段的开始位置 */

.bss :

{

*(.bss) *(.COMMON)

}

bss_end = .; /* bss段的结束位置 */

}

链接脚本的内容很简单,起始地址是0x02026400,并获取了bss段的起始和结束地址。


按照前面文章讲解的编译和烧写命令,将程序烧写到SD卡中,设置SD卡启动,观察现象,发现LED1/2被点亮。说明程序重定位成功。


完毕!


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机制作超级流水灯