一.前言
https://mp.weixin.qq.com/s/hgogGTFzBDx83sFjDX8lVw一文中我們詳細介紹了SPI NAND,也實現了相關的驅動(如果需要驅動源碼可以和我聯系)。X1和x4模式的擦除,寫,讀等都測試OK了?,F在我們需要進行性能測試和優化。https://mp.weixin.qq.com/s/uLraKF5kWMTHLpTggh2Q4Q一文中也介紹了ONFI。
二. 性能測試
既然是追求性能,所以我們后面就都基于X4模式進行了。
我們分別進行擦除,寫,讀全盤測試(128MB),然后使用定時器計算操作的時間。
性能測試代碼如下:
nand_set_qe(1,3); /* 使能QE模式 */
/* 擦除 */
pre = iot_timer_get_time();
for(uint32_t block=0; block < dev.blocks_per_lun*dev.luns; block++)
{
if(0 != (res = nand_block_erase(block*dev.pages_per_block)))
{
iot_printf("block %d erase err
",block,res);
}
}
cur = iot_timer_get_time();
if(cur < pre)
{
used = 0xFFFFFFFF - pre + cur;
}
else
{
used = cur-pre;
}
printf("erase time:%duS
",used);
/* 編程 */
memset(w_buffer,0xFF,sizeof(w_buffer));
w_buffer[dev.page_size] = 0xFF; /* 壞塊標志不能擦除 */
pre = iot_timer_get_time();
for(uint32_t block=0; block < dev.blocks_per_lun*dev.luns; block++)
{
for(uint32_t page=0; page< dev.pages_per_block; page++)
{
if(0 != (res = nand_write_page_x4(w_buffer, block*dev.pages_per_block+page, 0, dev.page_size+dev.page_spare_size)))
{
iot_printf("write page %d err %d
",block*dev.pages_per_block+page,res);
}
}
}
cur = iot_timer_get_time();
if(cur < pre)
{
used = 0xFFFFFFFF - pre + cur;
}
else
{
used = cur-pre;
}
printf("write time:%duS
",(cur-pre));
/* 讀 */
pre = iot_timer_get_time();
for(uint32_t block=0; block < dev.blocks_per_lun*dev.luns; block++)
{
for(uint32_t page=0; page< dev.pages_per_block; page++)
{
if(0 != (res = nand_read_page_x4(r_buffer, block*dev.pages_per_block+page, 0, dev.page_size+dev.page_spare_size)))
{
iot_printf("write page %d err %d
",block*dev.pages_per_block+page,res);
}
}
}
cur = iot_timer_get_time();
if(cur < pre)
{
used = 0xFFFFFFFF - pre + cur;
}
else
{
used = cur-pre;
}
printf("read time:%duS
",(cur-pre));
測試結果如下
對于寫
128MB花了17.40S
所以速度是7.36MB/S
三. 性能分析
我們使用邏輯分析儀抓取總線波形,用于進行性能分析
參考文章https://mp.weixin.qq.com/s/bCdgCNsGPbYjSzjv8VJyRA
我們以編程為例,擦除和讀類似。
編程PAGE的代碼如下,有三個步驟
即先寫數據到CACHE,然后寫使能,最后執行CACHE到PAGE的數據編程。
int nand_write_page_x4(uint8_t* buffer, uint32_t pageaddr, uint16_t start, uint16_t len)
{
int res = 0;
res = nand_write_to_cache_x4(start, len, buffer);
if(res == 0)
{
res = nand_write_enable();
if(res == 0)
{
res = nand_write_cache_to_page(pageaddr,NAND_PROG_CHECK_RETRY);
if(res == 0)
{
return 0;
}
else
{
return -3;
}
}
else
{
return -2;
}
}
else
{
return -1;
}
}
查看邏輯分析儀抓取到的數據如下,對應如下三個步驟
(1)總線上寫數據到NAND的Cache
(2)寫使能,并查詢寫使能OK
(3)執行CACHE到PAGE編程,并查詢完成
從以上時間戳可以看到三個步驟分別對應的時間是
第一次開始
19:48:31.513.198.648,PROGRAM LOAD x4(32),0000, ,FF,FF,FF,FF,FF,FF,FF,FF,........,
開始寫使能
19:48:31.513.259.134,WRITE ENABLE(06), , , , , , , , , , , ,
開始編程
19:48:31.513.273.890,PROGRAM EXECUTE(10),0040BE, , , , , , , , , , ,
編程完成
19:48:31.513.344.141,GET FEATURE(0F),C0, ,00, , , , , , , ,.,
下一次開始
19:48:31.513.435.474,PROGRAM LOAD x4(32),0000, ,FF,FF,FF,FF,FF,FF,FF,FF,........,
一個PAGE編程的周期
所以一個PAGE的編程時間是下一次開始和前一次開始的時間間隔
435.474-198.648=236.826uS
一次操作是寫2048+128字節,對應236.826uS,換算就是8.76MB/S比使用軟件定時器測試的7.36MB/S大一點,因為軟件額外一些邏輯處理需要一些時間,比如獲取定時器時間,塊之間的循環切換等。
波形如下
總線上數據傳輸時間
總線寫數據時間即第一次開始到開始寫使能,
259.134-198.648=60.486uS
如下如圖,后面6.96uS是兩次傳輸之間的間隔,即軟件完成一次傳輸到下一次傳輸之間的時間,也算在這個階段了。
寫使能時間
由于編程完之后,NAND會自動寫禁止,所以每次都需要重新寫使能。
執行寫使能后要回讀是否設置成功(當然回讀也可以省略但是出于可靠性考慮還是建議回讀,如果回讀未使能再重試)。
對應如下
273.890-259.134=14.756uS
編程時間
344.141-273.890=70.251
軟件處理時間
從下可以看出編程完成到下一次開始,還有
91uS
這一部分是軟件處理時間,主要是軟件從NAND控制器的緩存區中將數據搬運到用戶存儲中去。
所以整理下各階段的時間消耗如下
總線傳輸 | 寫使能 | 編程 | 軟件處理 | 總 | |
---|---|---|---|---|---|
時間 | 60.49 | 14.76 | 70.25 | 91 | 236.5 |
占比 | 25.58% | 6.24% | 29.7% | 38.48% | 100% |
可以看出軟件處理實際占用時間比例最大,主要是從控制器的緩沖區中將數據搬運到用戶存儲的時間。
四. 性能優化
針對以上性能分析過程,對各個階段考慮優化
1. 總線傳輸
已經使用了X4模式, 如果還要縮短該階段的時間,只能繼續提高頻率了,目前是80M的時鐘,手冊中參數是3.3V快讀可達133MHz。
針對讀還可以使用DTR雙邊沿模式但是這時最大時鐘頻率只有70MHz,雙邊沿也就是140M所以比133M也大不了多少。
2. 寫使能時間
由于每次編程之后,NAND自動寫禁止,所以該步驟不能少,可以減少回讀操作大約節省7uS,但是出于可靠性設計,建議還是回讀,如果回讀不成功則重試。
3. 編程時間
手冊中描述的時間是不使能ECC也最少要300uS,我們實測是70uS左右,所以手冊已經寫的很保守了,這里也沒有優化空間了。
4軟件處理時間
這一部分主要是軟件在用戶存儲和NAND控制器的緩存之間拷貝數據的時間。
最好是這一部分工作由控制器完成,而不是軟件去搬運,比如軟件指定一個地址,控制器自動從這個地址讀,或者寫入這個地址,而不是通過緩存再轉一遍,減少拷貝時間。
軟件時間還包括邏輯處理時間,比如一次傳輸到下一次傳輸,需要配置寄存器,進行判斷,等邏輯處理。
由于軟件是分層設計包括HW層寄存器的封裝,HAL層傳輸的接口,以設備驅動層,
對于HW層封裝可以使用宏或者內聯函數替代函數,減少函數調用時間,HW層和HAL不做參數檢查,因為接口調用頻繁等,在設備驅動層做參數檢查。
/**
* n int nfc_set_datalen(uint8_t id, uint16_t len)
* param[in] id port id
* param[in] len data len
*
etval 0 ok
*
etval < 0 param err
*
*/
NFC_INLINE int nfc_set_datalen(uint8_t id, uint16_t len)
{
uint32_t tmp;
(void)id;
tmp = NFC_READ_REG(CFG_NFC_ENA_ADDR);
tmp &= ~NFC_DATA_LEN_MASK;
tmp |= (len < < NFC_DATA_LEN_OFFSET);
NFC_WRITE_REG(CFG_NFC_ENA_ADDR,tmp);
return 0;
}
六.波形文件
這里分享一些實際抓取到的波形文件供參考
波形文件使用軟件Acute TravelLogic Analyzer打開查看。
鏈接:https://pan.baidu.com/s/103HHT4qcvFjGn1q-jJhAUg?pwd=iqlm
提取碼:iqlm
七. 總結
從以上分析可以看出最大的優化空間是減少軟件從控制器緩沖區去搬運數據的時間,這一部分時間占最大頭,可IP設計優化直接硬件搬運數據到用戶存儲。
審核編輯:湯梓紅
-
NAND
+關注
關注
16文章
1681瀏覽量
136118 -
存儲
+關注
關注
13文章
4296瀏覽量
85798 -
SPI
+關注
關注
17文章
1706瀏覽量
91502 -
性能測試
+關注
關注
0文章
209瀏覽量
21327
發布評論請先 登錄
相關推薦
評論