STM32在单片机领域因性价比高受到广大工程师的青睐,笔者最近做了一个STM32 M3内核的BootLoader现在把技术的要点梳理如下:
1、首先是对ROM分区的规划,把ROM划分为BOOT区和APP区,划分在KEIL的sct文件完成。
Boot分区
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00005800 { ; load region size_region
ER_IROM1 0x08000000 0x00005800 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY ;(+RO)
}
IRAM1 0x20000000 0x00004000 { ; RW data
.ANY (+RW +ZI)
*.o (RAMCODE)
ac78xx_eflash.o (+RO +RW)
}
IRAM2 0x20004000 0x00002000 { ; RW data
.ANY (pg_data1)
}
IRAM3 0x20006000 0x00002000 { ; RW data (+RW +ZI)
.ANY (pg_data2)
}
}
APP分区
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08006000 0x00019000 { ; load region size_region
ER_IROM1 0x08006000 0x00019000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY ;(+RO)
}
DATA_FLASH 0x0801f000 0x00001000 { ; load address = execution address
* (flash_data)
}
IRAM1 0x20000000 0x00004000 { ; RW data
.ANY (+RW +ZI)
}
IRAM2 0x20004000 0x00002000 { ; RW data
.ANY (pg_data1)
}
IRAM3 0x20006000 0x00002000 { ; RW data (+RW +ZI)
.ANY (pg_data2)
}
}
KEIL工程选择对应的文件
2、BOOT工作完成后向APP跳转,跳转前要关闭中断,避免单片机跑飞。
void JumpApp(uint32_t ApplicationAddress)
{
uint32_t JumpAddress;
pFunction Jump_To_Application;
__set_FAULTMASK(1);
if (((*(__IO uint32_t *)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
{
/* Jump to user application */
JumpAddress = *(__IO uint32_t *) (ApplicationAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
}
}
3、APP中要调整中断向量表的位置,接收到升级指令时复位进入Bootloader
SCB->VTOR = APP_START_ADDR;
mdelay(20);
__set_FAULTMASK(1);
mdelay(5);
NVIC_SystemReset();
4、在进行擦除、编程FLASH时,要关闭中断和看门狗,避免进入非法中断。
5、在进行BootLoader自身更新时需要将相关代码放入RAM中。
__attribute__((section("RAMCODE")))
void * UserMemCpy(uint8_t * dest, const uint8_t * src, int count)
{
uint8_t * tmp = (uint8_t *) dest;
uint8_t * s = (uint8_t *)src;
while (count--)
*tmp++ = *s++;
return dest;
}
在sct文件中对应
IRAM1 0x20000000 0x00004000 { ; RW data
.ANY (+RW +ZI)
*.o (RAMCODE)
ac78xx_eflash.o (+RO +RW)
}
6、用CAPL编程完成上位机
完成效果如下