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

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

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

      痞子衡嵌入式:實(shí)抓Flash信號(hào)波形來看i.MXRT的FlexSPI外設(shè)下AHB讀訪問情形(無緩存)


        大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是實(shí)抓Flash信號(hào)波形來看i.MXRT的FlexSPI外設(shè)下AHB讀訪問情形。

        上一篇文章 《i.MXRT中FlexSPI外設(shè)對(duì)AHB Burst Read特性的支持》 里痞子衡介紹了FlexSPI外設(shè)在不開啟Prefetch功能下響應(yīng)AHB master的訪問請(qǐng)求完全受AHB總線Burst Read特性決定,這是FlexSPI外設(shè)最基礎(chǔ)的對(duì)Flash訪問支持功能,研究這個(gè)其實(shí)是很有意義的,這可以反映出XiP下最原始的代碼執(zhí)行效率。

        我們知道在實(shí)際項(xiàng)目中,XiP應(yīng)用程序常常是在L1 Cache和Prefetch加持下運(yùn)行的,代碼執(zhí)行效率會(huì)得到大大提升,但無論是怎樣的緩存策略,極限情況下(比如大數(shù)據(jù)塊搬移,長(zhǎng)跳轉(zhuǎn)指令)最終還是拼得FlexSPI最基礎(chǔ)的讀訪問支持。今天痞子衡就從抓Flash信號(hào)波形角度帶大家真切感受下這最基礎(chǔ)的AHB讀訪問情形(為更清晰地分析結(jié)果,本次主要涉及數(shù)據(jù)總線AHB訪問,暫不涉及指令總線AHB訪問):

      一、實(shí)驗(yàn)準(zhǔn)備

        痞子衡用i.MXRT1050-EVKB來做這個(gè)AHB讀訪問實(shí)驗(yàn),這塊板子上的Flash被痞子衡更換過,目前的型號(hào)是華邦W25Q64JWS-IQ。我們基于 \SDK_2.9.1_EVKB-IMXRT1050\boards\evkbimxrt1050\demo_apps\led_blinky\iar 例程(記得切換到 flexspi_nor_debug build)來簡(jiǎn)單修改一下,把啟動(dòng)頭FDCB修改如下,設(shè)置Flash工作于30MHz Fast Read Quad I/O SDR模式,調(diào)成30MHz低速是為了方便后續(xù)用示波器抓Flash信號(hào)去分析。

      const flexspi_nor_config_t qspiflash_config = {
          .memConfig =
              {
                  .tag              = FLEXSPI_CFG_BLK_TAG,
                  .version          = FLEXSPI_CFG_BLK_VERSION,
                  .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
                  .csHoldTime       = 3u,
                  .csSetupTime      = 3u,
                  .controllerMiscOption = 0x10,
                  .deviceType       = kFlexSpiDeviceType_SerialNOR,
                  .sflashPadType    = kSerialFlash_4Pads,
                  // Flash工作于30MHz
                  .serialClkFreq    = kFlexSpiSerialClk_30MHz,
                  .sflashA1Size     = 8u * 1024u * 1024u,
                  .lookupTable =
                      {
                          // Quad I/O Fast Read SDR LUTs
                          [4*CMD_LUT_SEQ_IDX_READ + 0] = FLEXSPI_LUT_SEQ(CMD_SDR,   FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
                          [4*CMD_LUT_SEQ_IDX_READ + 1] = FLEXSPI_LUT_SEQ(MODE8_SDR, FLEXSPI_4PAD, 0xF0, DUMMY_SDR, FLEXSPI_4PAD, 0x04),
                          [4*CMD_LUT_SEQ_IDX_READ + 2] = FLEXSPI_LUT_SEQ(READ_SDR,  FLEXSPI_4PAD, 0x04, STOP,      FLEXSPI_1PAD, 0x00),
                          [4*CMD_LUT_SEQ_IDX_READ + 3] = 0,
                      },
              },
          .pageSize           = 256u,
          .sectorSize         = 4u * 1024u,
          .blockSize          = 64u * 1024u,
          .isUniformBlockSize = false,
      };
      

        下圖是華邦W25Q64JWS-IQ芯片的Fast Read Quad I/O SDR傳輸時(shí)序圖,Dummy Cycle連同MODE8_SDR序列一共6個(gè)SCK周期,此外還有個(gè)特別注意點(diǎn),MODE8_SDR序列參數(shù)值需要被設(shè)成0xFx,我們上面修改的FDCB啟動(dòng)頭是符合要求的。

        現(xiàn)在讓我們把示波器拿出來,四路探頭分別連到板載Flash器件的CE#、SCK、SI_IO0、SO_IO1引腳(IO2、IO3因探頭有限就不抓取了,IO[1:0]足夠我們分析時(shí)序了),然后將 led_blinky 工程下載進(jìn)Flash運(yùn)行便可以觀測(cè)結(jié)果了。

      二、實(shí)驗(yàn)代碼

        因?yàn)槲覀兿螺d的是一個(gè)XIP工程,代碼的執(zhí)行本身也會(huì)觸發(fā)Flash中的指令讀取,這會(huì)影響我們?cè)谑静ㄆ魃嫌^測(cè)AHB讀數(shù)據(jù)測(cè)試結(jié)果,所以我們可以在main()函數(shù)里把SysTick初始化去掉(不要中斷),并且調(diào)用如下ramfunc型函數(shù) test_ahb_read() 來做測(cè)試(痞子衡直接利用了IAR軟件的特性),這樣代碼跑起來后,F(xiàn)lash上發(fā)生的讀訪問均來自我們想要測(cè)試的AHB讀數(shù)據(jù)操作(這也意味著ICache是否開啟對(duì)本系列測(cè)試結(jié)果沒有影響,但不管怎么,我們統(tǒng)一關(guān)掉):

      Note: DCache和Prefetch必須要全部關(guān)閉,否則哪怕測(cè)試代碼里對(duì)同一個(gè)地方循環(huán)讀取,但在Flash引腳上根本看不到周期性信號(hào)波形,因?yàn)橄到y(tǒng)做了緩存,后續(xù)的讀取操作可能直接發(fā)生在緩存區(qū)里(32KB DCache, 1KB AHB RX prefetch buffer)了。

      #define AHB_ADDR_START (0x60002400) 
      
      #if (defined(__ICCARM__))
      #pragma optimize = none
      __ramfunc 
      #endif
      void test_ahb_read(void)
      {
          /* Disable L1 I-Cache*/
          SCB_DisableICache();
      
          /* Disable L1 D-Cache*/
          SCB_DisableDCache();
      
          /* Disable FlexSPI AHB read prefetch */
          FLEXSPI->AHBCR &= ~(FLEXSPI_AHBCR_PREFETCHEN_MASK | FLEXSPI_AHBCR_CACHABLEEN_MASK);
          
          while (1)
          {
              SDK_DelayAtLeastUs(10, SystemCoreClock);
              for (uint32_t i = 1; i <= 8; i++)
              {   
                  SDK_DelayAtLeastUs(2, SystemCoreClock);
                  memcpy((void *)0x20200000, (void *)AHB_ADDR_START, i);
              }
          } 
      }
      

        因?yàn)槲覀冇昧薽emcpy來做Flash數(shù)據(jù)拷貝,memcpy功能實(shí)際上是IAR軟件自帶庫 ABImemcpy.a 里面的 __aeabi_memcpy、__aeabi_memcpy4、__aeabi_memcpy8 等函數(shù)實(shí)現(xiàn)的,因此我們還需要在工程鏈接文件里將 ABImemcpy.o 鏈接到RAM區(qū);并且我們還用了SDK_DelayAtLeastUs()來分隔每次memcpy()波形結(jié)果,還需要將這個(gè)函數(shù)里調(diào)用的相關(guān)代碼放到RAM區(qū)(fsl_common.c里)。

      initialize by copy { readwrite,
                           section .textrw,
                           // 確保 memcpy() 相關(guān)代碼全在RAM里
                           object ABImemcpy.o,
                           // 確保 SDK_DelayAtLeastUs() 相關(guān)代碼全在RAM里
                           object fsl_common.o,
                           object I64DivZer.o,
                           object I64DivMod.o
                           };
      do not initialize  { section .noinit };
      

        一切準(zhǔn)備就緒后具體測(cè)試就是設(shè)置不同的AHB_ADDR_START值(這里主要是考慮地址對(duì)齊)來觀測(cè)Flash信號(hào)的實(shí)際波形。此外為了便于分辨IO[1:0]上的數(shù)據(jù),我們最好定義一塊特殊const數(shù)據(jù)區(qū),根據(jù)Flash傳輸時(shí)序圖,其中數(shù)據(jù)Byte[4]和Byte[0]是在IO0線上傳輸、Byte[5]和Byte[1]是在IO1線上傳輸?shù)模@4bit共有16種不同值組合,我們將這16種不同值放在ahbRdBlock[16]數(shù)組中,并將其鏈接在 0x60002400 - 0x6000240f 地址空間里。

      // 在工程源文件中
      const uint8_t ahbRdBlock[16] @ ".ahbRdBuffer" = {0x00, 0x01, 0x02, 0x03,
                                                       0x10, 0x11, 0x12, 0x13,
                                                       0x20, 0x21, 0x22, 0x23,
                                                       0x30, 0x31, 0x32, 0x33};
      // 在工程鏈接文件中
      keep{ section .ahbRdBuffer };
      place at address mem:0x60002400 { readonly section .ahbRdBuffer };
      

      三、實(shí)驗(yàn)結(jié)果

        因?yàn)榧葲]有Cache,也沒有Prefetch,所以用戶代碼中memcpy語句(哪怕存在循環(huán)重復(fù)讀?。┡cFlash端實(shí)際信號(hào)時(shí)序波形圖幾乎是一一對(duì)應(yīng)的,唯一不確定的就是AHB master是如何拆分CS信號(hào)周期的。

      3.1 AHB_ADDR_START = 0x60002400 即八字節(jié)對(duì)齊

        我們先來看AHB_ADDR_START = 0x60002400時(shí)抓取一次完整for循環(huán)結(jié)果的波形(見下圖),可以看到在八字節(jié)對(duì)齊的地址下使用memcpy拷貝1/2/4/8字節(jié),均僅產(chǎn)生一次CS信號(hào)有效周期(拉低),在這CS有效期間完成全部所需數(shù)據(jù)的讀取。但是拷貝3/5/6/7字節(jié)時(shí),會(huì)拆分出多個(gè)CS有效周期。

        當(dāng)使用memcpy拷貝3/5/6字節(jié)時(shí),會(huì)拆分出2個(gè)CS有效周期(見下圖),這里第一個(gè)CS周期看起來似乎是多余的,為什么是這種結(jié)果,這需要深入研究AHB機(jī)制(痞子衡會(huì)另寫文章分析);

      • 當(dāng)拷貝3字節(jié)時(shí),第一個(gè)CS周期實(shí)際讀取了前2個(gè)字節(jié) [0x60002400, 0x60002401],第二個(gè)CS周期讀取了全部3字節(jié) [0x60002400, 0x60002402]。
      • 當(dāng)拷貝5字節(jié)時(shí),第一個(gè)CS周期實(shí)際讀取了前4個(gè)字節(jié) [0x60002400, 0x60002403],第二個(gè)CS周期讀取了全部5字節(jié) [0x60002400, 0x60002404]。
      • 當(dāng)拷貝6字節(jié)時(shí),第一個(gè)CS周期實(shí)際讀取了前4個(gè)字節(jié) [0x60002400, 0x60002403],第二個(gè)CS周期讀取了全部6字節(jié) [0x60002400, 0x60002405]。

        當(dāng)使用memcpy拷貝7字節(jié)時(shí),會(huì)拆分出3個(gè)CS有效周期(見下圖),這里前兩個(gè)CS周期看起來似乎都是多余的;

      • 當(dāng)拷貝7字節(jié)時(shí),第一個(gè)CS周期實(shí)際讀取了前4個(gè)字節(jié) [0x60002400, 0x60002403],第二個(gè)CS周期實(shí)際讀取了前6個(gè)字節(jié) [0x60002400, 0x60002405],第三個(gè)CS周期讀取了全部7字節(jié) [0x60002400, 0x60002406]。

      3.2 AHB_ADDR_START = 0x60002404 即四字節(jié)對(duì)齊

        AHB_ADDR_START = 0x60002404時(shí)抓取一次完整for循環(huán)結(jié)果的波形(見下圖),可以看到在四字節(jié)對(duì)齊的地址下使用memcpy拷貝1/2/4字節(jié),均僅產(chǎn)生一次CS信號(hào)有效周期(拉低),在這CS有效期間完成全部所需數(shù)據(jù)的讀取。

        但是拷貝3/5/6/7/8字節(jié)時(shí),會(huì)拆分出多個(gè)CS有效周期。不過其中拷貝5/6/8字節(jié),是合理的拆分,并沒有冗余讀取。

      3.3 AHB_ADDR_START = 0x60002401 即奇地址

        AHB_ADDR_START = 0x60002401時(shí)抓取一次完整for循環(huán)結(jié)果的波形(見下圖),這種情況下CS拆分特別嚴(yán)重,幾乎都存在冗余讀取。

      3.4 AHB_ADDR_START = 0x60002402 即偶地址

        AHB_ADDR_START = 0x60002402時(shí)抓取一次完整for循環(huán)結(jié)果的波形(見下圖),這種情況下CS拆分特別嚴(yán)重,幾乎都存在冗余讀取。

      3.5 AHB_ADDR_START = 0x60002403

        AHB_ADDR_START = 0x60002403時(shí)抓取一次完整for循環(huán)結(jié)果的波形(見下圖),這種情況下CS拆分特別嚴(yán)重,幾乎都存在冗余讀取。

      四、追加實(shí)驗(yàn)

        上一節(jié)的實(shí)驗(yàn)主要側(cè)重于memcpy拷貝源Flash首地址對(duì)齊方式的不同,而拷貝長(zhǎng)度最大僅設(shè)到8byte,那么如果我們一次拷貝超過8byte會(huì)是什么情形呢?痞子衡做了如下實(shí)驗(yàn),這次從0x60002400開始一次拷貝1KB,從結(jié)果波形上來看,1KB的數(shù)據(jù)拷貝被拆分成了128個(gè)CS有效周期,每個(gè)CS有效期間拷貝8byte。

      #if (defined(__ICCARM__))
      #pragma optimize = none
      __ramfunc 
      #endif
      void test_ahb_read(void)
      {
          /* Disable L1 I-Cache*/
          SCB_DisableICache();
      
          /* Disable L1 D-Cache*/
          SCB_DisableDCache();
      
          /* Disable FlexSPI AHB read prefetch */
          FLEXSPI->AHBCR &= ~(FLEXSPI_AHBCR_PREFETCHEN_MASK | FLEXSPI_AHBCR_CACHABLEEN_MASK);
          
          while (1)
          {
              SDK_DelayAtLeastUs(10, SystemCoreClock);
              memcpy((void *)0x20200000, (void *)0x60002400, 0x400);
          } 
      }
      

        至此,實(shí)抓Flash信號(hào)波形來看i.MXRT的FlexSPI外設(shè)下AHB讀訪問情形痞子衡便介紹完畢了,掌聲在哪里~~~

      歡迎訂閱

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

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

      posted @ 2021-04-30 23:40  痞子衡  閱讀(1469)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产成人精品性色av麻豆| 无码电影在线观看一区二区三区| 襄樊市| 国产av一区二区麻豆熟女| 无码欧亚熟妇人妻AV在线外遇| 亚洲色成人一区二区三区人人澡人人妻人人爽人人蜜桃麻豆 | 99RE6在线观看国产精品| 中文字幕人妻无码一区二区三区 | 精品女同一区二区三区在线| 亚洲青青草视频在线播放| 少妇人妻综合久久中文字幕| 蜜臀av久久国产午夜| 新宾| 玩弄放荡人妻少妇系列| 国产高清不卡视频| 日韩精品一区二区三区中文无码| 一区二区三区激情免费视频| 久激情内射婷内射蜜桃| 亚洲精品久久久蜜桃| 无码专区 人妻系列 在线| 午夜通通国产精品福利| av偷拍亚洲一区二区三区| 内地自拍三级在线观看| 免费人妻无码不卡中文18禁| 亚洲美免无码中文字幕在线| 日本无翼乌邪恶大全彩h| 国产精品麻豆va在线播放| 亚洲av成人无码精品电影在线| 翘臀少妇被扒开屁股日出水爆乳| 国内熟妇人妻色在线三级| 欧美性猛交xxxx免费看| 国产精品不卡一区二区久久| 国产免费一区二区不卡| 亚洲天堂在线观看完整版| 国产在线观看免费观看| 7777精品久久久大香线蕉| 欧美人与zoxxxx另类| 日韩中文字幕一二三视频| 被灌满精子的波多野结衣| 十八禁国产一区二区三区| 国产精品成人高潮av|