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編程完成上位機
完成效果如下