最近开始学习ARM cortex M3,使用 NXP LPC1758开发板,编译环境 Keil uVision4。
阅读开发板和编译环境自带的开发例程。查找了许多文献,总结如下:
Startup_LPC17XX.s 文件
该文件作用是堆栈以及堆的初始化、定位中断向量表、调用Reset Handler复位处理程序及其他异常处理程序。
首先,对栈和堆的大小进行定义。(栈和堆含义不同,栈向下生长_initial_sp指针初始化位于栈顶,用于记录调用子程序的代码的地址以及保存局部变量等,堆可用于创建新变量,保存全局变量)
其次,在地址0x0000 0000建立中断向量表,该中断向量表第一表项(地址0x0000 0000)存放的是栈顶地址,第二个表项(地址0x0000 0004)存放的是复位中断服务入口地址,……。(LPC17xx 栈在SRAM中,所以栈顶地址为0x1000 0200。LPC1788上电后从内部Flash启动,遇到复位信号后,从0x0000 0004取出复位入口地址,执行中断复位函数,从而跳转到main C语言函数执行。)
再次,定义CRP加密。
再次,定义Reset Handler及其他异常处理程序。
再次,初始化后栈和堆,堆是从由低到高的增长,栈是由高向低生长的,两个是互相独立的数据段,并不能交叉使用。
注释:
Stack_Size EQU 0x00000200 //定义栈大小512B
AREA STACK, NOINIT, READWRITE, ALIGN=3 //堆栈段,未初始化,允许读写,8字节边界对齐
Stack_Mem SPACE Stack_Size //分配栈空间
__initial_sp
上述代码为栈定义一个512B的存储空间,并定义了存储方式和读写方式。
AREA伪指令,AREA 命令指示汇编器汇编一个新的代码段或数据段。
NOINIT:指定此数据段仅仅保留了内存单元,但为初始化。
IF :LNOT::DEF:NO_CRP
AREA |.ARM.__at_0x02FC|, CODE, READONLY
CRP_Key DCD 0xFFFFFFFF
ENDIF
AREA |.text|, CODE, READONLY
上述红色字体代码是指定LPC1700的CRP加密级别的代码段,芯片上电后会自动读取这一地址的值以确定加密方式,其中CRP_Key = 0xffffffff为不加密(0级加密),CRP_Key = 0x12345678为1级加密,CRP_Key = 0x87654321为2级加密,CRP_Key = 0x43218765为3级加密(最高级加密),3级加密将会禁止所有的ISP指令,即芯片将不能读写、不能擦除。
DCD伪指令:作用是开辟一段空间,其意义等价于C语言中的地址符“&”。开始建立的中断向量表则类似于使用C语言,其每一个成员都是一个函数指针,分别指向各个中断服务函数
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
LDR R0, =__main // 装载寄存器指令,_main为运行时库提供的函数
BX R0 //切换指令集,main函数不返回,跳到__main,进入C的世界
ENDP
上述蓝色字体代码是调用Reset Handler中断复位服务函数,先EXPORT伪指令声明Reset_Handler的全局性,然后函数__main。利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰。IMPORT伪指令用于通知编译器要使用的标号在其他的源文件中定义。 WEAK声明其他的同名标号优先于该标号被引用,就是说如果已在外面声明,会调用外面的。
; User Initial Stack & Heap
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory //定义全局标号
EXPORT __user_initial_stackheap //声明全局标号
__user_initial_stackheap //初始化两区的堆栈空间,堆是从由低到高的增长,栈是由高向低生长的,两个是互相独立的数据段,并不能交叉使用。
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ALIGN
ENDIF
END
上述紫色代码初始化栈和堆。
问题:
ARM cortex M3(以LPC1758为例)上电后除从Flash启动,能从SRAM或其他地方中启动吗?
待续。。。
|