学了那么久的嵌入式,可知程序烧录到哪
本文讨论问题
- 固件是烧录到哪里。
- CPU/MCU是从哪个地址开始执行程序。
- 你有遇到烧录固件开机后,除了电源灯常亮,板子却没有任何反应吗,你有考虑过这种现象与烧录的地址有关吗?
1. 固件烧录
回想一下刚开始学习嵌入式软件开发的时候是怎么进行的。拿到开发板后,跟着商家提供的学习课程一步一步的照敲代码、编译、烧录、启动开发板。
奥耶!开发板正常运行且与课程中的现象一致;本实验完成,开始攻克下一个实验课程。如果实验过程中遇到编译失败,或者实验现象不一致的,就拿课程附带的样例与自己的代码进行比较,看看哪里错了,就改成一致的,然后重复上述步骤。你是不是也是这样入手的呢?如果不是,那么恭喜你。
固件烧录对于整个开发过程来说,实在是再简单不过的事,也就是接好线,鼠标移至下载按钮,动动手指头,点击下载;烧录成功后,启动开发板。
如果得到预定的实验现象就万岁。如果开发板通电后没有反应,就先认为程序是否有误,检查没有错误,就觉得板子是否有问题。但就是不知有没有想过可能是烧录有问题。
我们来谈谈为什么可能是烧录的问题。烧录有个很关键的点:就是程序烧录到哪个设备的哪个地址。
我们都知道程序是顺序执行的,也就是说,程序存放的起始地址就是这段程序的入口。而CPU执行的第一条指令则是位于程序存储器的0x0地址①。如果该地址上存放的是一条无效或者错误的指令,将会导致CPU执行异常,从而导致无法正确的执行程序。
接下来,将结合51单片机、stm32F407xx、exynos4412的开发板,来探索固件烧录。
注1:0x0地址:是指程序存储器的起始地址,而不是指存储器(存储设备)的起始地址;因为CPU执行的指令都是由PC寄存器提供,而存储器不一定映射到程序存储器的起始地址,例如芯片内部有多个存储器。
2. 51单片机固件烧录
相较于其他两款芯片而言,51单片机固件的烧录地址是最为直观的,以芯片STC89C51RC为例。通过查阅STC89C51RC芯片手册,该芯片内部设有用存放程序的程序存储器,大小为4K,地址范围在0000H~0FFFH(图1-1-1)。也就是说在烧录时,应该在烧录工具中,将烧录的起始地址设置为0x0。
3. STM32固件烧录
对于stm32固件的烧录,在这以在keil软件中的在线仿真为例。stm32F407xx芯片内部主存储器的地址范围是0x08000000 ~ 0x080FFFFF(图1-1-2);也就是说,固件烧录的起始地址为0x08000000。
这个需要在keil中进行配置:【Options for Target ‘Target 1’】→【Debug】→【Use:J-LINK/J-TRACE Cortex】→【Settings】→【Flash Download】→【Programming Algorithm】→【Add】添加对应的flash配置文件,如果此处选错了flash的配置文件,会导致烧录出错甚至本节提到的问题(图1-1-3)。
看到这是否有所疑惑,此时程序存放的存储器的起始地址是0x08000000 ,而CPU却是从程序存储器的0x0地址开始的指令,那么CPU又是如何获取到0x08000000 地址的指令呢?结合stm32F4xx内部的程序存储器地址映射来分析(图1-1-4)。
stm32F407xx芯片内部有个SYSCFG存储器重映射寄存器(SYSCFG_MEMRMP),设置寄存器的MEM_MODE字段(寄存器低二位),可以实现把0x0地址映射到不同的程序存储设备,当该字段配置为(00)b时,把主 Flash 映射到地址 0x0,拨码开关就是这个操作原理。
4. exynos4412固件烧录
与前两者不同的是,exynos4412的固件是烧录在外接的存储设备中,而不是芯片内部的存储设备。其次,前两者是跑裸机程序;而后者则是运行操作系统,因此在烧录固件前需要对扩展存储设备进行分区。而且固件烧录地址与所使用的扩展存储设备类型有关。
例如扩展存储设备是EMMC4.3和EMMC4.4,则烧录在第0块以0x0地址为起始地址(一个块大小为512字节);使用的是SD/MMC/ MOVINAND,则烧录在第1块以0x0地址为起始地址;所以需要根据不同的扩展存储设备的类型来确定固件的烧录位置。
最后,51单片机和stm32的程序是在flash中运行的,当然stm32的程序也可以拷贝到RAM中执行。而exynos4412的固件程序是运行在RAM中的。并且开机启动时,首先执行的是iROM中的固化程序,而不是烧录的固件程序。
在本书中exynos4412烧录到存储设备中的固件统称为bootloader,该bootloader由三个镜像合成(在SPL小节分析):
第一个镜像是由芯片厂商提供大小为8k。
第二个镜像是由u-boot源码生成,包含uboot入口地址到重定位部分的程序,大小为14k,称之为spl。
第三个是完整的u-boot镜像,由u-boot源码生成(图1-1-5)。
iROM中存放着由芯片厂家固化好的一段简短的程序。开机后,先是执行iROM的程序(图1-1-6)。主要作用是初始化时钟和栈,准备一个最基本的程序执行环境。接着根据启动模式(拨码开关),从扩展存储设备上加载一段预设大小的程序到内部SRAM的一个预设定的地址中(下文简称为iRAM,地址:0x02021400,图1-1-7),并检查该程序的完整性。例如:根据检验码来检验拷贝的程序是否完整;最后跳转至iRAM,从这个预设定的地址,继续执行加载的程序。
5. 小结
相较于51单片机和stm32F4xx的固件烧录,exynos4412的bootloader要复杂的多,并且其中涉及多个镜像的烧录地址和运行地址,一旦其中某个镜像的烧录地址出错,就将导致后续的程序无法正常执行。
例如SPL镜像配置的运行地址不是0x02023400,那么就将导致无法从SPL镜像的程序入口开始执行,导致不可预知的错误;又或者是u-boot镜像地址烧录出错,SPL镜像的大小为14K,但还要包含2K的签名校验信息等,假如少算了这部分大小,就导致u-boot镜像烧录地址错误,被加载到内存中运行的u-boot镜像不完整,无法正常工作。
exynos4412的bootloader与51单片机和stm32F4xx的固件程序最大的区别在于,前者需要加载操作系统至内存中运行,将各种资源的管理权交由操作系统管理。而后两者的固件程序就是通常所说的裸机程序,将由这个裸机程序来管理各种资源。