2020年3月3日星期二

[STM32] M0 系列的 IAP 程式跳轉-1

STM32 IAP

之前有個案子指定要使用 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 等程式。 這次的例子先做如何跳轉到主程式段。以下是開始修改程式過程。


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 檔案。尋找下列文字

/* 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="">

複製 vector table 內容到 SRAM。關於 vector table 部分,在這裡算是一段落。我找出 datasheet 裡部分內容,因為表格太長就截最後一段。可能會因為型號不同而有所不同,遇到不同的在這裡做調整。


最後, 在 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:

發佈留言