Bootloader
bootloader 其实就是一段启动程序,它在芯片启动的时候最先被执行,可以用来做一些硬件的初始化或者用作固件热更新,当初始化完成之后跳转到对应的应用程序中去。
bootloader程序需要通过下载器烧写到芯片中,而APP则可以通过有线方式的UART、IIC、USB、SPI等总线来通过bootloader来更新,视所设计的bootloader程序而定。另外,对于无线方式热更新APP,一般是用WiFi、bluetooth通过UART透传的方式烧写芯片APP程序。
Bootloader的实现
本次采用STM32F429IGT6单片机,Flash共有1MB大小,SRAM共有256KB。
本次设计一个Bootloader和一个APP程序,空间分别如下:
BOOTloader程序起始地址0x0800 0000 分配大小为0xA000 ,40KB,注意按照扇区对齐(比如4KB一个扇区)
APP程序起始地址0x0800 A000 分配的大小为0xF6000 ,984KB。
起始地址 | 存储的内容 |
---|
0x0800 0000 | BOOTloader程序 | 0x0800 A000 | APP程序 |
STM32的中断向量表和栈顶地址
STM32Fx有一个中断向量表,这个中断向量表存放代码开始部分的后4个字节处(即0x08000004),代码开始的4个字节存放的是栈顶地址。
栈是从高到低分配,高地址到低地址
堆是从低到高分配,低地址到高地址
排列格式如下:
栈顶地址 | 占用4个字节 |
---|
Reset_Handler | 复位中断向量 | 中断向量表 | 每一个中断向量表占用4个字节 | 程序 | |
BOOTloader工程
bootloader和App都是完整的STM32工程,区别在于工程所实现的功能和占用Flash的大小。由于Bootloader的功能比较单一,并且为了节约Flash留给用户App,Bootloader一般不带操作系统,所占用的Flash较小。APP是完整的用户程序,按照正常的设计流程进行设计,只需要在工程配置和部分初始化代码处进行修改。
设置工程起始地址,及其大小
中断向量表的地址偏移
调用函数NVIC_SetVectorTable() 进行配置。BOOT工程一般不需要配置
执行BOOT后,跳转到APP程序中
注意点:
-
检查堆栈地址是否有效,单片机的RAM大小为0x30000,0x3000 0000 - 0x3000 = 0x2FFD 0000,也可以用其他方法来计算RAM是否超过单片机的范围 -
关闭全局中断,__set_PRIMASK(1);仅只剩下NMI 和硬 fault 可以响应,记得在APP工程设置__set_PRIMASK(0); -
复位BOOT工程中用到的外设 -
函数指针赋值为Reset_Handler向量的地址 -
设置堆栈地址 -
跳转到APP中
typedef void (*Run_APP_t)(void);
static void Jump_to_APP(uint32_t APPProgramAddr)
{
Run_APP_t run_app = (Run_APP_t)(*(uint32_t*)(APPProgramAddr + 4));
if((*(uint32_t*)APPProgramAddr & 0x2FFD0000) == 0x20000000)
{
__set_PRIMASK(1);
GPIO_DeInit(GPIOH);
GPIO_DeInit(GPIOA);
GPIO_DeInit(GPIOC);
EXTI_DeInit();
CRC_ResetDR();
USART_DeInit(USART1);
__set_MSP(*(uint32_t*)APPProgramAddr);
run_app();
}
else
{
USART1Printf("BOOT_ERROR1!\r\n");
}
}
APP工程
Flash的起始地址,大小
中断向量表偏移地址和开启全局中断
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0xA000);
__set_PRIMASK(0);
Keil5生成BIN文件
fromelf --bin -o "$L@L.bin" "#L"
工程文件下载链接
|