痞子衡嵌入式:飛思卡爾Kinetis系列MCU啟動那些事(3)- KBOOT配置(FOPT/BOOT Pin/BCA)

痞子衡發表於2017-04-08

  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是飛思卡爾Kinetis系列MCU的KBOOT配置

  KBOOT是支援配置功能的,配置功能可分為兩方面:一、晶片系統的啟動配置;二、KBOOT特性配置;痞子衡在前一篇文章裡介紹了 KBOOT形態(ROM/Bootloader/Flashloader),雖然KBOOT有三種形態,但實際上只有2種型別的晶片載體,即含ROM空間的晶片(比如Kinetis K80)和不含ROM空間的晶片(比如Kinetis KL25),KBOOT配置在這兩種載體上是有區別的,下面痞子衡為大家詳解KBOOT配置:

一、啟動配置:FTFx_FOPT, BOOT Pin, RCM_FM

  晶片系統的啟動配置主要決定的是晶片上電從哪裡(ROM/Flash)開始啟動,所以這個啟動配置對於含ROM空間的晶片特別重要,而不適用於不含ROM空間的晶片。

1.1 啟動方式選擇Flash Configuration Field - FOPT

  熟悉Kinetis晶片的朋友肯定知道,Kinetis晶片都是含內部Flash的,內部Flash起始地址一般是0x00000000,Flash操作是通過FTFx這個IP模組實現的,如果你對FTFx模組瞭解的話,這個IP模組內部其實有一些暫存器屬性是readonly的,並且從手冊裡看這些readonly暫存器的初值是undefined,擷取K80晶片FTFA模組中這些readonly暫存器如下:

痞子衡嵌入式:飛思卡爾Kinetis系列MCU啟動那些事(3)- KBOOT配置(FOPT/BOOT Pin/BCA)
痞子衡嵌入式:飛思卡爾Kinetis系列MCU啟動那些事(3)- KBOOT配置(FOPT/BOOT Pin/BCA)
痞子衡嵌入式:飛思卡爾Kinetis系列MCU啟動那些事(3)- KBOOT配置(FOPT/BOOT Pin/BCA)

  既然這些暫存器是readonly屬性並且初值又是undefined的,那麼其初值到底取決於什麼?這裡就涉及到Kinetis晶片中比較特別的FCF載入機制,FCF即Flash Configuration Field,其區域地址為Flash偏移0x400 - 0x40f,一共16個bytes,這16bytes內容組織如下:

痞子衡嵌入式:飛思卡爾Kinetis系列MCU啟動那些事(3)- KBOOT配置(FOPT/BOOT Pin/BCA)

  任何一次熱啟動後,晶片系統會自動從FCF區域載入初值進FTFx相應暫存器中,我們主要關注的是跟啟動配置相關的FTFx_FOPT暫存器(特別注意,當FCF中對應FOPT的值是無效值0x00時,在載入過程中晶片自動會給FOPT賦值0xFF),下面是FTFx_FOPT暫存器的bit定義,其中BOOTSRC_SEL和BOOTPIN_OPT位是關鍵(注意這兩個位在不含ROM空間的晶片上是reserved的)。

痞子衡嵌入式:飛思卡爾Kinetis系列MCU啟動那些事(3)- KBOOT配置(FOPT/BOOT Pin/BCA)

  BOOTSRC_SEL和BOOTPIN_OPT的值共同決定了晶片的啟動位置(ROM/Flash):

  • BOOTPIN_OPT = 1: 啟動位置完全由BOOTSRC_SEL決定。
  • BOOTPIN_OPT = 0: 啟動位置由BOOTSRC_SEL和BOOTCFG0 pin共同決定。

  因此當在FCF裡指定FOPT為0xFF時,晶片上電永遠從ROM啟動;當在FCF裡指定FOPT為0x3F時,晶片上電永遠從Flash啟動。

1.2 啟動位置切換BOOT Pin

  在1.1節的最後痞子衡提到了BOOTCFG0 pin,其實BOOTCFG0 pin對於含ROM空間晶片而言就是BOOT Pin,這個BOOT Pin是晶片系統直接指定的,與NMI pin複用(在上電以及ROM執行過程中,NMI pin原本中斷功能是被遮蔽的)。
  你一定會疑惑BOOT pin有什麼用?讓我們再回到1.1節的最後,0x3F和0xFF是兩種比較典型的FOPT啟動配置值,但是這種配置值指定的是固定啟動位置,除非你擦除FCF重新燒寫,不然無法輕易改變啟動位置。但是有的時候我們想在不擦除FCF情況下自由切換啟動位置ROM/Flash,這時候就得依靠BOOT Pin,此時我們需要在FCF裡指定FOPT為0x3D,讓我們結合下面的TWR-K80F150M原理圖來說明:

痞子衡嵌入式:飛思卡爾Kinetis系列MCU啟動那些事(3)- KBOOT配置(FOPT/BOOT Pin/BCA)

  在上述TWR-K80F150M原理圖中,我們可以看到兩個按鍵開關(SW2,SW1)分別連到了K80晶片的NMI_b pin和RESET_b pin,當我們配置FOPT為0x3D時,即啟動位置由BOOTSRC_SEL(2'b00,即從Flash啟動)和BOOTCFG0(NMI)共同決定,如果在RESET_b pin(SW1)按下復位過程中,BOOTCFG0 pin(SW2)一直被按下,那麼晶片會從ROM啟動(並且超時也不會跳轉到Application);而如果BOOTCFG0 pin(SW2)沒有被按下,那麼晶片會從Flash啟動。是不是瞬間覺得這樣切換啟動位置很方便!
  其實BOOT Pin設計不僅僅只在含ROM空間的晶片上存在,在不含ROM空間的晶片上也支援,只不過在不含ROM空間的晶片上,BOOT Pin是由Bootloader程式碼指定的(需要檢視晶片手冊Bootloader章節或原始碼),我們知道當晶片不含ROM時,上電預設從Flash起始地址處啟動,而Flash起始地址已被Flash-Resident Bootloader佔據,所以上電永遠執行Flash-Resident Bootloader,此時BOOT Pin的意義主要是決定是否要超時跳轉到Application,如果BOOT Pin在RESET_b pin按下復位過程中一直被按下,那麼晶片將會一直停留在Bootloader中;如果BOOT Pin沒有被按下,那麼晶片在執行Bootloader超時時間到了之後會跳轉到Application。

1.3 強制從ROM熱啟動RCM_FM

  我們知道晶片復位啟動分為冷啟動(POR Pin)和熱啟動(RESET_b Pin),冷啟動是最為徹底的啟動(所有暫存器初值全部重置),而熱啟動並不是徹底啟動(有些暫存器初值不會重置),RCM模組裡有1個暫存器(RCM_FM)就只有冷啟動才能被重置,而且這個暫存器與從ROM啟動息息相關,不得不提。下面是RCM_FM和RCM_MR暫存器的bit定義:

痞子衡嵌入式:飛思卡爾Kinetis系列MCU啟動那些事(3)- KBOOT配置(FOPT/BOOT Pin/BCA)

痞子衡嵌入式:飛思卡爾Kinetis系列MCU啟動那些事(3)- KBOOT配置(FOPT/BOOT Pin/BCA)

  上述兩個暫存器只在含ROM空間的晶片上存在,其作用是為了保證ROM在執行期間即使不小心發生熱啟動,下一次還是會強制執行ROM程式,而不受FOPT, BOOT Pin狀態變化影響。ROM程式裡操作RCM_FM/MR暫存器使能了這一強制ROM啟動功能,具體程式碼如下:

// ROM statrup過程中呼叫的函式
void SystemInit (void)
{
    // ...

    // Set Force ROM bits in RCM. We only set bit 2, so the RCM_MR register doesn't
    // falsely show that the ROM was booted via boot pin assertion.
    RCM->FM = RCM_FM_FORCEROM(2);

    // ...
}

// ROM跳轉到Application之前呼叫的函式
void shutdown_cleanup(bool isShutdown)
{
    // ...

    // Disable force ROM.
    RCM->FM = RCM_FM_FORCEROM(0);

    // Clear status register (bits are w1c).
    RCM->MR = RCM_MR_BOOTROM(3);

    // ...
}

  因為ROM裡有了上述程式碼,所以只要晶片上電執行過ROM程式,除非是ROM主動跳轉到了Application或者發生了冷啟動,否則任何與ROM有關的配置修改操作都不會影響到下一次啟動ROM的執行,這種機制可以確保Application一定會被ROM下載進Flash。

二、特性配置:BCA

  除了啟動配置外,KBOOT還支援特性配置,我們知道KBOOT提供的特性功能非常多,比如支援的外設種類豐富、超時時間可設、Application完整性校驗、USB ID可設、執行時鐘可配、加密特性支援、QSPI啟動支援,這些特性可以通過BCA來配置,BCA是Bootloader Configuration Area的簡稱,KBOOT通過從BCA區域載入使用者配置資料完成這些特性配置。BCA配置結構體原型如下(以K80晶片為例):

//! @brief Format of bootloader configuration data on Flash.
typedef struct BootloaderConfigurationData
{
    uint32_t tag;                          //!< [00:03] Tag value used to validate the BCA data. Must be set to 'kcfg'.
    uint32_t crcStartAddress;              //!< [04:07]
    uint32_t crcByteCount;                 //!< [08:0b]
    uint32_t crcExpectedValue;             //!< [0c:0f]
    uint8_t enabledPeripherals;            //!< [10:10]
    uint8_t i2cSlaveAddress;               //!< [11:11]
    uint16_t peripheralDetectionTimeoutMs; //!< [12:13] Timeout in milliseconds for peripheral detection before jumping to application code
    uint16_t usbVid;                       //!< [14:15]
    uint16_t usbPid;                       //!< [16:17]
    uint32_t usbStringsPointer;            //!< [18:1b]
    uint8_t clockFlags;                    //!< [1c:1c] High Speed and other clock options
    uint8_t clockDivider;                  //!< [1d:1d] One's complement of clock divider, zero divider is divide by 1
    uint8_t bootFlags;                     //!< [1e:1e] One's complemnt of direct boot flag, 0xFE represents direct boot
    uint8_t pad0;                          //!< [1f:1f] One's complemnt of direct boot flag, 0xFE represents direct boot
    uint32_t mmcauConfigPointer;           //!< [20:23] Holds a pointer value to the MMCAU configuration
    uint32_t keyBlobPointer;               //!< [24:27] Holds a pointer value to the key blob array used to configure OTFAD
    uint8_t reserved[8];                   //!< [28:2f] Reserved.
    uint32_t qspi_config_block_pointer;    //!< [30:33] QSPI config block pointer.
} bootloader_configuration_data_t;

  如果你想配置KBOOT的特性,必須按上述結構體格式準備好配置資料,具體資料值所代表含義請檢視晶片手冊Bootloader章節,痞子衡在後續文章裡也會慢慢講到。此處假設你已經準備好了BCA資料,那麼這個BCA資料應該放在哪裡呢?其實KBOOT已經指定好了BCA位置,見如下程式碼,BCA起始地址固定在APP_VECTOR_TABLE地址偏移0x3c0處,對於ROM Bootloader而言,BCA地址就是0x3c0,因為APP_VECTOR_TABLE=0;而對於Flash-Resident Bootloader而言,BCA地址是Bootloader指定的Application起始地址偏移0x3c0處。

//! @brief Flash constants.
enum _flash_constants
{
    //! @brief The bootloader configuration data location .
    //!
    //! A User Application should populate a BootloaderConfigurationData
    //! struct at 0x3c0 from the beginning of the application image which must
    //! be the User Application vector table for the flash-resident bootloader
    //! collaboration.
    kBootloaderConfigAreaAddress = (uint32_t)(APP_VECTOR_TABLE) + 0x3c0
};

  最後再解釋一下BCA地址為何是APP_VECTOR_TABLE + 0x3c0,我們知道ARM Cortex-M系統規定Application前1KB(0x0 - 0x3FF)應放中斷向量表,Cortex-M最大支援256箇中斷,其中前16個是系統中斷,後240個是外設中斷,而Cortex-M廠商生產的晶片一般用不滿240個外設中斷,所以其實中斷向量表後半部分其實是reserved的,因此我們可以把reserved區域裡的0x3C0 - 0x3FF這64bytes用作BCA配置。

  至此,飛思卡爾Kinetis系列MCU的KBOOT配置痞子衡便介紹完畢了,掌聲在哪裡~~~

相關文章