了解C语言的小伙伴,一定会好奇为什么编程都会从main函数开始执行。相信很多学过的人都只是知道一个程序是从main函数这个入口进入的,但main函数又是从哪里来的呢?
对于在电脑上编程,如在windows/Linux上,main函数是由操作系统调用的,main函数完成后,会给操作系统返回值。
对于最简单的嵌入式程序,CPU从上电开始,需要执行以下步骤:
- 从启动文件的代码开始执行程序。
- 启动代码跳转到main函数
- main函数结束后返回启动文件也就是说,main函数是由人为设定的,并不一定要叫做main函数。
启动文件:
因进入main函数后程序是以C语言编写,C语言中的函数实现需要出入栈,因此启动文件在跳转到main函数前需要先设置栈。完成栈的设置后,启动文件会做一些硬件方面的初始化工作,如内存的初始化。下面将以之前的代码为例进行讲解:
随后调用main函数,设置main函数的返回地址。
main函数返回后,启动文件还会进行一些清理工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @****************************************************************************** @ File:head.S @ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行 @****************************************************************************** .extern main .text .global _start _start: Reset: ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈 bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启 // bl是位置无关码,相当于:PCnew = PC + 偏移 // PCnew = (4+8) + 0x28 = 0x34 //ldr pc, =disable_watch_dog /* 这样写将出错 */ bl clock_init @ 设置MPLL,改变FCLK、HCLK、PCLK bl memsetup @ 设置存储控制器以使用SDRAM bl copy_steppingstone_to_sdram @ 复制代码到SDRAM中 ldr pc, =on_sdram @ 跳到SDRAM中继续执行 on_sdram: ldr sp, =0x34000000 @ 设置栈指针 ldr lr, =halt_loop @ 设置返回地址 ldr pc, =main @ 调用main函数 halt_loop: b halt_loop
|
这里以SDRAM程序的启动文件为例,程序流程如下:
- 关闭看门狗,否则程序会不断重启。
- 初始化SDRAM,然后将程序拷贝到SDRAM中执行。
- 设置栈指针。
- 跳转到main函数。
- 设置main函数返回后进入一个死循环,防止程序跑飞。