大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是飛思卡爾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寄存器如下:



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

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

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原理圖來說明:

在上述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定義:


上述兩個寄存器只在含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配置痞子衡便介紹完畢了,掌聲在哪里~~~
歡迎訂閱
文章會同時發布到我的 博客園主頁、CSDN主頁、微信公眾號 平台上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。