从串口接收到hex文件的一行,校验后调用以下函数写入FLASH。以下是简单的一个写入流程
@ CSDN Tyrion.Mon
void UpgradeAPP(xxx)
{
uint16_t i = 0;
uint16_t line_data_len = xxx; //数据域长度
static uint32_t base_addr = 0;
uint32_t offset_addr = 0x0000ffff & xxx; //偏移地址
uint32_t write_addr = 0;
static uint32_t has_erase_page = 0;
uint32_t need_erase_page = 0;
static bool APP_StartAddr_OK = false;
uint8_t line_type = xxx;
switch (line_type) //行数据类型
{
case 4: //指定基地址
base_addr = xxx;
base_addr = (base_addr << 16) & 0xffff0000;
【解锁FLASH】
break;
case 0: //写入Flash的数据
write_addr = base_addr | offset_addr;
if (APP_StartAddr_OK == false && ((APP_LOADED_ADDR + 0x08000000) == write_addr))
{
APP_StartAddr_OK = true; //APP Flash首地址正确
}
if (APP_StartAddr_OK == true)
{
for (i = 0; i < line_data_len; i += 4)
{
need_erase_page = ((write_addr + i) - 0x08000000) / 2048; //算出当前地址所在页,2K每页
if (need_erase_page != has_erase_page)
{
has_erase_page = need_erase_page;
【擦除该页】
}
【向指定地址以整字方式写入FLASH,或者接收到一页的量后采用页编程方式写入】
【读出对比】
printf("%x, ", *((volatile uint32_t *)(write_addr + i)));
}
printf("\r\n");
}
break;
case 1: //文件结束
【FLASH上锁】
break;
default:
break;
}
}
跳转APP后的处理
/* 基地址 */
#define NVIC_VECTTAB_RAM ((uint32_t)0x20000000) /*!< RAM */
#define NVIC_VECTTAB_FLASH ((uint32_t)0x08000000) /*!< Flash */
/* NVIC中断向量表偏移掩码 */
#define NVIC_VECTTAB_OFFSET_MASK ((uint32_t)0x1FFFFF80)
#define USER_BOOT_EXIST 1 //是否有bootloader
#define VECT_TAB_OFFSET 0x5000 //
#if (USER_BOOT_EXIST == 1)
/* APP中断向量表地址偏移 需要在Linker选项卡勾选“USE Memory Layout from Target Dialog”,并修改Target选项卡中的ROM的Start地址 */
nvic_vector_table_set(NVIC_VECTTAB_FLASH, VECT_TAB_OFFSET);
__enable_irq(); //解除中断屏蔽
#endif
@ CSDN Tyrion.Mon
void nvic_vector_table_set(uint32_t nvic_vict_tab, uint32_t offset)
{
SCB->VTOR = nvic_vict_tab | (offset & NVIC_VECTTAB_OFFSET_MASK);
}
如果在Bootloader跳转APP前就设置了中断向量偏移,则略过。 NVIC_VECTTAB_OFFSET_MASK掩码为0x1FFFFF80是因为VTOR寄存器的格式
APP地址偏移不能随意,CortexM3 M4权威指南中有如下描述。且还要关注该型号单片机的Flash每页大小,因为写Flash时需要整页擦除,须避免APP和Bootloader代码在同一页。
页:
1
[2]