1:理解BootLoader
所谓BootLoader,无非是从一个地址跳转到另外一个地址,
这种跳转是通过修改处理器的程序计数器(PC)或跳转指令来实现的,
用到BootLoader更多的是用来和上位机进行通信升级,通过boot跳转到从上位机下载好的app地址中执行。
1: typedef void (*pFunction)(void);
这种类型的指针可以指向一个不返回任何值(void)且不带任何参数的函数,用于跳转到另一个程序或者子程序的入口点,
2:pFunction Jump_To_Application;
Jump_To_Application是一个函数指针
3: if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
在这里可能会有人疑惑,这个判断为何会成立,要看ApplicationAddress地址值 & 0x2FFE0000(掩码)是否等于0x20000000这个地址值。
掩码:是一种用来选择、屏蔽或者操作指定位的数值。
4: Jump_To_Application = (pFunction) JumpAddress;
函数指针会跳到 JumpAddress这个地址实现跳转。
5:__set_MSP(*(__IO uint32_t*) ApplicationAddress);
MSP:主堆栈指针,作用是参数设置为应用程序的起始地址的值,意味着将主堆栈指针设置为应用程序的起始地址,这是启用应用程序的做法。
6:Jump_To_Application()
为什么还会需要这个函数调用呢,在4中不是已经有了实现跳转吗。其实是用来触发4的地址上的代码执行。这样才可以启用应程序
2:理解APP
app在Flash另外一块地址上,图形界面和基本功能都是在APP上。在下位机和上位机升级过程中就会用到BootLoader实现跳转,下位机开发者会把app的bin文件给上位机开发者存储到升级软件中,当下位机把USART或者USB插入到上位机(电脑)中,(Ymodem协实现上位机和下位机升级下期再说),在设备管理中会识别出来USART或USB,此时已经实现了连接。
3:BOOT和APP地址设置
1:根据我们的bootloader预留的空间的大小,设置APP跳转的起始地址,以下我设置boot地址地址是0x8000000-0x8002000,而APP地址是0x8002000-Flash最大地址, 这个芯片是512K
2:跳转APP地址是在系统初始化中下面判断中,如果VECT_TAB_SRAM初始化了即用SRAM,而我们用的是Flash。
3:SCB->VOTR是向量表偏移寄存器(Vector Table Offset Register)的缩写,
找到 VECT_TAB_OFFSET初始化,可以看到初始状态是0x000。上面在BOOT和APP地址设置中有讲到,APP地址设置的是0x8002000。
所以我们把 VECT_TAB_OFFSET 设置成 0x2000。有没有人疑惑这里为什么要设置是0x2000,因为FLASH_BASE地址是((uint32_t)0x08000000)。
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;这样就实现跳转到APP了。
4:还有另外一种方法配置APP
不设置VECT_TAB_OFFSET值,直接在main函数初始化中添加,也是能成功跳转的。
boot跳转代码
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;
#define ApplicationAddress 0x8002000int8_t IAP_RunApp(void)
{
if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
{JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
return 0;
}
else
{return -1;
}
}
APP代码
#define APP_FLASH_ADDR 0x08002000
SystemInit();
SCB->VTOR = APP_FLASH_ADDR;
__enable_irq();