单片机利用bootloader阶段对app进行升级的方案

2019-04-15 18:43发布

使用单片机平台:MT031, 32位处理器,最高运行频率72Mhz, 32kb FLASH, 4kb sram。 目标:在该平台上实现bootloader+app的软件结构,bootloader和app分阶段加载,bootloader阶段负责检查需不需要对APP进行固件升级,升级的固件由CAN总线发送过来,然后写入app的固件地址即可。 遇到的问题:该单片机的中断向量表固定在flash的0x0地址,app工程的中断无法响应。 解决思路:bootloader阶段不使用任何中断(reset中断除外),bootloader启动app之前先拷贝app的中断向量表覆盖到bootloader的中断向量表。这样APP阶段使用的中断就能正常响应。
拷贝方式如下: #define jump_addr FIRMWARE_START_ADDERSS __align(4) uint32_t * code_buffer; __align(4) uint8_t code_buf[512] = {0}; void update_rom(void) { int i, flag = 0; code_buffer = (uint32_t *)code_buf; if (((*(volatile uint32_t *)(jump_addr)) & 0x2FFF0000) != 0x20000000){ return; } for (i=1; i<48; i++){ if ((*(volatile uint32_t *)(jump_addr+ i*4)) > 0x8000){ return; } } for (i=8; i<192; i++){ if ((*(volatile uint8_t *)(i)) != (*(volatile uint8_t *)(jump_addr+i))) { flag = 1; } } if (flag){ for (i=0; i<48; i++){ code_buffer[i] = *(volatile long *)(jump_addr + i*4); } for (; i<128; i++){ code_buffer[i] = *(volatile long *)(0 + i*4); } code_buffer[0] = *(volatile long *)(0); code_buffer[1] = *(volatile long *)(4); FLASH_FlushCacheCmd(ENABLE); //刷新Cache FLASH_FlushCacheCmd(DISABLE); //刷新Cache FLASH_CacheCmd(DISABLE); //关闭Cache FLASH_FlushCacheCmd(ENABLE); //刷新Cache FLASH_FlushCacheCmd(DISABLE); //刷新Cache FLASH_Unlock(); delay_ms(1); FLASH_EraseSector(0); FLASH_ProgramData((uint32_t *)code_buffer, 0, 0x200); FLASH_Lock(); FLASH_CacheCmd(ENABLE); //使能Cache } } 解释:
if(flag)前的代码是一些检查动作
1.检查app的运行地址是否是ram。
2.检查app的中断向量表是否指向了不合法的空间,flash 32KB==0x8000
3.检查是否已经拷贝过一次,这样就不用每次启动都拷贝,影响flash的使用寿命
后面是拷贝中断向量表的动作,这里code_buffer是一个flash 的sector大小,拷贝前48个指针,但是第一个和第二个指针不拷贝,因为第一个地址指向栈地址,第二个指针指向reset中断,这两个指针不需要指向APP的地址,其他的46个中断分别指向芯片架构不同的中断,芯片手册可以查到。后面的flash内容不变。然后是写入flash中。 以上就完成了拷贝动作;
然后就可以直接跳转到APP阶段运行了 /* *Addr;flash addr where do you want to be load */ void CAN_BOOT_JumpToApplication(__IO uint32_t Addr) { pFunction Jump_To_Application; __IO uint32_t JumpAddress; if (((*(__IO uint32_t*)Addr) & 0x2FFE0000 ) == 0x20000000) { JumpAddress = *(__IO uint32_t*) (Addr + 4); Jump_To_Application = (pFunction) JumpAddress; __set_MSP(*(__IO uint32_t*)Addr); Jump_To_Application(); } } 注意事项:为了不影响bootloader阶段拷贝动作的正常运行,可以把bootloader的代码分区存放,这里我们把bootloader的flash分为rom1和rom2,rom1是我们刚才拷贝的一个sector的大小512字节,用来存放中断向量表,拷贝flash的代码运行地址要配置成ram。 ; ************************************************************* ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* LR_IROM1 0x00000000 0x0000200 { ; load region size_region ER_IROM1 0x00000000 0x0000200 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) } } LR_IROM2 0x0000200 0x00001e00 { ; load region size_region ER_IROM2 0x00000200 0x00001e00 { ; load address = execution address .ANY (+RO) } RW_IRAM1 0x20000000 0x00000c00 { ; RW data .ANY (+RW +ZI) } RW_IRAM2 0x20000c00 0x00000400 { mt031x_flash.o (+RO) } }