大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家分享的是i.MXRT1170 XECC開啟及Data Swap功能對于外部RAM的訪問性能影響。
這篇文章里痞子衡給大家介紹了 XECC 原理及在其使能下操作 NOR Flash 步驟(尤其涉及對 Flash 的 AHB 方式寫),但文章里并沒有涉及性能方面的評估。我們知道 RT1170 上內(nèi)部 FlexRAM ECC 模塊使能后對 TCM 訪問性能幾乎無影響,那么 XECC 使能后對于掛在 FlexSPI/SEMC 接口上的外部 PSRAM/SDRAM 訪問性能是否有影響呢?今天我們就來聊聊這個話題:
- Note:本文以 MIMXRT1170-EVKB (Rev.B) 板卡上掛在 SEMC 接口的 16bit SDRAM - W9825G6KH-5I 讀寫測試為例,PSRAM 測試過程類似。
一、XECC功能測試
測試 XECC 對于 SDRAM 訪問保護功能我們可以直接使用如下兩個官方例程,其中 xecc_single_error 示例了單 bit 糾錯(4bits數(shù)據(jù)單元而言),xecc_multi_error 示例了雙 bit 報錯(4bits數(shù)據(jù)單元而言),這兩個例程都借助了 XECC 本身的 Error injection 特性人為制造數(shù)據(jù) bit 錯誤來做測試(可以指定 32bits 數(shù)據(jù)塊中任意位置和個數(shù)的 bit 出錯)。
SDK_2_16_000_MIMXRT1170-EVKBboardsevkbmimxrt1170driver_examplesxeccsemcxecc_single_errorcm7
SDK_2_16_000_MIMXRT1170-EVKBboardsevkbmimxrt1170driver_examplesxeccsemcxecc_multi_errorcm7
痞子衡簡單整合了上述兩個例程代碼到一個工程里,這樣可以同時測單/雙/多 bit 錯誤情況,其中主要代碼摘錄如下。此外為了方便觀察不同的錯誤注入導致的結(jié)果,我們將待寫入值 sdram_writeBuffer[0] 設為 0x00000000,這樣發(fā)生無法糾錯情況時讀回的數(shù)據(jù) sdram_readBuffer[0] 就應該等于錯誤注入值 errorData。
#include?"fsl_xecc.h"
volatile?uint32_t?sdram_writeBuffer[0x1000];
volatile?uint32_t?sdram_readBuffer[0x1000];
int?main(void)
{
????//?系統(tǒng)與?SDRAM?初始化代碼省略...
????//?初始化?XECC_SEMC?模塊,設置?SDRAM?[0x80000000,?0x8007FFFF]?為?ECC?使能區(qū)域,其中前?256KB?是用戶數(shù)據(jù)訪問空間
????XECC_Deinit(XECC_SEMC);
????xecc_config_t?config;
????XECC_GetDefaultConfig(&config);
????config.enableXECC?????=?true;
????config.enableWriteECC?=?true;
????config.enableReadECC??=?true;
????//config.enableSwap?=?true;
????config.Region0BaseAddress?=?0x80000000U;
????config.Region0EndAddress??=?0x80080000U;??//?256KB?*?2
????XECC_Init(XECC_SEMC,?&config);
????(void)EnableIRQ(XECC_SEMC_INT_IRQn);
????(void)EnableIRQ(XECC_SEMC_FATAL_INT_IRQn);
????SCB->SHCSR?|=?SCB_SHCSR_BUSFAULTENA_Msk;
????XECC_EnableInterrupts(XECC_SEMC,?kXECC_AllInterruptsEnable);
????//?對?32bits?數(shù)據(jù)塊進行錯誤注入(這里設定得是錯誤?bit?位置)
????uint32_t?errorData?=?0x00000001;
????XECC_ErrorInjection(XECC_SEMC,?errorData,?0);
????sdram_writeBuffer[0]?=?0x00000000U;
????//?AHB?方式寫數(shù)據(jù)進?SDRAM
????*(uint32_t?*)0x80000000U?=?sdram_writeBuffer[0];
????//?關閉?DCache?代碼省略...
????//?AHB?方式從?SDRAM?讀回數(shù)據(jù)
????sdram_readBuffer[0]?=?*(uint32_t?*)0x80000000U;
????while?((!s_xecc_single_error)?&&?(!s_xecc_multi_error))
????{
????}
????//?代碼省略...
}
在放測試結(jié)果之前,我們先回顧一下 XECC 錯誤檢測機制。在默認不開啟 Data Swap 特性情況下,對于 32bits 數(shù)據(jù)塊,XECC 可以糾正其中發(fā)生的 8bits 錯誤,但前提是按序分割開的每 4bits 數(shù)據(jù)單元僅能有 1bit 錯誤(即分散 bit 錯誤)。如果這 4bits 數(shù)據(jù)單元里有 2bit 錯誤,那 XECC 會檢測出位置并報告;如果有 3/4bit 錯誤,那已經(jīng)超出 XECC 處理能力,結(jié)果不可預期了。
但如果現(xiàn)場實際環(huán)境發(fā)生連續(xù) bit 錯誤概率高于分散 bit 錯誤,這時候可以考慮開啟 XECC Data Swap 功能,這時候 XECC 處理能力變成可以糾正連續(xù) bit 錯誤,但對于分散 bit 錯誤就無法處理了(如下圖所示,實際上 Swap 是將圖左邊 32bits 原數(shù)據(jù)打亂再重新組合成圖右邊 32bits 新數(shù)據(jù))。
根據(jù)上面的理論,我們現(xiàn)在再來看測試結(jié)果,那就非常合理了,有些情況下開啟 Data Swap 增強了糾檢錯能力,有些情況下開啟 Data Swap 卻減弱了原來的糾檢錯能力。(注意,Error injection 設定的 errorData 是針對 swap 之后的數(shù)據(jù) bit 序而言)
- Note:單 32bits 數(shù)據(jù)塊寫讀測試時,改動 L1 D-Cache 操作代碼位置(前移到 main 開始),會影響測試結(jié)果,這里留一個伏筆,以后具體分析。
二、XECC性能測試
現(xiàn)在我們簡單測試一下內(nèi)核對 SDRAM 讀寫性能是否受 XECC 影響,就在 semcxecc_multi_error 例程基礎之上,設計了如下代碼,便于測試不同的數(shù)據(jù)塊大?。ū热?64KB,128KB,256KB),而且可以一次性對比沒有 XECC 保護,加 XECC 保護,以及開啟 XECC Data Swap 三種情況(中途需要 Deinit 再 Init XECC 模塊)。
uint32_t?readErrorCnt?=?0;
uint32_t?get_sdram_rw_block_time(uint32_t?start,?uint32_t?size)
{
????uint64_t?tickStart?=?life_timer_clock();
????readErrorCnt?=?0;
????for?(uint32_t?idx?=?0;?idx?<?size;?idx?+=?4)
????{
????????*((uint32_t*)(start?+?idx))?=?idx;
????}
????for?(uint32_t?idx?=?0;?idx?<?size;?idx?+=?4)
????{
????????uint32_t?temp?=?*((uint32_t*)(start?+?idx));
????????if?(temp?!=?idx)
????????{
????????????readErrorCnt++;
????????}
????}
????uint64_t?tickEnd?=?life_timer_clock();
????return?((tickEnd?-?tickStart)?/?(CLOCK_GetRootClockFreq(kCLOCK_Root_Bus)?/?1000000));
}
void?test_xecc_sdram_perf(uint32_t?size)
{
????xecc_config_t?config;
????XECC_GetDefaultConfig(&config);
????config.enableXECC?????=?true;
????config.enableWriteECC?=?true;
????config.enableReadECC??=?true;
????config.Region0BaseAddress?=?0x80040000;
????config.Region0EndAddress??=?0x800C0000;
????XECC_Deinit(EXAMPLE_XECC);
????//?寫讀?SDRAM?非?XECC?保護區(qū)域
????uint32_t?normalTimeInUs?=?get_sdram_rw_block_time(0x80000000,?size);
????//?寫讀?SDRAM?XECC?保護區(qū)域(不使能?Data?Swap)
????config.enableSwap?=?false;
????XECC_Init(XECC_SEMC,?&config);
????uint32_t?xeccNoSwapTimeInUs?=?get_sdram_rw_block_time(0x80040000,?size);
????//?寫讀?SDRAM?XECC?保護區(qū)域(使能?Data?Swap)
????XECC_Deinit(XECC_SEMC);
????config.enableSwap?=?true;
????XECC_Init(XECC_SEMC,?&config);
????uint32_t?xeccSwapTimeInUs?=?get_sdram_rw_block_time(0x80040000,?size);
????PRINTF("---------------------------------------rn");
????PRINTF("Write/Read/Compare?data?size:?%drn",?size);
????PRINTF("Write/Read/Compare?time?in?SDRAM?region?XECC?disable?:?%d?usrn",?normalTimeInUs);
????PRINTF("Write/Read/Compare?time?in?SDRAM?region?XECC?enable?without?data?swap?:?%d?usrn",?xeccNoSwapTimeInUs);
????PRINTF("Write/Read/Compare?time?in?SDRAM?region?XECC?enable?with?data?swap?:?%d?usrn",?xeccSwapTimeInUs);
}
get_sdram_rw_block_time() 函數(shù)里實際上也統(tǒng)計了數(shù)據(jù)出錯情況,可用于輔助判斷寫讀是否正常,在恩智浦開發(fā)板測試環(huán)境下應該無 ECC 錯誤,所以這里結(jié)果就略去不表了。
我們現(xiàn)在來看 800MHz 內(nèi)核主頻下對 200MHz SDRAM 訪問性能情況(代碼跑在 ITCM 上),為了結(jié)果可靠,本次測試內(nèi)核頻率沒有設到最高。根據(jù)代碼打印結(jié)果,我們能得到如下結(jié)論:
結(jié)論1:在無 XECC 保護情況下,開啟 D-Cache 能將 SDRAM 讀寫整體訪問速度提升到 4 倍。
結(jié)論2:XECC 使能情況下,是否開啟 Data Swap 功能幾乎不帶來性能變化(在 XECC 外設里 Swap 操作一拍時鐘就能完成,時延可以忽略)。
結(jié)論3:XECC 使能情況下,會降低 SDRAM 讀寫整體訪問性能,降幅在 28% (開啟 D-Cache) 或 11%(不開啟 D-Cache)。
結(jié)論4:XECC 使能情況下,對于讀寫訪問同樣大小數(shù)據(jù)塊,是否開啟 D-Cache,不影響 XECC 校驗處理的時間(即 D-Cache 不加速 XECC)。
至此,i.MXRT1170 XECC開啟及Data Swap功能對于外部RAM的訪問性能影響痞子衡便介紹完畢了,掌聲在哪里~~~