复旦微FM33LG045串口实现在线升级
参考文档:
STM32单片机实现Bootloader跳转的关键步骤 - 知乎 (zhihu.com)
【笔记】复旦微FM33L026实现远程升级 - 知乎 (zhihu.com)
本文以FM33LG045为例,实现串口在线升级。
配置bootloader地址和app地址
app地址
app程序的起始地址为0x10000~0x30000
总大小为192KB
PS:这里需要器件的flash总大小,即不要地址越界了,我这个芯片的flash大小为256KB,即地址范围0x0~0x40000
BootLoador地址
FM33中flash起始地址为0x00,故BootLoador的空间为0x0~0x10000,总大小64KB。
PS:在stm32中起始地址映射为0x8000000,根据不同的单片机选择合适的起始地址。
修改中断向量偏移
这里尤其要注意,需要修改APP程序的中断向量偏移,如果不修改偏移,APP程序里的中断就会跑到引导程序里面!!
找到文件system_fm33lg0xx.c,在 SystemInit() 中添加下列代码
SCB->VTOR = 0x00010000;
实现IAP跳转
下列代码即可实现bootloader程序到app程序的跳转
//.h文件
typedef void (*iapfun)(void); /* 定义一个函数类型的参数 */
#define FLASH_APP1_ADDR 0x00010000
//.c文件
iapfun jump2app;
uint32_t g_iapbuf[128];
void iap_load_app(uint32_t appxaddr)
{
/* 用户代码区第二个字为程序开始地址(复位地址) */
jump2app = (iapfun) * (volatile uint32_t *)(appxaddr + 4);
/* 初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址) */
__set_MSP(*(volatile uint32_t *)appxaddr);
/* 跳转到APP */
jump2app();
}
至此所有配置结束,在main函数中调用iap_load_app()即可实现app程序的跳转
生成app程序的bin文件
bin文件后续升级需要用到,keil需要配置后编译才能生成bin文件,具体配置如下
fromelf --bin --output
./Objects/nx.bin //生成目标文件位置和文件名
./Objects/FM33LC0xx_Tester.axf //.axf的文件位置
APP程序升级
接下来就是向flash对应地址中写入bin文件数据了
本例中app起始地址为0x10000,我们只需要将串口接收到的app数据写入地址0x10000,全部写完后,再进行app跳转即可实现app程序的升级,如下图所示:
将串口接收到的数据写入flash参考代码
uint32_t g_iapbuf[128]; /* 2K字节缓存 */
/**
* @brief IAP写入APP BIN
* @param appxaddr : 应用程序的起始地址
* @param appbuf : 应用程序CODE
* @param appsize : 应用程序大小(字节)
* @retval 无
*/
//
void iap_write_appbin(uint32_t appxaddr, uint8_t *appbuf, uint32_t appsize)
{
uint16_t t;
uint16_t i = 0;
uint32_t temp;
uint32_t fwaddr = appxaddr; /* 当前写入的地址 */
uint8_t *dfu = appbuf;
for (t = 0; t < appsize; t += 4)
{
temp = (uint32_t)dfu[3] << 24|(uint32_t)dfu[2] << 16|(uint32_t)dfu[1] << 8|(uint32_t)dfu[0];
dfu += 4; /* 偏移2个字节 */
g_iapbuf[i++] = temp;
if (i == 128)
{
i = 0;
FL_FLASH_PageErase(FLASH, fwaddr);
FL_FLASH_Program_Page(FLASH, fwaddr / FL_FLASH_MAX_PAGE_NUM, g_iapbuf);
fwaddr += 512; /* 偏移2048 16 = 2 * 8 所以要乘以2 */
}
}
if (i)
{
FL_FLASH_PageErase(FLASH, fwaddr);
for(int j=0;j<i;j++){
FL_FLASH_Program_Word(FLASH, fwaddr, g_iapbuf[j]);
fwaddr +=4; /* 将最后的一些内容字节写进去 */
}
}
}
以上代码将串口接收到的数据存入一个2K大小的数据,再一起写入flash,若数据量比较大的情况,可以配合上位机分批写入。