打印

(转)GD32F130FXP6学习笔记五:cortex-m3系列的启动过程

[复制链接]
820|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
renzheshengui|  楼主 | 2018-8-4 10:31 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

出处:http://blog.csdn.net/cwcwj3069/article/details/10828007

补充资料:https://wenku.baidu.com/view/4f9d2eb11a37f111f1855bfc.html

补充资料:https://wenku.baidu.com/view/6132c9c158f5f61fb73666db.html

补充资料:https://segmentfault.com/q/1010000004829859



Cortex_m3的启动过程

一.arm的启动过程

arm的启动代码一般是用汇编写的,在堆栈建立以后才可以运行C代码,因为C函数调用需要把参数,函数返回地址入栈,堆栈没有建立不能运行C代码。




应用程序启动过程

应用程序启动过程:

1.映像入口地址,一般为0X00000000地址,也可以指定为其他的地址,硬件复位起来,从地址0x00000000处取指,地址0x00000000处放的复位服务函数的地址,就会进入复位服务函数。在复位函数里做一些系统的初始化,然后调用系统函数_main();

2._main 直接跳转到 __scatterload,__scatterload 执行代码和数据复制以及 ZI 数据的清零。根据分散加载文件,拷贝RW数据到RAM,在RAM空间里建立ZI的数据空间,建立运行时的映像存储器映射,然后跳转到 __rt_entry(运行时的入口)则负责初始化 C 库。还设置应用程序的栈和堆,初始化库函数及其静态数据。

3.这时应用程序的堆栈建立了,跳转到main()函数,运行用户代码。

GD32F130FXP6启动文件:

; Reset handler routine
Reset_Handler       PROC
                    EXPORT  Reset_Handler                   [WEAK]
                    IMPORT  __main
                    IMPORT  System_Init
                    IMPORT  User_Reset_Handler
                    LDR     R0, =User_Reset_Handler
                    BLX     R0
                    LDR     R0, =System_Init
                    BLX     R0
                    LDR     R0, =__main
                    BX      R0
                    ENDP

刚开始,我直接调用的Reset_Handler,执行完了后,就直接进入HardFault_Handler。后来查看资料,采知道Reset_Handler,它的作用就是将保存于flash中的初始化数据复制到sram中,做一些系统的初始化。所以自己定义的Reset_Handler要实现这部分功能,但是我又看不见代码,只能调式看汇编。我采取了另外一个办法,直接在Reset_Handler执行完之后,System_Init执行之前,加入一个自己的User_Reset_Handler,这样就可以解决问题,(但是仍然可能存在问题,刚上电时候,电源不稳,初始化SRAM里面数据,可能不对)。





二.  存储器映射的建立

1.编译链接生成的ELF文件



ELF文件格式

链接器根据输入节的属性在一个区内对它们进行排序。 具有相同属性的输入节在区内形成相邻块。链接生成的ELF文件里的数据节。

RO:包括代码和只读数据(.init  .text  .rodata)

RW:读写数据(.data)

ZI:未初始化的数据,在装载区不分配空间,执行区才分配空间。(.bss)


2. 映像的加载区和执行区

加载区: 根据映像加载到内存时所在的地址(即映像开始执行之前的位置)。

执行区: 映像执行时所在的地址。

根区:  加载区和执行区的地址相同。


加载区和执行区

一般下载到FLASH里的2进制文件就放在加载区,上图中的0X0000-0X4000空间。应用程序启动时,__scatterload函数根据分散加载文件把RW数据节拷贝到RAM空间,然后在RAM空间分配ZI数据节的空间。因为对RAM空间里数据的读写比FLASH快。一般把RW的数据拷贝到RAM。RO节的数据不做处理。这样运行时的存储器空间就建立起来了。


二.堆栈的设置

__user_initial_stackheap() 可用 C 或 ARM 汇编语言来编写。它必须返回以下参数:

• r0 中的堆基址;

• r1 中的栈基址;

• r2 中的堆限制(双区模型);

• r3 中的栈限制(双区模型)。

堆栈的模式有2种:单区模式,双区模式。

1.单区模型

默认情况下为单区模型,应用程序的堆和栈在同一存储器区中互相朝向对方增长,其中栈从地址 0x40000 向下增长,堆从地址 0x20000 向上增长。将相应的值加载到寄存器 r0 和 r1,然后返回。r2 和 r3 保持不变,因为在单区模型中不使用堆限制和栈限制。


EXPORT __user_initial_stackheap

__user_initial_stackheap

LDR r0, =0x20000 ;

LDR r1, =0x40000 ;

; r2 not used (HL)

; r3 not used (SL)

MOV pc, lr


2.双区模型

使用双区模型必须使用汇编命令 IMPORT 引入符号 __use_two_region_memory。将堆和栈分别放置在存储器不同的区中,__user_initial_stackheap() 建立的专用堆限制来检查堆。需要设置堆栈的长度。


汇编代码的实现,。栈从 0x40000 向0x20000 的限制向下增长。为使用该栈限制,所有使用此实现的模块必须进行编译以便进行软件栈检查。堆从 0x28000000 到 0x28080000 向上增长。


IMPORT __use_two_region_memory

EXPORT __user_initial_stackheap

__user_initial_stackheap

LDR r0, =0x28000000 ;HB

LDR r1, =0x40000 ;SB

LDR r2, =0x28080000 ;HL

LDR r3, =0x20000 ;SL

MOV pc, lr


沙发
labasi| | 2018-8-8 12:09 | 只看该作者
在做什么的情况下 需要关心启动过程啊

使用特权

评论回复
板凳
paotangsan| | 2018-8-9 09:35 | 只看该作者
我也没注意过 都是拿来就用

使用特权

评论回复
地板
vibra2016| | 2018-8-18 20:12 | 只看该作者
arm的启动代码一般是用汇编写的,在堆栈建立以后才可以运行C代码,因为C函数调用需要把参数,函数返回地址入栈,堆栈没有建立不能运行C代码

使用特权

评论回复
5
vivilzb1985| | 2018-8-18 20:18 | 只看该作者
映像入口地址,一般为0X00000000地址,也可以指定为其他的地址,硬件复位起来,从地址0x00000000处取指,地址0x00000000处放的复位服务函数的地址,就会进入复位服务函数。在复位函数里做一些系统的初始化,然后调用系统函数_main();

使用特权

评论回复
6
angerbird| | 2018-8-23 21:17 | 只看该作者
C函数调用需要把参数,函数返回地址入栈,堆栈没有建立不能运行C代码

使用特权

评论回复
7
chuntian2016| | 2018-8-28 22:50 | 只看该作者
这个几个补充资料的非常不错

使用特权

评论回复
8
lxs0026| | 2018-9-6 23:28 | 只看该作者
哇塞,学习一下,这个资料很好,分享的不错。 可以拿来就用。开心

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

78

主题

3858

帖子

2

粉丝