大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是i.MXRT1170 XECC開啟及Data Swap功能對于外部RAM的訪問性能影響。
這篇文章里痞子衡給大家介紹了 XECC 原理及在其使能下操作 NOR Flash 步驟(尤其涉及對 Flash 的 AHB 方式寫),但文章里并沒有涉及性能方面的評估。我們知道 RT1170 上內部 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數據單元而言),xecc_multi_error 示例了雙 bit 報錯(4bits數據單元而言),這兩個例程都借助了 XECC 本身的 Error injection 特性人為制造數據 bit 錯誤來做測試(可以指定 32bits 數據塊中任意位置和個數的 bit 出錯)。
SDK_2_16_000_MIMXRT1170-EVKBboardsevkbmimxrt1170driver_examplesxeccsemcxecc_single_errorcm7
SDK_2_16_000_MIMXRT1170-EVKBboardsevkbmimxrt1170driver_examplesxeccsemcxecc_multi_errorcm7
痞子衡簡單整合了上述兩個例程代碼到一個工程里,這樣可以同時測單/雙/多 bit 錯誤情況,其中主要代碼摘錄如下。此外為了方便觀察不同的錯誤注入導致的結果,我們將待寫入值 sdram_writeBuffer[0] 設為 0x00000000,這樣發(fā)生無法糾錯情況時讀回的數據 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?是用戶數據訪問空間
????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?數據塊進行錯誤注入(這里設定得是錯誤?bit?位置)
????uint32_t?errorData?=?0x00000001;
????XECC_ErrorInjection(XECC_SEMC,?errorData,?0);
????sdram_writeBuffer[0]?=?0x00000000U;
????//?AHB?方式寫數據進?SDRAM
????*(uint32_t?*)0x80000000U?=?sdram_writeBuffer[0];
????//?關閉?DCache?代碼省略...
????//?AHB?方式從?SDRAM?讀回數據
????sdram_readBuffer[0]?=?*(uint32_t?*)0x80000000U;
????while?((!s_xecc_single_error)?&&?(!s_xecc_multi_error))
????{
????}
????//?代碼省略...
}
在放測試結果之前,我們先回顧一下 XECC 錯誤檢測機制。在默認不開啟 Data Swap 特性情況下,對于 32bits 數據塊,XECC 可以糾正其中發(fā)生的 8bits 錯誤,但前提是按序分割開的每 4bits 數據單元僅能有 1bit 錯誤(即分散 bit 錯誤)。如果這 4bits 數據單元里有 2bit 錯誤,那 XECC 會檢測出位置并報告;如果有 3/4bit 錯誤,那已經超出 XECC 處理能力,結果不可預期了。
但如果現場實際環(huán)境發(fā)生連續(xù) bit 錯誤概率高于分散 bit 錯誤,這時候可以考慮開啟 XECC Data Swap 功能,這時候 XECC 處理能力變成可以糾正連續(xù) bit 錯誤,但對于分散 bit 錯誤就無法處理了(如下圖所示,實際上 Swap 是將圖左邊 32bits 原數據打亂再重新組合成圖右邊 32bits 新數據)。
根據上面的理論,我們現在再來看測試結果,那就非常合理了,有些情況下開啟 Data Swap 增強了糾檢錯能力,有些情況下開啟 Data Swap 卻減弱了原來的糾檢錯能力。(注意,Error injection 設定的 errorData 是針對 swap 之后的數據 bit 序而言)
- Note:單 32bits 數據塊寫讀測試時,改動 L1 D-Cache 操作代碼位置(前移到 main 開始),會影響測試結果,這里留一個伏筆,以后具體分析。
二、XECC性能測試
現在我們簡單測試一下內核對 SDRAM 讀寫性能是否受 XECC 影響,就在 semcxecc_multi_error 例程基礎之上,設計了如下代碼,便于測試不同的數據塊大小(比如 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() 函數里實際上也統(tǒng)計了數據出錯情況,可用于輔助判斷寫讀是否正常,在恩智浦開發(fā)板測試環(huán)境下應該無 ECC 錯誤,所以這里結果就略去不表了。
我們現在來看 800MHz 內核主頻下對 200MHz SDRAM 訪問性能情況(代碼跑在 ITCM 上),為了結果可靠,本次測試內核頻率沒有設到最高。根據代碼打印結果,我們能得到如下結論:
結論1:在無 XECC 保護情況下,開啟 D-Cache 能將 SDRAM 讀寫整體訪問速度提升到 4 倍。
結論2:XECC 使能情況下,是否開啟 Data Swap 功能幾乎不帶來性能變化(在 XECC 外設里 Swap 操作一拍時鐘就能完成,時延可以忽略)。
結論3:XECC 使能情況下,會降低 SDRAM 讀寫整體訪問性能,降幅在 28% (開啟 D-Cache) 或 11%(不開啟 D-Cache)。
結論4:XECC 使能情況下,對于讀寫訪問同樣大小數據塊,是否開啟 D-Cache,不影響 XECC 校驗處理的時間(即 D-Cache 不加速 XECC)。
至此,i.MXRT1170 XECC開啟及Data Swap功能對于外部RAM的訪問性能影響痞子衡便介紹完畢了,掌聲在哪里~~~