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

使用单片机平台: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)
  }
}

你可能感兴趣的:(单片机类)