0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

深入i.MXRT1050系列ROM中串行NOR Flash啟動初始化流程

冬至子 ? 來源:痞子衡嵌入式 ? 作者:痞子衡 ? 2023-06-02 17:43 ? 次閱讀

一、整體初始化流程

我們知道外部串行NOR Flash是接到i.MXRT的FlexSPI外設(shè)引腳上,有時(shí)串行NOR Flash啟動也叫FlexSPI NOR啟動。關(guān)于FlexSPI NOR啟動流程,i.MXRT1050參考手冊System Boot章節(jié)有如下流圖,藍(lán)框之外的流程屬于常規(guī)i.MXRT啟動XIP App流程,是個(gè)通用流程。藍(lán)框之內(nèi)才是具體FlexSPI初始化步驟,這個(gè)步驟概括得比較精煉。

圖片

為了讓大家對FlexSPI NOR設(shè)備啟動初始化流程有個(gè)更具體的概念,痞子衡重新畫了一張更詳細(xì)的流程圖,圖中灰底框里描述得是FlexSPI初始化流程,痞子衡將其分解成了六步,我們有必要深入這六步初始化流程。

圖片

二、分解初始化流程

2.1 復(fù)位Flash芯片(可選)

第一步是嘗試復(fù)位Flash芯片,這步是可選的,在fuse_0x6e0[7]里配置,默認(rèn)是不使能的。復(fù)位Flash目的是為了讓Flash處于一個(gè)確定的初始狀態(tài),方便i.MXRT BootROM去配置訪問。為什么要強(qiáng)調(diào)Flash的初始狀態(tài),因?yàn)楹芏鄷r(shí)候i.MXRT未必是冷啟動(上電啟動),也有可能是軟復(fù)位啟動(比如調(diào)用NVIC_SystemReset),這時(shí)候外部Flash已經(jīng)被軟復(fù)位前執(zhí)行過的BootROM甚至用戶App配置過,因此Flash的狀態(tài)可能不是上電初始狀態(tài)(一般來說板級設(shè)計(jì)里Flash的RESET#引腳要么懸空,要么連接i.MXRT的POR#引腳),這可能會影響軟復(fù)位后BootROM去再次配置啟動這塊不定態(tài)的Flash。

fuse 0x6e0[7] - FLEXSPI_RESET_PIN_EN

圖片

正常的Flash都提供了RESET#引腳來實(shí)現(xiàn)跟上電復(fù)位一樣的功能,對于普通8-pin的QSPI Flash,這個(gè)RESET#引腳往往是跟信號線IO3復(fù)用的(僅在QE bit沒使能情況下有效),而對于16-pin的QSPI Flash或者HyperFlash,其RESET#引腳都是獨(dú)立的。

圖片

BootROM就是借助了Flash的RESET#引腳來實(shí)現(xiàn)的復(fù)位操作,實(shí)現(xiàn)代碼比較簡單,i.MXRT1050 BootROM直接指定了GPIO1[9]當(dāng)做復(fù)位信號線,板級設(shè)計(jì)里需要你將GPIO1[9]連到Flash的RESET#引腳,然后BootROM就是簡單地拉低GPIO1[9]即可。RESET#信號都是低電平有效,BootROM直接拉低這個(gè)信號持續(xù)250us,這個(gè)低電平持續(xù)時(shí)間對于復(fù)位來說是夠夠的,很多Flash數(shù)據(jù)手冊里其實(shí)僅要求幾u(yù)s即可。

  • 備注:對于BootROM的Flash復(fù)位功能來說,主要適用有獨(dú)立RESET#引腳的Flash。
#define RESET_PAD_IDX       kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_09
#define RESET_PIN_MUX       IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(5)
#define RESET_PIN_GPIO      GPIO1
#define RESET_PIN_INDEX     9

if ((OCOTP- >MISC_CONF1 & 0x80) > > 7)
{
    // Set pinmux as GPIO
    IOMUXC- >SW_MUX_CTL_PAD[RESET_PAD_IDX] = RESET_PIN_MUX;
    // Set GPIO to output mode
    RESET_PIN_GPIO- >GDIR |= (1U<

2.2 準(zhǔn)備初始FDCB配置塊

第二步是準(zhǔn)備一個(gè)初始的FDCB配置塊(即flexspi_nor_config_t,大小為512字節(jié)),這個(gè)初始FDCB配置塊將被用來做FlexSPI外設(shè)的第一次初始化,目的是為了能夠保證FlexSPI初始化之后CPU能夠使用AHB方式正常讀取Flash(訪問性能不要求最高,但求穩(wěn)定訪問)。這個(gè)初始FDCB并不是一個(gè)完全定死的配置塊,部分值也是根據(jù)fuse來配置的,一共有三處fuse位置,其中最重要的是FLASH_TYPE:

fuse 0x440[20]    - QSPI_2ND_BOOTPIN_ENABLE,決定是否啟動第二組FlexSPI pinmux
fuse 0x450[10:8]  - FLASH_TYPE,決定當(dāng)前連接的Flash類型
fuse 0x470[30:24] - DELAY_CELL_NUM,設(shè)置Flash讀訪問時(shí)序數(shù)據(jù)線有效時(shí)間

圖片

初始FDCB配置塊中僅給memConfig設(shè)了值,這個(gè)memConfig才是用于配置FlexSPI外設(shè)本身。如下部分賦值是固定的FDCB設(shè)置,不受fuse影響,從這個(gè)固定配置你可以看到,BootROM假定了所有外接Flash都是128MB,且訪問時(shí)鐘(SCK)速度能支持30MHz,不要對這個(gè)假定感到焦慮,它只是用于FlexSPI第一次初始化,目的只求能正常訪問Flash前4KB即可:

flexspi_nor_config_t config;
memset(config, 0, sizeof(config));

// 公共的FDCB配置
config.memConfig.tag           = FLEXSPI_CFG_BLK_TAG;
config.memConfig.version       = FLEXSPI_CFG_BLK_VERSION;
config.memConfig.deviceType    = kFlexSpiDeviceType_SerialNOR;
config.memConfig.sflashA1Size  = 128UL*1024*1024;
config.memConfig.serialClkFreq = kFlexSpiSerialClk_30MHz;
config.memConfig.dataHoldTime  = 3;
config.memConfig.dataSetupTime = 3;
config.memConfig.timeoutInMs   = 1000;

然后便是從fuse里獲取flashType,根據(jù)具體flashType來對初始FDCB配置塊做進(jìn)一步動態(tài)賦值,這進(jìn)一步賦值才用于區(qū)分不同F(xiàn)lash種類(Pad數(shù)量、DQS信號屬性、最重要的lookupTable等)。

// 從fuse里獲取flash類型
uint32_t flashType;
if ((OCOTP- >CFG3 & 0x100000) > > 20)
{
    flashType = 7;
}
else
{
    flashType = (OCOTP- >CFG4 & 0x700) > > 8;
}

圖片

上圖中最重要的FDCB賦值是config.memConfig.lookupTable,它是FlexSPI外設(shè)需要的核心配置,有了這個(gè)配置,CPU便可以直接從AHB總線讀取Flash的內(nèi)容,因?yàn)镕lexSPI會自動解析AHB總線讀請求然后翻譯成具體FlexSPI讀時(shí)序,底層讀時(shí)序需要的命令、地址字節(jié)數(shù)、DUMMY周期都在lookupTable里。BootROM預(yù)存了如下6大類Flash的lookupTable:

// Dedicated 3Byte Address Read(0x03), 24bit address
static const uint32_t s_dedicated3bRead[4]   = {
    FLEXSPI_LUT_SEQ(CMD_SDR,  FLEXSPI_1PAD, 0x03, RADDR_SDR, FLEXSPI_1PAD, 0x18),
    FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x04, STOP,      FLEXSPI_1PAD, 0),
    0,
    0
};

// Dedicated 4Byte Address Read(0x13), 32 bit address
static const uint32_t s_dedicated4bRead[4]   = {
    FLEXSPI_LUT_SEQ(CMD_SDR,   FLEXSPI_1PAD, 0x13, RADDR_SDR, FLEXSPI_1PAD, 0x20),
    FLEXSPI_LUT_SEQ(READ_SDR,  FLEXSPI_1PAD, 0x04, STOP,      FLEXSPI_1PAD, 0),
    0,
    0
};
// HyperFlash Read
static const uint32_t s_hyperflashRead[4]    = {
    FLEXSPI_LUT_SEQ(CMD_DDR,   FLEXSPI_8PAD, 0xA0, RADDR_DDR,      FLEXSPI_8PAD, 0x18),
    FLEXSPI_LUT_SEQ(CADDR_DDR, FLEXSPI_8PAD, 0x10, DUMMY_RWDS_DDR, FLEXSPI_8PAD, 0x0c),
    FLEXSPI_LUT_SEQ(READ_DDR,  FLEXSPI_8PAD, 0x04, STOP,           FLEXSPI_8PAD, 0),
    0
};

// MXIC Octal DDR read
static const uint32_t s_mxicOctDdrRead[4]    = {
    FLEXSPI_LUT_SEQ(CMD_DDR,   FLEXSPI_8PAD, 0xEE, CMD_DDR,   FLEXSPI_8PAD, 0x11),
    FLEXSPI_LUT_SEQ(RADDR_DDR, FLEXSPI_8PAD, 0x20, DUMMY_DDR, FLEXSPI_8PAD, 0xc),
    FLEXSPI_LUT_SEQ(READ_DDR,  FLEXSPI_8PAD, 0x04, STOP,      FLEXSPI_8PAD, 0),
    0
};

// Micron Octal DDR read
static const uint32_t s_micronOctDdrRead[4]  = {
    FLEXSPI_LUT_SEQ(CMD_SDR,   FLEXSPI_8PAD, 0xFD, RADDR_DDR, FLEXSPI_8PAD, 0x20),
    FLEXSPI_LUT_SEQ(DUMMY_DDR, FLEXSPI_8PAD, 0x8,  READ_DDR,  FLEXSPI_8PAD, 0x04),
    0,
    0
};
// Adesto Octal DDR read
static const uint32_t s_adestoOctDdrRead[4]  = {
    FLEXSPI_LUT_SEQ(CMD_SDR,   FLEXSPI_8PAD, 0x0B, RADDR_DDR, FLEXSPI_8PAD, 0x20),
    FLEXSPI_LUT_SEQ(DUMMY_DDR, FLEXSPI_8PAD, 0x8,  READ_DDR,  FLEXSPI_8PAD, 0x04),
    0,
    0
};

2.3 第一次FlexSPI初始化

第三步就是利用上述配置完成的初始FDCB塊對FlexSPI外設(shè)進(jìn)行第一次初始化,就是下面代碼,這個(gè)流程跟官方SDK里的flexspi_nor_flash_init()大同小異,這里不予具體展開。如果在這里初始化就返回失敗(這里一般不會失敗,因?yàn)閮H僅是FlexSPI外設(shè)自身初始化,并不涉及操作外部Flash芯片的動作),BootROM則直接退出FlexSPI NOR設(shè)備啟動,轉(zhuǎn)入SDP下載。

#define FLEXSPI_INSTANCE    0
uint32_t instance = FLEXSPI_INSTANCE;

status_t status = flexspi_init(instance, (flexspi_mem_config_t *)(&config));
if (status != kStatus_Success)
{
    return status;
}
flexspi_update_lut(instance, 0, &config.memConfig.lookupTable, 1);

2.4 若干善后工作

上述第一次FlexSPI初始化一般都會成功的,但這并不代表fuse里的flashType等配置跟板子上Flash型號是匹配的,也就是說初始FDCB配置塊此時(shí)還沒有被充分驗(yàn)證其是否適用板載Flash型號。

FlexSPI第一次初始化結(jié)束后,為了保證后續(xù)能正常AHB訪問,BootROM里做了一些善后工作,主要是兩件事:

  1. 做一些訪問前的延時(shí):根絕fuse 0x450[3:2] - HOLD TIME來調(diào)用microseconds_delay()做延時(shí),以使FlexSPI外設(shè)完全準(zhǔn)備好。
  2. 做一次無效AHB訪問:類似這樣的代碼 volatile uint32_t dummy = *(uint32_t *)0x60000000;,無效AHB讀可以使Flash退出continuous read模式

2.5 獲取用戶FDCB配置塊

善后工作結(jié)束之后,此時(shí)CPU應(yīng)該可以通過AHB正常訪問Flash了,這個(gè)階段我們只需要從Flash的偏移0地址處讀取用戶FDCB,驗(yàn)證用戶FDCB是否存在,這里才是對前面初始FDCB配置塊以及第一次FlexSPI外設(shè)初始化的真正考驗(yàn)。

驗(yàn)證用戶FDCB是否存在就是簡單讀取FDCB的前四個(gè)字節(jié)(tag),驗(yàn)證這個(gè)tag是否合法。如果第一次驗(yàn)證tag不成功(有可能是FlexSPI配置不正確,也有可能是用戶FDCB不存在),會嘗試做一次三字節(jié)地址切換到四字節(jié)地址的LUT更新(僅適用QSPI Flash),然后做第二次tag讀取驗(yàn)證,如果此時(shí)還是驗(yàn)證失?。ù蟾怕适遣淮嬖谟脩鬎DCB了),BootROM則直接退出FlexSPI NOR設(shè)備啟動,轉(zhuǎn)入SDP下載。

#define FlexSPI_AMBA_BASE      (0x60000000U)
#define FLASH_BASE             FlexSPI_AMBA_BASE

// 使用三字節(jié)地址的LUT對Flash進(jìn)行初次AHB訪問
flexspi_clear_cache(FLEXSPI_INSTANCE);
flexspi_nor_config_t *pConfig = (flexspi_nor_config_t *)FLASH_BASE;
if (pConfig- >memConfig.tag != FLEXSPI_CFG_BLK_TAG)
{
    // 因?yàn)槟貌坏接脩鬎DCB的tag,嘗試切換使用四字節(jié)地址的LUT
    if (flashType == 0)
    {
        flexspi_update_lut(FLEXSPI_INSTANCE, 0, s_basic4bRead, 1);
    }
    flexspi_clear_cache(FLEXSPI_INSTANCE);
    pConfig = (flexspi_nor_config_t *)FLASH_BASE;
}

// 對Flash進(jìn)行第二次AHB訪問,再次確認(rèn)能否拿到用戶FDCB的tag
if (pConfig- >memConfig.tag != FLEXSPI_CFG_BLK_TAG)
{
    return kStatus_Fail;
}

上面代碼里有flexspi_clear_cache()操作,這個(gè)其實(shí)就是利用FLEXSPI0->MCR0[SWRESET]做一個(gè)外設(shè)級別的軟復(fù)位,另外代碼里還涉及到一個(gè)四字節(jié)地址QSPI Flash的LUT表,即如下所示:

// Basic read with 32bit address
static const uint32_t s_basic4bRead[4]   = {
    FLEXSPI_LUT_SEQ(CMD_SDR,  FLEXSPI_1PAD,  0x03, RADDR_SDR, FLEXSPI_1PAD, 0x20), 
    FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD,  0x04, STOP,      FLEXSPI_1PAD, 0),
    0,
    0
};

2.6 第二次FlexSPI初始化

到了這里,基本代表第一次FlexSPI初始化是正確且可用的,并且能夠拿到有效的用戶FDCB配置塊。這時(shí)候就是利用用戶FDCB配置塊對FlexSPI外設(shè)做第二次初始化,初始化代碼流程跟第一次初始化是一模一樣的。

這個(gè)第二次初始化是非常有必要的,因?yàn)樗从沉擞脩舻恼鎸?shí)需求,用戶FDCB配置塊里會準(zhǔn)確描述板載Flash的全面特性(訪問速度,真實(shí)存儲空間大小,特殊定制LUT等等),這些信息必須由用戶來提供。

需要注意的是,第二次FlexSPI初始化返回成功并不代表用戶FDCB配置塊一定就是正確的,還是那句話,這僅僅是對FlexSPI外設(shè)自身的初始化。后續(xù)常規(guī)App解析流程里才是對這個(gè)用戶FDCB配置塊的真正考驗(yàn)。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • GPIO
    +關(guān)注

    關(guān)注

    16

    文章

    1175

    瀏覽量

    51515
  • AHB總線
    +關(guān)注

    關(guān)注

    0

    文章

    18

    瀏覽量

    9440
  • QSPI接口
    +關(guān)注

    關(guān)注

    0

    文章

    14

    瀏覽量

    3317
收藏 人收藏

    評論

    相關(guān)推薦

    i.MXRTxxx系列ROM靈活的串行NOR Flash啟動硬復(fù)位引腳選擇

    篇非常詳細(xì)的文章 《深入i.MXRT1050系列ROM串行
    發(fā)表于 12-21 06:34

    IAR開發(fā)環(huán)境下i.MXRT串行NOR Flash下載算法設(shè)計(jì)

      大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是IAR開發(fā)環(huán)境下i.MXRT串行NOR Flash下載算法設(shè)計(jì)?! ≡?b class='flag-5'>i.MX
    發(fā)表于 01-26 07:46

    i.MXRT上使能NOR Flash的Continuous read模式在軟復(fù)位后無法正常啟動問題的解決

    串行NOR Flash的Continuous read模式下軟復(fù)位后i.MXRT無法啟動問題解決方案之RESET#》,利用RESET#引
    發(fā)表于 01-26 06:52

    系統(tǒng)時(shí)鐘配置不當(dāng)會導(dǎo)致i.MXRT1xxx系列下OTFAD加密啟動失敗的解決辦法

    型號(RT1050/RT0160/RT1020)的硬件解密外設(shè)名字叫BEE,這個(gè)外設(shè)主要是配合FlexSPI外設(shè)去實(shí)現(xiàn)外接串行NOR Flash在線解密XIP執(zhí)行用的。而到了最近的
    發(fā)表于 02-08 06:09

    FPGA的ROM初始化問題討論

    本文討論FPGA的ROM初始化問題,詳細(xì)介紹mit文件的創(chuàng)建與使用。利用FPGA實(shí)現(xiàn)的ROM只能認(rèn)為器件處于用戶狀態(tài)時(shí)具備ROM功能。使用時(shí)不必要刻意劃分,而
    發(fā)表于 02-08 14:24 ?5409次閱讀
    FPGA的<b class='flag-5'>ROM</b><b class='flag-5'>初始化</b>問題討論

    淺析Keil MDK下串行Flash的下載算法設(shè)計(jì)

    今天給大家介紹的是 Keil MDK 工具下 i.MXRT串行 NOR Flash 下載算法設(shè)計(jì)。 在 i.MXRT 硬件那些事
    的頭像 發(fā)表于 12-23 13:15 ?1318次閱讀

    J-Link工具下i.MXRT串行NOR Flash下載算法設(shè)計(jì)

    大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是 J-Link 工具下 i.MXRT串行 NOR Flash 下載算法設(shè)計(jì)。 一、J-Link 各版本對
    的頭像 發(fā)表于 12-08 10:07 ?943次閱讀

    Flash不支持SFDP,如何下載適用i.MXRT

    大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是導(dǎo)致串行 NOR Flashi.MXRT 下無法正常下載 / 啟動的常
    的頭像 發(fā)表于 10-30 10:30 ?593次閱讀

    i.MXRT系列ROM API設(shè)計(jì)

    的 FlexSPI driver API 可輕松 IAP》、《其實(shí) i.MXRT1050,1020,1015 系列 ROM 也提供了 FlexSPI driver API》 基本把 i.MXR
    的頭像 發(fā)表于 10-30 10:52 ?479次閱讀

    痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU硬件那些事(2.5)- 串行NOR Flash下載算法(IAR EWARM篇)...

      大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是IAR開發(fā)環(huán)境下i.MXRT串行NOR Flash下載算法設(shè)計(jì)?! ≡?b class='flag-5'>i.MX
    發(fā)表于 12-02 09:06 ?7次下載
    痞子衡嵌入式:恩智浦<b class='flag-5'>i</b>.MX RT1xxx<b class='flag-5'>系列</b>MCU硬件那些事(2.5)- <b class='flag-5'>串行</b><b class='flag-5'>NOR</b> <b class='flag-5'>Flash</b>下載算法(IAR EWARM篇)...

    痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU啟動那些事(11.1)- FlexSPI NOR連接方式大全(RT1015/1020/1050)

    非易失性存儲器,因此在系統(tǒng)設(shè)計(jì)時(shí)為i.MXRT搭配一塊存放應(yīng)用程序代碼的存儲器是頭等大事。i.MXRT支持啟動的外部存儲器類型眾多,其中通過FlexSPI接口連接串行
    發(fā)表于 12-06 10:51 ?8次下載
    痞子衡嵌入式:恩智浦<b class='flag-5'>i</b>.MX RT1xxx<b class='flag-5'>系列</b>MCU<b class='flag-5'>啟動</b>那些事(11.1)- FlexSPI <b class='flag-5'>NOR</b>連接方式大全(RT1015/1020/<b class='flag-5'>1050</b>)

    i.MXRT1170上串行NOR Flash雙程序可交替啟動設(shè)計(jì)

    i.MXRT10xx 一樣,這里要聊的還是在一片掛載在 FlexSPI 上的串行 NOR Flash 里做冗余/雙程序設(shè)計(jì),就是下圖中的 image L 和 image H,不涉及
    的頭像 發(fā)表于 04-29 15:23 ?968次閱讀

    i.MXRTxxx系列i.MXRT11xx系列雙程序啟動細(xì)節(jié)差異

    大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是i.MXRT500/600上串行NOR Flash雙程序可交替啟動設(shè)計(jì)。
    的頭像 發(fā)表于 05-06 12:44 ?1976次閱讀

    i.MX RT500/600系列串行NOR Flash雙程序可交替啟動設(shè)計(jì)

    i.MX RT500/600系列串行NOR Flash雙程序可交替啟動設(shè)計(jì)
    的頭像 發(fā)表于 10-27 09:36 ?391次閱讀
    <b class='flag-5'>i</b>.MX RT500/600<b class='flag-5'>系列</b>上<b class='flag-5'>串行</b><b class='flag-5'>NOR</b> <b class='flag-5'>Flash</b>雙程序可交替<b class='flag-5'>啟動</b>設(shè)計(jì)

    恩智浦i.MX RT1060/1010上串行NOR Flash冗余程序啟動設(shè)計(jì)

    恩智浦i.MX RT1060/1010上串行NOR Flash冗余程序啟動設(shè)計(jì)
    的頭像 發(fā)表于 09-26 16:53 ?616次閱讀
    恩智浦<b class='flag-5'>i</b>.MX RT1060/1010上<b class='flag-5'>串行</b><b class='flag-5'>NOR</b> <b class='flag-5'>Flash</b>冗余程序<b class='flag-5'>啟動</b>設(shè)計(jì)