1:程序的存储-单片机内部FLASH
在单片机控制里面,程序作为单片机的灵魂,操控着单片机各个外部引脚的高低电平持续时间。比如说最基本的LED灯翻转程序。那这个程序是存放在哪里呢?他又是怎么被执行的呢?
1.1:单片机的程序(指令)生成
我们在进行单片机编程的时候,编译器会先将我们的c代码编译成二进制指令,(下面是我打开的.bin文件)
然后编译器会将这些二进制指令烧录到单片机的程序存储区,cpu会去一条条的读取指令执行。
1.2:指令的存放位置
下面就是我在gd32用户手册里找的一张图片,因为我们将程序(指令)写到单片机中,必须是烧录到固定的位置里面。这样的话单片机才能去找到这些指令并执行以完成我们需要的功能。
1:keil生成的单片机程序最终是以十六进制(二进制)的数据形式存在的。
2:烧录进单片机的程序是有固定位置的,并且程序存储区是有固定的大小,所以当生成的程序合适时,程序存储区就可以同时存放几段程序代码。
所以在理论上来说,只需要确定好boot程序和app程序的大小,给他们在ROM内分配合适的区块。在需要进行代码跳转的时候,做好中断向量表重定向。就可以在一个单片机中存放多块不同的程序段。
在了解了以上的原理后,我们可以从两个程序的配置方面去进行深入了解。
2:bootloader程序
bootloader程序,翻译成中文就是 引导装载程序 。他的作用就和他的名称一样,接收外部程序,装载到固定位置。
2.1:烧录位置配置
因为boot程序必须是单片机上电执行的第一个程序,所以他的存放位置就在0x08000000位置处。
2.2:配置的结果
我们可以点击工程名称打开他的.map文件查看他的一些中断函数地址。
可以看到,这些地址都是从0x08000000位置处开始分配的。所以他的函数地址是从0x08000000开始往后顺的。
3:app执行程序
所谓的app执行程序,就是真正在执行我们所需要的功能代码程序。
3.1:烧录位置的配置
这里我们将app程序放到0x08003000位置处,当然相对的ROM大小也得相减。
0x7D000 = 0x80000 - 0x3000。
3.2:配置的结果
打开.map文件,可以看到,这个工程他整体的函数地址分配都往后偏移了0x3000个数值。
总结:
我们在实现一个boot工程时,包括boot和app程序。需要哪些步骤呢?
1:与外界通信协议栈,有线也好,无线也好,本质来说都一样。因为一般来说app程序都比较大,几十个k字节的数据,单片机不可能一次性申请那么大的缓存去存放这些数据,只能是分包去发送,上位机发送完成一包,等待单片机响应,单片机接收到完整一包后,校验没问题就将其写入到内部flash中,发送接收完成信号给上位机,然后继续接收下一包。
2:事先确认好boot程序和app程序存放的位置以及大小,上面我举例的单片机内部flash大小为512k,所以我分了12k给到boot程序,这里也是根据他实际的一个大小来进行分配的。
3:细节的处理了。
boot ==> app跳转处理
1):判断栈顶地址是否在合法范围内
2):关闭boot工程所配置的中断
3):设置新的栈顶指针
4):执行app工程的Reset_Handler从而跳转到app程序
5):在app程序中第一个重定向中断向量表。偏移量为0x3000