1. 程式人生 > >創龍TMS320C6748開發板———EDMA簡介及配置

創龍TMS320C6748開發板———EDMA簡介及配置

一、EDMA模組介紹             TMS320C6748是一款高效能DSP,非常適合用來跑大資料量的演算法,而這樣的演算法往往需要保證實時性,那麼這麼大規模的資料怎麼進行運算能夠讓程式跑的最快,我們知道DSP中運算最快的儲存單元是RAM區,但是RAM畢竟有限的,無法儲存大量資料,因而我們只能把資料存在DDR中,這時我們需要一種工具能夠將資料從DDR中匯入RAM中運算,算完的結果再發回DDR中儲存。大家學習《微機原理》的時候應該聽說過DMA吧,簡單來說就是CPU把資料傳送的源、目的、資料個數等資訊交給DMA,讓DMA控制資料傳輸,在此期間,CPU可以執行其他程式,等到DMA控制的資料傳輸完成,傳送中斷告訴CPU我的資料傳輸完成了,你來處理吧,因而提高了演算法的速度,Ti公司為TMS320C6748量身設計了增強版直接儲存器訪問控制器EDMA3。        EDMA3一共有32個通道,通道的優先順序可選,可以實現資料傳輸的無縫連結,為什麼是無縫的,後面我們會具體說到。利用EDMA,可以實現片記憶體儲器、片內外設以及外部儲存器之間的資料傳輸。 1、EDMA概述        前面已經介紹過了DMA的原理,下面我們來說EDMA能夠完成哪些功能。        (1)一維二維資料傳輸,包括資料轉置,不知道你在寫程式時有沒有遇到需要轉置的資料矩陣,這裡的轉置其實也是提高演算法運算速度的一種手段吧,在DSP配套的MATHLIB檔案中提供了一種基於向量定址的快速演算法,我們知道無論什麼處理器運算的第一步一定是待計算資料的定址,然後才是運算,資料定址其實需要佔用非常多的時間,而向量定址的快速演算法可以對一個連續的向量進行高速運算,因為每計算完一次,地址自動加1就行,節省了運算時間。        (2)事件、鏈式事件觸發,也就是說可以利用一箇中斷,或者事件觸發EDMA傳輸,例如當SPI、UPP傳輸完資料後給EDMA控制器一個訊號,告訴EDMA我的資料準備好了,存入DDR吧。        (3)地址過載,EDMA應用的是PaRAM儲存每組要傳輸資料的資訊,源、目的地址,資料個數等資訊,其中有一個參量是連結到其他PaRAM的地址,額,有點複雜,下面具體說吧。        (4)乒乓儲存,非常實用高效的一種資料流控制方法,簡單來說就是將RAM分為兩個部分,第一個週期第一段資料由EDMA傳入RAM1,第二個週期對RAM1中資料進行處理,同時,第二段資料由EDMA傳入RAM2,第三個週期對RAM2中資料進行處理,同時第三段資料由EDMA傳入RAM1 ,如此迴圈,可以對資料進行高效處理。        EDMA通道控制器主要由以下5個部分組成:事件相關暫存器、事件選擇器、引數RAM、QDMA檢測器、結束和錯誤檢測器。事件暫存器完成對EDMA事件的捕獲,一個事件相當於一個同步訊號,由它觸發某個EDMA通道開始傳輸資料。如果有多個事件同時發生,由事件選擇器對他們進行識別。在EDMA的引數RAM中存放與事件相關的傳輸引數,這些引數送入傳輸請求,進而產生對外設讀寫操作所需要的地址。EDMA的通道控制器和傳輸器的結構如上圖所示。 2、EDMA傳輸相關 (1)傳輸資料型別 EDMA3 的傳輸型別EDMA3 的傳輸是在3 個維度上定義的: 1. Array (A):一次傳輸中的一維指ACNT 個連續位元組。 2. Frame (B):一次傳輸中的二維指BCNT 個含有ACNT 個位元組的陣列array。      每個在二維傳輸中的array 是通過SRCBIDX/DSTBIDX 來分隔的。 3. Block (C):一次傳輸中的三維指CCNT 個含有BCNT 個陣列的幀,每個陣列array 含有ACNT 個位元組。在三維上進行的傳輸是通過SRCCIDX/DSTCIDX 與前次傳輸進行分隔的。
  在這三種維度上,EDMA3 只支援兩種同步方式的傳輸:A 同步傳輸和AB 同步傳輸,而EDMA3並不直接支援ABC 同步傳輸,但可以通過將多個AB 同步傳輸通過鏈方式來間接支援。A 同步傳輸方式相對AB 同步傳輸方式簡單,下面著重分析AB 同步傳輸方式。
  在一個 AB 同步的傳輸中,EDMA3 同步事件會在2 個維度上即一幀對傳輸進行初始化。
  即每個事件所提交的傳輸請求會要求傳輸一幀的資料,即BCNT 個array,每個array 含有ACNT 個連續位元組,因此一次傳輸BCNTxACNT 個位元組。因此,在AB 同步傳輸的PaRAM時,進行傳輸的次數為CCNT 次,即該引數表對應的事件數為CCNT 個。
  陣列 array 間通過SRCBIDX 及DSTBIDX 兩個引數進行分隔,如下圖所示,陣列N 的起始地址等於陣列N-1 的起始地址加上SRCBIDX/DSTBIDX。幀間通過SRCCIDX 及DSTCIDX 引數進行分隔。對於一個AB 同步傳輸,一個傳輸請求TR 被提交後,地址的更新是通過對幀頭陣列的地址加SRCCIDX/DSTCIDX來實現的。 (2)傳輸觸發方式 DMA 傳輸的觸發方式有三種方式可以觸發在DMA 通道上的傳輸:
  1.Event-triggered transfer request 事件觸發傳輸請求:外設、系統、外部事件產生的傳輸請求。
  2.Manually-triggered transfer request 手動觸發傳輸請求:CPU 向相應的事件置位暫存器(ESR/ESRH)中寫1 來觸發傳輸。
  3.Chain-triggered transfer request 鏈觸發傳輸請求:另一傳輸完成時觸發的傳輸。
  外設或引腳產生事件時,事件暫存器中相應位將置1(ER.En = 1)。如果事件使能暫存器(EER)相應位被使能(EER.En = 1),那麼EDMA3CC 將會按優先順序處理該事件並將其排隊。        3、EDMA暫存器 (1)通道控制暫存器          QCHMAP
n:[PAENTRY]QDMA連結到指定的PaRAM,PaRAM一共有128個引數集,也就意味可以配置128組EDMA傳輸引數。          DMAQNUMnQDMAQNUM安排事件到佇列0或者佇列1中,佇列0優先順序高於佇列1,推薦,高優先順序用於短時突發和單元素傳輸,低優先順序用於長時塊的搬移。另外一旦一個佇列裡的請求滿了,那麼這個佇列如果再來請求的時候,EDMA控制器會STALL,所以所有的請求都會不響應,直到那個佇列有空閒位置才繼續響應事件。所以,我們不要讓某個級別的請求太過繁忙,從而導致STALL發生。比較好的情況是:讓各個級別的請求的負擔基本差不多,這樣避免EDMA控制器阻塞。        ER:只讀,事件暫存器,但設定相應位後相應的事件被啟用。ESR:事件設定暫存器。ECR:事件清除暫存器。CER:事件連結暫存器,也就是說本事件發生的同時,讓另一事件對應暫存器ER的位為有效,EDMA處理完第一個事件,將繼續處理第二個事件。EER:只讀,事件使能暫存器,只有該暫存器的位使能,對應的事件才發生了才能使ER置位,也才能觸發EDMA傳輸。EECR:事件使能清除暫存器,EESR,事件使能設定暫存器。 (2)PaRAM暫存器(引數RAM暫存器)          OPT
傳輸配置引數 SRC源地址引數。 A_B_CNT高16位為2維計數器值,低16位為1維計數器值.        DST目的地址引數。        SRC_DST_BIDX高16位為傳輸目的索引,低16位為傳輸源的索引。        LINK_BCNTRLD高16位為二維傳輸引數過載,也就是說本次EDMA傳輸完成,該引數會複製到A_B_CNT的高16位,這樣可以再次出=觸發該EDMA而傳輸不同的引數,低16位為引數RAM連結地址。也即是說本次EDMA傳輸完成,低16位為引數RAM連結地址所指向的PaRAM中的引數複製到當前所使用的PaRAM。        SRC_DST_CIDX
高16位為三維傳輸目的索引,低16位為三維傳輸源索引。        CCNT低16位為3維傳輸計數器。 索引,簡單來說就是在傳輸完一個數據後源/目的地址加幾。        4、EDMA例程        (1) 手動觸發事件11,可執行PaRAM11中的傳遞引數並通過PaRAM.LINK連結到PaRAM10,再手動觸發事件11即可執行PaRAM10中的傳遞引數。 extern void setup_EDMA ( void)//EDMA3初始化,通道10,使用CPU開始中斷 {        // Clear EventRegisters        CSL_FINST(edma3ccRegs->ECR, EDMA3CC_ECR_REG, MASK);//清空中斷事件        CSL_FINST(edma3ccRegs->SECR, EDMA3CC_SECR_REG, MASK);//清空中斷事件 /*---------------------------------- EDMA Event10-------------------------------*/        // Enable Channel 10to DSP (Region 1)        CSL_FINST(edma3ccRegs->DRA[CSL_EDMA3_REGION_1].DRAE,                             EDMA3CC_DRAE_E10,ENABLE);//設定DRA1通道的第10個通道        // Assign Channel 10to Queue 0        CSL_FINST(edma3ccRegs->DMAQNUM[1], EDMA3CC_DMAQNUM_E2, Q0);//將通道10放置在佇列0中;        //由於只定義了E0-E7,在NUM0時對應E2,在NUM1時對應E10,查表可知        // Initialize PaRAMTransfer Context for Event 10 //     init_PaRAM_event10();//設定引數向量        // Enable Channel 10Event Register        CSL_FINST(edma3ccRegs->EESR, EDMA3CC_EESR_E10, SET);//使能事件10        // Enable Interruptsfor Channel 10        CSL_FINST(edma3ccRegs->IESR, EDMA3CC_IESR_I10, SET);//允許通道10中斷 /*---------------------------------- EDMA Event11-------------------------------*/        // Enable Channel 11to DSP (Region 1)        CSL_FINST(edma3ccRegs->DRA[CSL_EDMA3_REGION_1].DRAE,                             EDMA3CC_DRAE_E11,ENABLE);//設定DRA1通道的第11個通道        // Assign Channel 11to Queue 0        CSL_FINST(edma3ccRegs->DMAQNUM[1], EDMA3CC_DMAQNUM_E3, Q0);//將通道11放置在佇列0中;        //由於只定義了E0-E7,在NUM0時對應E3,在NUM1時對應E11,查表可知        // Initialize PaRAMTransfer Context for Event 11        //init_PaRAM_event11();//設定引數向量        // Enable Channel 11Event Register        CSL_FINST(edma3ccRegs->EESR, EDMA3CC_EESR_E11, SET);//使能事件10        // Enable Interruptsfor Channel 11        CSL_FINST(edma3ccRegs->IESR, EDMA3CC_IESR_I11, SET);//允許通道10中斷 } /*---------------------------------------------------------------------------*/ /* setup_EDMA */ /*---------------------------------------------------------------------------*/ void main(void) {           setup_EDMA();//初始化EDMA3暫存器 for(jj=0;jj<2;jj++)     {               for(kk=0;kk<256;kk++)               {                      SRC_AA[jj][kk]=kk*(jj+1);               }     }        for(jj=0;jj<2;jj++)        {               for(kk=0;kk<256;kk++)               {                      SRC_BB[jj][kk]=kk;               }        }     for(jj=0;jj<256;jj++)     {          SRC_CC[jj]=2*jj;     }     for(jj=0;jj<256;jj++)     {          SRC_DD[jj]=3*jj;     }     EDMA_event11_Buffer_transfer(1,0,2,2,256);//flag(單行轉秩1/矩陣轉秩other);轉換第x行;資料型別;行數;列數     EDMA_event10_Buffer_transfer(1,1,2,2,256);//flag(單行轉秩1/矩陣轉秩other);轉換第x行;資料型別;行數;列數     CSL_FINST(edma3ccRegs->ESR, EDMA3CC_ESR_E11, SET);     delay(10000);     CSL_FINST(edma3ccRegs->ESR, EDMA3CC_ESR_E11, SET);     delay(10000);     } /*--------------------------------陣列轉秩-----------------------------------*/ // function:完成通道10單行/矩陣轉秩儲存,需要在函式中修改源、目的地址,當轉秩矩陣時,引數為轉換第0行 // parameters:flag(單行轉秩1/矩陣轉秩other);轉換第x行;資料型別;行數;列數 int EDMA_event10_Buffer_transfer(Uint16 flag,Uint16 trans_number,Uint16 type_data,Uint16 row,Uint16 column)//引數RAM配置 {        int time_EDMA=0;        edma3ccRegs->PARAMSET[EDMA_EVENT10].OPT = CSL_EDMA3CC_OPT_RESETVAL;//引數RAM復位        // ConfigPaRAM OPT (Enable TC Interrupt & ITC Chaining; Set TCC)//允許產生中斷,對應事件10        edma3ccRegs->PARAMSET[EDMA_EVENT10].OPT =               CSL_FMKT(EDMA3CC_OPT_ITCCHEN,ENABLE) |               CSL_FMKT(EDMA3CC_OPT_TCINTEN,ENABLE) |               CSL_FMK(EDMA3CC_OPT_TCC,EDMA_EVENT10)|               CSL_FMKT(EDMA3CC_OPT_TCCMOD,NORMAL)   |               CSL_FMKT(EDMA3CC_OPT_FWID,8BIT)          |//僅僅針對常數位有效               CSL_FMKT(EDMA3CC_OPT_STATIC,NORMAL)      |               CSL_FMKT(EDMA3CC_OPT_SYNCDIM,ASYNC)   |               CSL_FMKT(EDMA3CC_OPT_DAM,INCR)           |               CSL_FMKT(EDMA3CC_OPT_SAM,INCR);        // Initialize EDMAEvent Src and Dst Addresses        edma3ccRegs->PARAMSET[EDMA_EVENT10].SRC = (Uint32)&(SRC_AA);//設定源陣列地址        edma3ccRegs->PARAMSET[EDMA_EVENT10].DST = (Uint32)&(DST_BB[0][trans_number]);//設定目的陣列地址        // Set EDMA EventPaRAM A,B,C CNT        edma3ccRegs->PARAMSET[EDMA_EVENT10].A_B_CNT =               CSL_FMK(EDMA3CC_A_B_CNT_ACNT,type_data) |//設定傳輸資料型別               CSL_FMK(EDMA3CC_A_B_CNT_BCNT,column);//設定傳輸數目        if(flag==1)        {               edma3ccRegs->PARAMSET[EDMA_EVENT10].CCNT = 1;        }        else        {               edma3ccRegs->PARAMSET[EDMA_EVENT10].CCNT = row;        }        edma3ccRegs->PARAMSET[EDMA_EVENT10].SRC_DST_BIDX =                      CSL_FMK(EDMA3CC_SRC_DST_BIDX_SRCBIDX,type_data) |                      CSL_FMK(EDMA3CC_SRC_DST_BIDX_DSTBIDX,row*type_data);//二維索引        edma3ccRegs->PARAMSET[EDMA_EVENT10].SRC_DST_CIDX =                             CSL_FMK(EDMA3CC_SRC_DST_CIDX_SRCCIDX,type_data) |                             CSL_FMK(EDMA3CC_SRC_DST_CIDX_DSTCIDX,(1-column)*type_data*row+type_data);//三維索引        // Set EDMA EventPaRAM LINK and BCNTRLD        edma3ccRegs->PARAMSET[EDMA_EVENT10].LINK_BCNTRLD =               CSL_FMK(EDMA3CC_LINK_BCNTRLD_LINK,0xFFFF) |               CSL_FMK(EDMA3CC_LINK_BCNTRLD_BCNTRLD,column);        time_EDMA=1;        return time_EDMA; } /*--------------------------------陣列轉秩PaRAM引數-----------------------------------*/ // function:完成通道11單行/矩陣轉秩儲存,需要在函式中修改源、目的地址,當轉秩矩陣時,引數為轉換第0行 // parameters:flag(單行轉秩1/矩陣轉秩other);轉換第x行;資料型別;行數;列數 int EDMA_event11_Buffer_transfer(Uint16 flag,Uint16 trans_number,Uint16 type_data,Uint16 row,Uint16 column)//引數RAM配置 {        int time_EDMA=0;        edma3ccRegs->PARAMSET[EDMA_EVENT11].OPT = CSL_EDMA3CC_OPT_RESETVAL;//引數RAM復位        // ConfigPaRAM OPT (Enable TC Interrupt & ITC Chaining; Set TCC)//允許產生中斷,對應事件10        edma3ccRegs->PARAMSET[EDMA_EVENT11].OPT =               CSL_FMKT(EDMA3CC_OPT_ITCCHEN,ENABLE) |               CSL_FMKT(EDMA3CC_OPT_TCINTEN,ENABLE) |               CSL_FMK(EDMA3CC_OPT_TCC,EDMA_EVENT11)|               CSL_FMKT(EDMA3CC_OPT_TCCMOD,NORMAL)   |               CSL_FMKT(EDMA3CC_OPT_FWID,8BIT)          |//僅僅針對常數位有效               CSL_FMKT(EDMA3CC_OPT_STATIC,NORMAL)      |               CSL_FMKT(EDMA3CC_OPT_SYNCDIM,ASYNC)   |               CSL_FMKT(EDMA3CC_OPT_DAM,INCR)           |               CSL_FMKT(EDMA3CC_OPT_SAM,INCR);        // Initialize EDMAEvent Src and Dst Addresses        edma3ccRegs->PARAMSET[EDMA_EVENT11].SRC = (Uint32)&(SRC_CC);//設定源陣列地址        edma3ccRegs->PARAMSET[EDMA_EVENT11].DST = (Uint32)&(DST_BB[0][trans_number]);//設定目的陣列地址        // Set EDMA EventPaRAM A,B,C CNT        edma3ccRegs->PARAMSET[EDMA_EVENT11].A_B_CNT =               CSL_FMK(EDMA3CC_A_B_CNT_ACNT,type_data) |//設定傳輸資料型別               CSL_FMK(EDMA3CC_A_B_CNT_BCNT,column);//設定傳輸數目        if(flag==1)        {               edma3ccRegs->PARAMSET[EDMA_EVENT11].CCNT = 1;        }        else        {               edma3ccRegs->PARAMSET[EDMA_EVENT11].CCNT = row;        }        edma3ccRegs->PARAMSET[EDMA_EVENT11].SRC_DST_BIDX =                      CSL_FMK(EDMA3CC_SRC_DST_BIDX_SRCBIDX,type_data) |                      CSL_FMK(EDMA3CC_SRC_DST_BIDX_DSTBIDX,row*type_data);//二維索引        edma3ccRegs->PARAMSET[EDMA_EVENT11].SRC_DST_CIDX =                             CSL_FMK(EDMA3CC_SRC_DST_CIDX_SRCCIDX,type_data) |                             CSL_FMK(EDMA3CC_SRC_DST_CIDX_DSTCIDX,(1-column)*type_data*row+type_data);//三維索引        // Set EDMA EventPaRAM LINK and BCNTRLD        edma3ccRegs->PARAMSET[EDMA_EVENT11].LINK_BCNTRLD =               CSL_FMK(EDMA3CC_LINK_BCNTRLD_LINK,0x4140) |               CSL_FMK(EDMA3CC_LINK_BCNTRLD_BCNTRLD,column);        time_EDMA=1;        return time_EDMA; }        這裡PaRAM.LINK是這麼計算的:        每個PaRAM佔用32個字,那麼PaRAM10就是10*32=320=140h,那麼連結地址就是0x4140。