STM32 QSPI interface address in Dual-Flash memory mode

Dual Bank Flash on STM32L476

前言

因Firmwave更新時我們期望原先運行的程式不會因此停止,所以這邊就要開創Dual Bank Flash的功能,一邊再下載更新Firmwave另一邊執行原先運行程式,最後再比對F/W version選擇最新的,就跳到該Bank開機

Flash

快閃記憶體,係一種EEPROM嘅形式,可以喺操作中多次擦寫嘅記憶體。呢種科技主要用喺一般性資料儲存,同埋喺電腦同其他數碼產品之間交換傳輸資料,例如記憶卡USB手指。快閃記憶體係一種特殊嘅、以大區塊抹寫嘅EEPROM。早期嘅快閃記憶體進行一次抹除,就會清嗮全部喺晶片上嘅資料。

快閃記憶體嘅成本遠比可以位元組為單位寫入嘅EEPROM低[1],亦因為咁成為咗非揮發性固態儲存最重要亦最廣為採納嘅技術。PDA、手提電腦、數碼隨身聽、數碼相機同埋手機上都有用到快閃記憶體。另外,快閃記憶體喺遊戲主機上嘅採用亦都越嚟越多,取代咗儲存遊戲資料用嘅EEPROM或者帶有電池嘅SRAM

雙bank IAP原理

STM32部分型號有提供雙BANK功能,簡單說就是把Flash切割成2區塊BANK1與BANK2。
。當在bank1中運行app時就可以把新更新的固件寫入到bank2,寫完以後就切換到從bank2啟動運行新的app。如果當前在bank2運行就把新固件寫入bank1,寫完以後切換從bank1啟動。

如何判別與開啟Dual Bank Flash

首先在Datasheet裡面查看第一頁Memories是否存在2 bank(這邊以STM32L476/STM32L073為例),如果沒有會寫single bank Flash

開啟2 bank首先開啟STM32CubeProgrammer把下圖BFB2打勾(L476為例,L073基本上就是daul bank不用特別開啟)

STM32F4 / G4 / G0 / L4 / L0  在SystemInit() 沒有重設Vector table , 當你使用Dual bank ,  並轉跳Bank之後,   產生中斷會導致系統異常 . 建議要將” USER_VECT_TAB_ADDRESS” 打開  (default 是disable) , 如此進到SystemInit()之後才會重置Vector table .

what is UFB?

這是存在於SYSCFG寄存器中的一個位,它有兩個值:0或者1,功能是

  • 0:FLASH bank1 被映射在0x8000000地址上
  • 1:FLASH bank2 被映射在0x8000000地址上

這個為主要是去切換BANK的主要判斷,下2張圖為不同BANK啟動流程

Bank圖解

BANK1啟動流程

BANK2啟動流程

由上圖可以看到Bank2會映射到0x8000000起始地址上,因此如果Bank2寫Flash在地址0x08090000上實際上用CudePrg看是在0x08010000地址上,而Bank1有無映射都是相同的因此讀Flah與寫入Flash都是跟一般模式相同。知道此原理後Bank2可以去讀取Bank1數值而Bank1可以去讀取Bank2存取數值了~

範例coding參考

下面是L476給的範例程式所初始化部分

void toggleBankAndReset() {
    FLASH_OBProgramInitTypeDef OBInit;
    HAL_FLASH_Unlock();
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
    HAL_FLASH_OB_Unlock();
   <mark style="background-color:rgba(0, 0, 0, 0);color:#09ed1b" class="has-inline-color"> /* Get the Dual boot configuration status */</mark>
   <mark style="background-color:rgba(0, 0, 0, 0);color:#eb0c0c" class="has-inline-color"> HAL_FLASHEx_OBGetConfig(&OBInit);
   </mark><mark style="background-color:rgba(0, 0, 0, 0);color:#0ceb16" class="has-inline-color"> /* Enable/Disable dual boot feature */</mark><mark style="background-color:rgba(0, 0, 0, 0);color:#eb0c0c" class="has-inline-color">
    OBInit.OptionType = OPTIONBYTE_USER;
    OBInit.USERType = OB_USER_BFB2;</mark>

    if (((OBInit.USERConfig) & (OB_BFB2_ENABLE)) == OB_BFB2_ENABLE) {
        OBInit.USERConfig = OB_BFB2_DISABLE;
    } else {
        OBInit.USERConfig = OB_BFB2_ENABLE;
    }
    if (HAL_FLASHEx_OBProgram(&OBInit) != HAL_OK) {
        // uint32_t errorCode = HAL_FLASH_GetError();
        while (1) {
        	          BSP_LED_On(LED2);
        	          HAL_Delay(500);
        	          BSP_LED_Off(LED2);
        	          HAL_Delay(500);
        }
    }
    if (HAL_FLASH_OB_Launch() != HAL_OK) {
        //uint32_t errorCode = HAL_FLASH_GetError();
        while (1) {
        	 BSP_LED_On(LED2);
        	          HAL_Delay(500);
        	          BSP_LED_Off(LED2);
        	          HAL_Delay(500);
        }
    }
    HAL_FLASH_OB_Lock();
    HAL_FLASH_Lock();
}

下面是確認是在哪個bank部分

uint8_t getActiveBank() {
    volatile uint32_t remap = READ_BIT(SYSCFG->MEMRMP, 0x1 << 8);
    return remap == 0 ? 1 : 2;
}

燒入方式

這邊燒入方式需要注意因為CubeIDE目前來看無法直接從0x08080000開始燒入,因此會借助cubeProgrammer使用bin檔燒入方法如下

  1. 先清除全部Flash內存
  2. 紅框處為燒入點選按鈕
  3. 籃框為選擇要燒入的Bin檔(這邊要先燒Bank2,因此先從0x08080000開始燒入)
  4. 綠框為燒入啟始位置
  5. 檢查0x08080000是否燒入成功
  6. 檢查0x08000000是否還是FF
  7. 修正燒入起始位置重覆步驟2~4燒入Bank1
  8. 檢查全部內容是否燒入成功

Leave a Comment

Your email address will not be published. Required fields are marked *

Shopping Cart