大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是i.MXRT系列FlexSPI驅(qū)動Flash頁編程執(zhí)行時(shí)間。
痞子衡之前寫過一篇文章 《串行NOR Flash的頁編程模式對于量產(chǎn)效率的影響》,簡要分析了 NOR Flash 的 Page Program 命令不同模式對于整體量產(chǎn)時(shí)間的影響,文章僅從理論計(jì)算角度做了分析,假定了 Flash 中所有 Page 擦寫表現(xiàn)都是一致的,但是每個(gè) Page 的表現(xiàn)真的是完全一致嗎?今天我們從一個(gè)客戶問題出發(fā)來探討下這個(gè)話題:
一、引入客戶問題
最近有一個(gè) i.MXRT1170 客戶反饋,他們的應(yīng)用程序里 IAP 功能代碼對于 Flash 擦寫表現(xiàn)不穩(wěn)定。他們的 IAP 代碼就是移植的 SDK_2.10.0_MIMXRT1170-EVKboardsevkmimxrt1170driver_examplesflexspinorpolling_transfer 例程,F(xiàn)lash 選用得跟官方 EVK 上一樣的型號 IS25WP128-JBLE,測試代碼會把整個(gè) Flash 的 16MB 循環(huán)擦除寫入,反復(fù)進(jìn)行測試,在測試過程中發(fā)現(xiàn)的部分區(qū)域表現(xiàn)速度較慢,這個(gè)慢的定義是在部分 256 字節(jié)(一個(gè) Page)寫入時(shí),寫入 API 返回時(shí)間較長(因?yàn)槭禽喸兡J剑欠祷貭顟B(tài)是正確的。
由于客戶并沒有進(jìn)一步給出 Page 寫入快慢時(shí)間分別是多少,痞子衡只能先盲猜。既然寫入 API 返回狀態(tài)是正確的,那說明 FlexSPI 驅(qū)動是能正常工作的,先排除板級硬件設(shè)計(jì)問題。那么只剩下兩種可能:一、FlexSPI 軟件驅(qū)動執(zhí)行穩(wěn)定性問題;二、Flash 本身 Page 表現(xiàn)一致性問題。這兩個(gè)問題都可以通過觀察統(tǒng)計(jì)全部 Page 的寫入時(shí)間來進(jìn)一步確認(rèn)。對于第二個(gè)可能性,從 Flash 手冊里我們可以得知 Page 寫入命令的等待時(shí)間典型值是 0.2ms,最大值是 0.8ms,但這個(gè)表述并沒有明確這是針對不同 Flash 芯片而言,還是針對同一 Flash 內(nèi)不同 Page 而言。
二、確定測量方案
帶著上述疑問,痞子衡決定在官方 MIMXRT1170-EVK 上實(shí)測一下,我們僅需簡單改造一下 SDK_2.10.0_MIMXRT1170-EVKboardsevkmimxrt1170driver_examplesflexspinorpolling_transfer 例程,在 flexspi_nor_polling_transfer.c 源文件中 main() 函數(shù)里加入計(jì)時(shí)代碼統(tǒng)計(jì) flexspi_nor_flash_page_program() 函數(shù)執(zhí)行時(shí)間即可,其中計(jì)時(shí)實(shí)現(xiàn)可用 https://github.com/JayHeng/microseconds 項(xiàng)目,具體用法參考 《通用微秒(microseconds)計(jì)時(shí)函數(shù)框架設(shè)計(jì)與實(shí)現(xiàn)》 一文。
//?保存?65536?個(gè)?Page?的寫入?API?執(zhí)行時(shí)間
uint16_t?timeRes[65536];
int?main(void)
{
????//?省略原?Flash?初始化、擦除代碼
????microseconds_init();
#if?!(defined(XIP_EXTERNAL_FLASH))
????uint32_t?startAddr?=?0;
#else
????uint32_t?startAddr?=?0x8000;
#endif
????uint32_t?endAddr?=?0x1000000;
????while?(startAddr?<?endAddr)
????{
????????//?計(jì)時(shí)開始
????????uint64_t?startTicks?=?microseconds_get_ticks();
????????uint64_t?endTicks?=?startTicks;
????????uint64_t?deltaTicks?=?0;
????????status_t?status?=?flexspi_nor_flash_page_program(FLEXSPI1,?startAddr,?(void?*)s_nor_program_buffer);
????????if?(status?==?kStatus_Success)
????????{
????????????//?計(jì)時(shí)結(jié)束
????????????endTicks?=?microseconds_get_ticks();
????????????deltaTicks?=?endTicks?-?startTicks;
????????????uint16_t?costMicroseconds?=?microseconds_convert_to_microseconds(deltaTicks);
????????????timeRes[startAddr?/?256]?=?costMicroseconds;
????????}
????????startAddr?+=?256;
????}
????for?(uint32_t?i?=?0;?i?<?sizeof(timeRes)?/sizeof(uint16_t);?i++)
????{
????????PRINTF("%drn",?timeRes[i]);
????}
????
????while?(1)
????{
????}
}
三、選一款串口波形顯示軟件
上一節(jié)代碼中,我們把所有 Page 的寫入時(shí)間都通過串口打印了出來,現(xiàn)在需要一款串口波形顯示軟件,來直觀地看這 65536 個(gè)時(shí)間結(jié)果的差異。痞子衡試用了好幾款軟件:Serial Plot v0.12.0、Serial Chart V034、Serial Hunter V31,發(fā)現(xiàn)做得最完善的是 Serial Plot 軟件,推薦給大家:
Serial Plot 軟件源碼:https://github.com/hyOzd/serialplotSerial Plot 軟件安裝包:https://serialplot.ozderya.net/downloads/serialplot-0.12.0-win32-setup.exe
Serial Plot 軟件做得最好的地方是對串口接收數(shù)據(jù)格式的完善支持,既可以是 Binary(單通道字節(jié)長度可設(shè)),也可以是 ASCII 碼(通道間隔符可設(shè)),還可以是自定義數(shù)據(jù)幀(幀頭、幀格式可設(shè)),通道數(shù)也可以任意設(shè),基本上可以滿足大部分串口波形顯示需求了。
四、測試結(jié)果分析
準(zhǔn)備就緒,給板卡通上電,將測試程序下載進(jìn)去跑起來,打開 Serial Plot 設(shè)置好串口接收參數(shù)后觀測結(jié)果,我們發(fā)現(xiàn)波形顯示是一條直線,即 65536 個(gè) Page 寫入時(shí)間是穩(wěn)定的,都是 271us(測試工程選擇的是 debug build),這個(gè)結(jié)果推翻了我們之前的兩個(gè)猜測,寫入 API 執(zhí)行時(shí)間是穩(wěn)定的,F(xiàn)lash 的各 Page 表現(xiàn)也是一致的。后來跟客戶進(jìn)一步溝通,客戶反饋他們是在 ThreadX 的 LevelX 中發(fā)現(xiàn)的,所以看起來客戶問題和 ThreadX 系統(tǒng)調(diào)度有關(guān),那就是另外一個(gè)話題了,以后再展開。
至此,i.MXRT系列FlexSPI驅(qū)動Flash頁編程執(zhí)行時(shí)間痞子衡便介紹完畢了,掌聲在哪里~~~