EMIF介面與FPGA的互聯(轉)
reference: https://blog.csdn.net/ruby97/article/details/7539151
DSP6455的EMIFA模組
之前介紹了DSP6455的GPIO和中斷部分。今天,繼續介紹EMIFA模組。
關於C6000系列的GPIO,請參考:C6000系列DSP的GPIO模組
關於C6000系列的中斷系統,請參考:C6000系列DSP的中斷系統
背景
使用FPGA系統進行視訊採集,DSP進行視訊處理需要了解以下知識:
- 1. DSP-C6000系列的中斷與GPIO系統
- 2. DSP-C6000系列的EMIFA模組
- 3. DSP-C6000系列的EDMA模組
- 4. FPGA的乒乓RAM
- 5. 一種視訊格式(例如VGA,PAL等)
- 6. 視訊處理演算法
之前已經介紹了第一部分,今天介紹第二部分。
主題
EMIF是External Memory Interface的簡稱。個人認為它是DSP比較強大的地方之一。通過EMIF介面,使得DSP可以和FPGA很方便地進行大資料量的資料傳輸。
C6455的EMIFA可以訪問多種外部儲存器,比如:SRAM,ROM,FLASH等等。當然,也包括FPGA。本文的重點就是介紹使用EMIFA介面與FPGA建立無縫連線。
--------------------------------------------華麗分割------------------------------------------------
EMIFA
根據習慣,還是先貼圖,框圖總給人一目瞭然的感覺。
這是官方文件給出的EMIFA模組的介面示意圖,乍一看,複雜的很。好多引腳而且還有好多複用。沒關係,我們再貼一張,你就會感覺輕鬆很多了。
這一張圖首先是把EMIFA模組的介面分了類,然和呢,我把在與FPGA通訊場合下所需要使用的管腳使用紅色框框標註了出來。是不是少了很多呢。歸納一下標註的管腳,如下:
- AED[63:0] 64位資料匯流排
- AEA[19:0] 20位地址匯流排(Optional)
- ACE2 片選訊號(低有效)
- AECLKOUT 時鐘訊號
- ASWE 寫使能(低有效)
- ASRE 讀使能(低有效)
(注:應用場合是DSP讀FPGA內部RAM中的影象資料,其他場合續根據情況調整)
由於FPGA的可程式設計性,使得一切從DSP看來簡單了許多。因為DSP面對的“儲存器”顯得格外智慧。甚至連地址線都可以不需要。
下面,我們來一一分析上述的訊號。
- 首先,應該是片選訊號CE。這裡不得不提到DSP的地址空間。下圖是DSP6455的EMIFA對映情況
- EMIFA共支援4個外部儲存器,比如可以把CE2分配給FPGA,CE3分配給SRAM,CE4分配給FLASH等。
- 每個外部儲存器的定址空間大小是8MB。20根地址線即2的20次方,也就是1MB,此外由於資料匯流排是64位的,故對應的定址空間是8MB
由於FPGA內部時序邏輯可以產生地址,所以我們可以不使用地址線。這樣,下面的事情就簡單了。只要把CE2管腳和FPGA的某一個通用IO口連上即可。
在讀取FPGA內部RAM資料時告訴EDMA要讀取的資料的基地址是0xA0000000,以及讀取的資料的長度即可。
- 第二個訊號,ECLKOUT,即時鐘訊號的。因為FPGA工作是需要時鐘激勵的,沒有時鐘訊號怎麼產生地址邏輯呢?此外,時鐘頻率不能過高,要考慮到FPGA晶片的能力。OK,因為有了同步時鐘,所以EMIFA模組的工作模式也就確定了,即同步工作模式。
- 第三個訊號,包括2個,即ASRE,ASWE。更熟悉的叫法是RE,WE。讀使能和寫使能。這個就不贅述了。
- 第四個訊號,資料匯流排&地址匯流排。也不贅述了。
經過上面的分析,我們可以簡要的畫出FPGA與DSP的連線圖:
在連線的思路清晰之後,我們可以開始配置EMIFA的暫存器了。其實也就只有1個比較重要的暫存器,即CEnCFG。該暫存器有兩套完全不同的配置。分別對應於同步儲存器模式和非同步儲存器模式。由於FPGA內部RAM工作於同步模式,故我們來看一下同步模式下該暫存器的配置。
SSEL設定為1時,表示該CE對應同步模式的外部儲存器。 在與FPGA連線時,主要考慮以下四個引數:R_ENABLE | 設定SRE/SADS管腳功能 |
值為 1 | 管腳功能為SRE,即Read Enable |
值為 0 | 管腳功能為SADS |
W_LTNCY | 寫延時週期 |
值為 00 | 0週期延時 |
值為 01 | 1週期延時 |
值為 10 | 2週期延時 |
值為 11 | 3週期延時 |
R_LTNCY | 讀延時週期 |
值為 01 | 1週期延時 |
值為 10 | 2週期延時 |
值為 11 | 3週期延時 |
讀延時:當CE和RE同時為低電平後,表示DSP開始讀FPGA的RAM,經過R_LTNCY個ECLKOUT週期後第一個資料出現在資料匯流排上
SBSIZE | 資料位寬 |
值為 00 | 8位資料匯流排 |
值為 01 | 16位資料匯流排 |
值為 10 | 32位資料匯流排 |
值為 11 | 64位資料匯流排 |
EMIFA之CSL
使用CSL配置EMIFA模組時,主要的步驟如下:
- l 1. 使能裝置EMIFA模組
- l 2. 配置CEnCFG暫存器
- l 3. 初始化EMIFA模組
- l 4. 開啟EMIFA模組
- l 5. 把2中配置的引數設定到開啟的EMIFA模組中
完整配置程式碼:(把EMIFA的CE2配置為以FPGA作為外部儲存器,64位資料線,2個週期的讀延時)
/*----------------------------------------------------------------------------------- * * 初始化EMIFA * -----------------------------------------------------------------------------------*/ #define EMIFA_MEMTYPE_ASYNC 0 #define EMIFA_MEMTYPE_SYNC 1 #define EMIFA_CE2_BASE_ADDR (0xA0000000)//地址空間基地址 #define CSL_EMIFA_SYNCCFG_RLTNCY_PARAMETER 2//讀延時2週期 #define CSL_EMIFA_SYNCCFG_SBSIZE_PARAMETER 3//64位資料匯流排 #define CSL_EMIFA_SYNCCFG_READEN_PARAMETER 1//SRE //CEnCFG暫存器引數巨集 #define CSL_EMIFA_SYNCCFG_PARAMETER {\ (Uint8)CSL_EMIFA_SYNCCFG_READBYTEEN_DEFAULT, \ (Uint8)CSL_EMIFA_SYNCCFG_CHIPENEXT_DEFAULT, \ (Uint8)CSL_EMIFA_SYNCCFG_READEN_PARAMETER, \ (Uint8)CSL_EMIFA_SYNCCFG_WLTNCY_DEFAULT, \ (Uint8)CSL_EMIFA_SYNCCFG_RLTNCY_PARAMETER, \ (Uint8)CSL_EMIFA_SYNCCFG_SBSIZE_PARAMETER \ } void Init_EMIF() { CSL_EmifaObj emifaObj; CSL_Status status; CSL_EmifaHwSetup hwSetup; CSL_EmifaHandle hEmifa; CSL_EmifaMemType syncVal; CSL_EmifaSync syncMem = CSL_EMIFA_SYNCCFG_PARAMETER; memset(&emifaObj, 0, sizeof(CSL_EmifaObj)); memset(&hwSetup, 0, sizeof(CSL_EmifaHwSetup)); //步驟1: 使能裝置的EMIFA功能(不用先解鎖外設暫存器) CSL_FINST(((CSL_DevRegs*)CSL_DEV_REGS)->PERCFG1, DEV_PERCFG1_EMIFACTL, ENABLE); //步驟2:配置CE2CFG暫存器 syncVal.ssel = EMIFA_MEMTYPE_SYNC; syncVal.async = NULL; syncVal.sync = &syncMem; hwSetup.ceCfg[0] = &syncVal; hwSetup.ceCfg[1] = NULL; hwSetup.ceCfg[2] = NULL; hwSetup.ceCfg[3] = NULL; //步驟3:初始化EMIFA模組 status = CSL_emifaInit(NULL); #ifdef SHOW_PRINTF if (status != CSL_SOK) { printf("EMIFA: Initialization error.\n"); printf("\tReason: CSL_emifaInit [status = 0x%x].\n", status); return; } else { printf("EMIFA: Module Initialized.\n"); } #endif //步驟4:開啟EMIFA模組 hEmifa = CSL_emifaOpen(&emifaObj,CSL_EMIFA,NULL,&status); #ifdef SHOW_PRINTF if ((status != CSL_SOK) || (hEmifa == NULL)) { printf("EMIFA: Error opening the instance. [status = 0x%x, hEmifa \ = 0x%x]\n", status, hEmifa); return; } else { printf("EMIFA: Module instance opened.\n"); } #endif //步驟5:把步驟2中配置的引數設定到開啟的EMIFA模組中 status = CSL_emifaHwSetup(hEmifa,&hwSetup); #ifdef SHOW_PRINTF if (status != CSL_SOK) { printf("EMIFA: Error in HW Setup.\n"); printf("Read write operation fails\n"); return; } else { printf("EMIFA: Module Hardware setup is successful.\n"); } #endif }