之前有個案子指定要使用 STM32 M0 ,而在這個專案上又要有 IAP 功能。雖然 STM32 已經有 Embedded bootloader ,可惜的是不符合實際需求。 實做的時候發現 M0 沒有VTOR 暫存器,這點並沒有像 M3/M4 方便。在這裡做個紀錄
首先,我選定晶片的是 STM32F0xx 系列,在硬體上有三個啟動區塊,透過 Boot0 腳位可以選擇。分別是 Main Flash memory,System memory,Embedded SRAM。雖然如此,有沒有可能透過軟體的方式繞過 Boot0 ?
有的,這也是會提到的部分。
在 Reference manual 提到以下,
簡單說 boot 會從 0x0000 0000 開始,而 Flash memory 為主要的啟動空間 。 0x0000 0000 與 0x0800 0000 可以當成同一個位置。
以下的敘述就是這今天題目的重點。
在程式軟體區塊可以選擇 boot 區塊,必需透過 SYSCFG configuration register 的 MEM_MODE 做設定。M0 並不像 M3/M4 有支援 vector table relocation 。 我們可以在程式段設定不同的開機位置。要做的是要將 vector table 抄寫到 SRAM 裡,並將 SRAM Remap 到 0x0000 0000 的位置。
OK,現在要做 2 個 Project 分別是 IAP 和 主程式。首先是 flash memory 區塊選擇,以這次的例子是 IAP 0x0800 0000 ~ 0x0800 3FFF ,主程式段開始從 0x0800 4000。這個劃分沒有一定是這樣做,但是一定要按照 Sector 區塊做選擇。畢竟 Erase 是以 Sector 為最小單位來算,最好在 Reference manual 確認,因為不同型號有可能不相同。
I
AP 程式段會是 程式下載或接收 及 Flash 相關的 Write 與 Erase 等程式。 這次的例子先做如何跳轉到主程式段。以下是開始修改程式過程。
在 Private variables 區塊加入
在 main() 內加入
IAP 程式段 - Project 1
在 Define 程式段落加入
#define APP_FLASHADDR 0x08004000
typedef void (*JmpFunction)(void);
APP_FLASHADDR 是主程式的 開始位址, JmpFunction 是 function pointer 宣告。在 Private variables 區塊加入
uint32_t JumpAddress;
JmpFunction Jump_To_Application;
在 main() 內加入
uint32_t ApplicationAddress = APP_FLASHADDR;
if(((*(__IO uint32_t*)ApplicationAddress); 0x2FFE0000 ) == 0x20000000)
{
/* Jump to user application */
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
Jump_To_Application = (JmpFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
}
if 判斷式確認是否有程式碼在程式段,如果就執行跳轉的程序。主程式 - Project 2
首先,先編輯 Linker script。找出 STM32xxx.ld 檔案。尋找下列文字
修改成
在最後一行 .ARM.attributes 0 : { *(.ARM.attributes) } 後面再 新增
在 main.c 頭段放入
在 main() 加入
複製 vector table 內容到 SRAM。關於 vector table 部分,在這裡算是一段落。我找出 datasheet 裡部分內容,因為表格太長就截最後一段。可能會因為型號不同而有所不同,遇到不同的在這裡做調整。
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
}
修改成
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000400, LENGTH = 7K
FLASH (rx) : ORIGIN = 0x8004000, LENGTH = 48K
SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 1k
}
在最後一行 .ARM.attributes 0 : { *(.ARM.attributes) } 後面再 新增
.RAMVectorTable : {*(.RAMVectorTable)} >SRAM AT> FLASH
為了要放 Vector table,所以要修改記憶體組織架構
在 main.c 頭段放入
#define APPLICATION_ADDRESS 0x08004000
#if (defined ( __CC_ARM ))
__IO uint32_t VectorTable[188] __attribute__((at(0x20000000)));
#elif (defined (__ICCARM__))
#pragma location = 0x20000000
__no_init __IO uint32_t VectorTable[188];
#elif defined ( __GNUC__ )
__IO uint32_t VectorTable[188] __attribute__((section(".RAMVectorTable")));
#endif
在 main() 加入
/* USER CODE BEGIN 1 */
uint32_t i=0;
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Copy the vector table from the Flash (mapped at the base of the application
load address 0x08004000) to the base address of the SRAM at 0x20000000. */
for(i = 0; i < 188; i++)
{
VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2 code="">2>
最後, 在 Initialize configured peripherals 前,加入
/* Enable the SYSCFG peripheral clock*/
__HAL_RCC_SYSCFG_CLK_ENABLE();
/* Remap SRAM at 0x00000000 */
__HAL_SYSCFG_REMAPMEMORY_SRAM();
以上,跳轉部分已完成。 如果要驗證是否是正常運作,可以在 while loop 加入以下程式。看看是否會直接跳轉到這裡。
HAL_Delay(250);
HAL_GPIO_TogglePin(GPIOC,LD4_Pin);
HAL_Delay(100);
HAL_GPIO_TogglePin(GPIOC,LD3_Pin);
相關連結
M0 系列的 IAP 程式跳轉-2
https://www.makdev.net/2020/03/stm32-m0-iap-2.html
0 comments:
發佈留言