<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      痞子衡嵌入式:導(dǎo)致串行NOR Flash在i.MXRT下無(wú)法正常下載/啟動(dòng)的常見(jiàn)因素之Write Protection


        大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是導(dǎo)致串行NOR Flash在i.MXRT下無(wú)法正常下載/啟動(dòng)的常見(jiàn)因素之Write Protection

        i.MXRT系列MCU發(fā)布已兩年多了,基于i.MXRT的客戶產(chǎn)品也越來(lái)越多,可以說(shuō)是全面開(kāi)花了。痞子衡作為i.MXRT產(chǎn)品線的系統(tǒng)應(yīng)用工程師,早期的時(shí)候還可以盡情做參考設(shè)計(jì),現(xiàn)在基本大量時(shí)間都被客戶支持占據(jù)了。

        因?yàn)閕.MXRT系列都沒(méi)有內(nèi)置Flash(RT1064, RT1024等SIP型號(hào)除外),因此為其搭配一塊串行NOR Flash去啟動(dòng)是客戶項(xiàng)目的頭等大事,而串行NOR Flash廠商非常多,客戶選擇余地很大,因此我們不得不與客戶一起同茫茫Flash型號(hào)打交道,痞子衡也常常調(diào)侃自己已淪為Flash測(cè)試工程師。

        痞子衡在支持客戶解決串行NOR Flash下載啟動(dòng)問(wèn)題過(guò)程中主要遇到幾個(gè)常見(jiàn)因素,這幾個(gè)因素可能會(huì)影響Flash在i.MXRT下無(wú)法正常使用,上兩篇痞子衡分別講了 《SFDP因素》《QE bit因素》, 今天痞子衡重點(diǎn)跟大家聊聊Write Protection這個(gè)因素。

      一、引入客戶板子可以啟動(dòng)、無(wú)法再次下載問(wèn)題

        痞子衡最近遇到一個(gè)智能電表廠商客戶,他們項(xiàng)目板卡選用的是主控i.MXRT1051 + 華邦W25Q64JVSSIQ,應(yīng)用程序是MBED bootloader + User App二級(jí)加載設(shè)計(jì),其中MBED bootloader是由Arm Pelion物聯(lián)網(wǎng)小組主導(dǎo)設(shè)計(jì)的,User App是這個(gè)電表廠商自己的功能代碼。

        客戶的問(wèn)題是燒寫(xiě)了一個(gè)特定版本的MBED bootloader運(yùn)行之后,板卡Flash無(wú)法再次做燒寫(xiě)了,但是板子是能夠正常從Flash啟動(dòng)的。客戶之后嘗試使用了各種下載工具都不管用(J-Flash/IDE/NXP Tool等),其中下載工具包括痞子衡設(shè)計(jì)的一站式下載工具 MCUBootUtility ,于是問(wèn)題就轉(zhuǎn)到了痞子衡這里(好像有點(diǎn)躺槍的感覺(jué))。工具后臺(tái)報(bào)的錯(cuò)是擦除或者寫(xiě)入時(shí)會(huì)返回 kStatus_FlexSPINOR_CommandFailure,導(dǎo)致無(wú)法下載。

        既然問(wèn)題和特定版本的MBED bootloader有關(guān),那看起來(lái)就是這個(gè)bootloader引入的問(wèn)題,但是痞子衡拿不到客戶MBED bootloader源碼,無(wú)法做白盒分析。鑒于痞子衡這么多年和Flash打交道的經(jīng)驗(yàn),痞子衡盲猜是bootloader使能了Flash的軟件寫(xiě)保護(hù)功能(Software Write Protection)導(dǎo)致的問(wèn)題,于是痞子衡讓客戶寄來(lái)了一塊板卡,實(shí)測(cè)來(lái)證實(shí)痞子衡的猜想。

      二、修改SDK FlexSPI例程來(lái)讀取Status Register

        查看W25Q64JVSSIQ數(shù)據(jù)手冊(cè)得知,軟件寫(xiě)保護(hù)功能的配置集成在Flash器件內(nèi)部非易失性Status Register中,這款Flash一共有3個(gè)8bit的Status Register(狀態(tài)寄存器均支持易失性寫(xiě)入(即斷電恢復(fù))和非易失性寫(xiě)入(即斷電保持),由前導(dǎo)的Write Enable命令類(lèi)型0x06/0x50決定),并且每個(gè)Status Register都有不同的讀寫(xiě)命令:

        現(xiàn)在我們簡(jiǎn)單修改了下SDK里的如下flexspi nor例程(選擇ram build),增加上述三個(gè)Status Register讀取功能的支持,從而實(shí)測(cè)讀取Status Register來(lái)做驗(yàn)證。

      \SDK_2.9.1_EVKB-IMXRT1050\boards\evkbimxrt1050\driver_examples\flexspi\nor\polling_transfer

        首先是在 app.h 和 flexspi_nor_polling_transfer.c 中將Status Register的讀取命令加入到LUT表中。原來(lái)工程里已經(jīng)有Status Register 1的讀取支持,所以我們僅需增加Status Register 2/3的支持即可。因?yàn)檫@新增的兩條命令,需要將CUSTOM_LUT_LENGTH由60改到64(i.MXRT1051上最大64,即支持16條LUT Sequence)。

      const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
          // ...
      
          /* 原有 Read status register 1 */
          [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG] =
              FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x05, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
      
          /* 新增 Read status register 2 */
          [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG2] =
              FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
      
          /* 新增 Read status register 3 */
          [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG3] =
              FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x15, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
      
          // ...
      };
      

        然后在 flexspi_nor_flash_ops.c 中新增如下 flexspi_nor_get_status_register() 函數(shù),這個(gè)函數(shù)直接仿照 flexspi_nor_get_vendor_id() 函數(shù)流程寫(xiě)即可,F(xiàn)lash端時(shí)序是一樣的。

      status_t flexspi_nor_get_status_register(FLEXSPI_Type *base, uint8_t seqIndex, uint8_t *regValue)
      {
          uint32_t readValue;
          flexspi_transfer_t flashXfer;
      
          flashXfer.deviceAddress = 0;
          flashXfer.port          = kFLEXSPI_PortA1;
          flashXfer.cmdType       = kFLEXSPI_Read;
          flashXfer.SeqNumber     = 1;
          flashXfer.seqIndex      = seqIndex;
          flashXfer.data          = &readValue;
          flashXfer.dataSize      = 1;
      
          status_t status = FLEXSPI_TransferBlocking(base, &flashXfer);
          *regValue = (uint8_t)readValue;
      
          /* Do software reset. */
          FLEXSPI_SoftwareReset(base);
      
          return status;
      }
      

        最后就是在 flexspi_nor_polling_transfer.c 中的 main() 函數(shù)里增加 flexspi_nor_get_status_register() 函數(shù)調(diào)用語(yǔ)句,將Status Register 1/2/3的值全部讀取出來(lái)。

      static uint8_t s_regValue1 = 0;
      static uint8_t s_regValue2 = 0;
      static uint8_t s_regValue3 = 0;
      
      int main(void)
      {
          status_t status;
          BOARD_ConfigMPU();
          BOARD_InitPins();
          BOARD_BootClockRUN();
          BOARD_InitDebugConsole();
      
          flexspi_nor_flash_init(EXAMPLE_FLEXSPI);
      
          /* Get status register 1-3. */
          status = flexspi_nor_get_status_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_READSTATUSREG, &s_regValue1);
          status = flexspi_nor_get_status_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_READSTATUSREG2, &s_regValue2);
          status = flexspi_nor_get_status_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_READSTATUSREG3, &s_regValue3);
      
          // ...
      }
      

      三、W25Q64JVSSIQ的Write Protection特性

        將上一節(jié)修改后的 flexspi nor 例程下載進(jìn)RAM調(diào)試運(yùn)行,可以讀出Status Register 1/2/3的值分別為0x40、0x42、0x60,看起來(lái)Status Register確實(shí)被MBED bootloader修改過(guò)。痞子衡標(biāo)出了W25Q64JVSSIQ內(nèi)部狀態(tài)寄存器中所有與寫(xiě)保護(hù)相關(guān)的bit位如下,我們需要對(duì)照Flash數(shù)據(jù)手冊(cè)具體查看讀出來(lái)的值對(duì)應(yīng)了什么樣的寫(xiě)保護(hù)設(shè)置:

        首先Status Register1[SRP],Status Register2[SRL]以及外部WP#引腳共同決定Status Register設(shè)置條件,本例中SRL和SRP均為0,則WP#引腳控制不生效,Status Register可以直接被設(shè)置。

        Status Register中其他寫(xiě)保護(hù)相關(guān)的bit位解釋如下,其中WPS是核心設(shè)置,它決定了寫(xiě)保護(hù)是用單獨(dú)的Block lock命令來(lái)控制(見(jiàn)Flash命令集)還是直接由Status Register1/2中的CMP,TB,SEC,BPx位來(lái)決定。

      Status Register3[WPS]:決定寫(xiě)保護(hù)策略是獨(dú)立的Block鎖定命令控制(WPS=1,默認(rèn)設(shè)置)還是由Status Register1/2控制(WPS=0)
      
      Status Register1[BPx]:指定Flash Memory保護(hù)區(qū)域塊范圍
      Status Register1[SEC]:指定Flash Memory保護(hù)區(qū)域塊單位是4KB Sector(SEC=1)還是64KB Block(SEC=0)
      Status Register1[TB]:指定Flash Memory保護(hù)區(qū)域是從Top(TB=0)/Bottom(TB=1)開(kāi)始
      Status Register2[CMP]:決定由BPx,SEC,TB決定的Flash Memory保護(hù)區(qū)域是否生效(否的話,則區(qū)域外是受保護(hù)的)
      

        綜合上面分析,最后我們發(fā)現(xiàn)MBED bootloader將全部的8MB Flash空間都保護(hù)起來(lái)了,所以各種下載工具都無(wú)法正常燒寫(xiě)這款Flash了。

      四、修改SDK FlexSPI例程來(lái)寫(xiě)入Status Register

        要想重新使能Flash燒寫(xiě),需要一個(gè)單獨(dú)的嵌入式小工程將Status Register1/2/3值再改回到默認(rèn)狀態(tài)(WPS=0, CMP=0),可按照第2節(jié)里讀SR功能修改步驟,代碼如下。代碼工程修改完成后借助調(diào)試器下載到RAM運(yùn)行一次即可,需要注意應(yīng)在芯片SDP模式下運(yùn)行,運(yùn)行結(jié)束后,立刻借助其他下載工具將Flash里舊固件更新掉,保證這個(gè)過(guò)程中不存在軟復(fù)位而導(dǎo)致舊固件被再次運(yùn)行的可能。(此處是將Flash里的MBED bootloader換掉,因?yàn)槭撬谑鼓蹻lash的寫(xiě)保護(hù)功能)

      // flexspi_nor_flash_ops.c 文件中新增 flexspi_nor_set_status_register() 函數(shù)
      status_t flexspi_nor_set_status_register(FLEXSPI_Type *base, uint32_t seqIdx, uint8_t regValue)
      {
          flexspi_transfer_t flashXfer;
          status_t status;
          uint32_t writeValue = (uint32_t)regValue;
      
          /* Write enable */
          status = flexspi_nor_write_enable(base, 0);
          if (status != kStatus_Success)
          {
              return status;
          }
      
          flashXfer.deviceAddress = 0;
          flashXfer.port          = kFLEXSPI_PortA1;
          flashXfer.cmdType       = kFLEXSPI_Write;
          flashXfer.SeqNumber     = 1;
          flashXfer.seqIndex      = seqIdx;
          flashXfer.data          = &writeValue;
          flashXfer.dataSize      = 1;
      
          status = FLEXSPI_TransferBlocking(base, &flashXfer);
          if (status != kStatus_Success)
          {
              return status;
          }
      
          status = flexspi_nor_wait_bus_busy(base);
      
          /* Do software reset. */
          FLEXSPI_SoftwareReset(base);
      
          return status;
      }
      
      // app.h 文件中
      #define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG     9
      #define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG2    10
      #define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG3    11
      //#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI           10
      //#define NOR_CMD_LUT_SEQ_IDX_EXITQPI            11
      
      // flexspi_nor_polling_transfer.c 文件中將Status Register的寫(xiě)入命令加入到LUT表中
      const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
          // ...
      
          /* 原有 Write status register 1 */
          [4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] =
              FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x01, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),
      
          /* 新增 Write status register 2 */
          [4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG2] =
              FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x31, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),
      
          /* 新增 Write status register 3 */
          [4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG3] =
              FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x11, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),
      
          /*
          // Enter QPI mode //
          [4 * NOR_CMD_LUT_SEQ_IDX_ENTERQPI] =
              FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
      
          // Exit QPI mode //
          [4 * NOR_CMD_LUT_SEQ_IDX_EXITQPI] =
              FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xF5, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
          */
      };
      
      int main(void)
      {
          status_t status;
          BOARD_ConfigMPU();
          BOARD_InitPins();
          BOARD_BootClockRUN();
          BOARD_InitDebugConsole();
      
          flexspi_nor_flash_init(EXAMPLE_FLEXSPI);
      
          /* Set status register 1-3. */
          status = flexspi_nor_set_status_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG, 0x00);
          status = flexspi_nor_set_status_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG2, 0x02);
          status = flexspi_nor_set_status_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG3, 0x60);
      
          // ...
      }
      

      五、寫(xiě)在最后

        這里僅以華邦Flash為例介紹Write Protection,其他廠商Flash對(duì)于這個(gè)Write Protection特性設(shè)計(jì)也許有所不同,需要查看數(shù)據(jù)手冊(cè)具體分析。此外鑒于Flash這種種因素會(huì)導(dǎo)致在i.MXRT無(wú)法下載或正常啟動(dòng),痞子衡之前計(jì)劃做的全新上位機(jī)工具M(jìn)CUTestSuite,會(huì)考慮將串行NOR Flash狀態(tài)信息查詢功能(SFDP/QE bit/Write Protection等)也放進(jìn)去,敬請(qǐng)關(guān)注這個(gè)新項(xiàng)目:

        至此,導(dǎo)致串行NOR Flash在i.MXRT下無(wú)法正常下載/啟動(dòng)的常見(jiàn)因素之Write Protection痞子衡便介紹完畢了,掌聲在哪里~~~

      歡迎訂閱

      文章會(huì)同時(shí)發(fā)布到我的 博客園主頁(yè)CSDN主頁(yè)知乎主頁(yè)微信公眾號(hào) 平臺(tái)上。

      微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機(jī)上第一時(shí)間看了哦。

      posted @ 2021-05-17 23:05  痞子衡  閱讀(1130)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 精品国产丝袜自在线拍国语| 亚洲国产在一区二区三区| 中文字幕日韩精品有码| 中国熟妇毛多多裸交视频| 亚洲乱熟乱熟女一区二区| 这里只有精品在线播放| 国产成人午夜精品影院| 奉化市| 国产精品美女一区二三区| 日韩在线视频线观看一区| 好紧好湿好黄的视频| 在线看片免费人成视频久网| 无码AV无码免费一区二区| 色av综合av综合无码网站| 日本三线免费视频观看| 蜜桃在线一区二区三区| 国产桃色在线成免费视频| 久久亚洲精品成人综合网| 亚洲国产日韩欧美一区二区三区 | 欧美性猛交xxxx乱大交极品| 国产精品国产三级在线专区| 亚洲乳大丰满中文字幕| A毛片终身免费观看网站| 亚洲一区二区三区自拍天堂| 免费区欧美一级猛片| 色综合久久久久综合体桃花网| 视频一区视频二区视频三区| 国产在线观看播放av| 特黄大片又粗又大又暴| 久青草视频在线免费观看| 国产精品国产三级国快看| 安平县| 亚洲第一视频区| 日本国产一区二区三区在线观看| 日韩有码中文在线观看| 国产综合久久亚洲综合| 熟女精品视频一区二区三区| 久久天天躁夜夜躁一区| 无码一区中文字幕| 欧美人与性动交α欧美精品| 看全色黄大黄大色免费久久|