DMA原理和實驗

來源:互聯網
上載者:User

最近忙於驅動這塊,於是我自己整理了有關S3C2410的DMA的基本編程及DMA的相關寄存器操作。
一.DMA訪問的原理
    1.DMA(Driect Memory Access)訪問的概述
    當系統記憶體想要與高速外設或者記憶體的不同地區之間進行大資料的快速傳送時,查詢和中斷這兩種方式不能滿足要求:DMA就是為解決這樣的問題提出來的。
(中斷方式較之查詢方式來說,可以提高CPU的利用率和保證對外設響應的即時性,但對於高速外設,中斷方式不能滿足資料轉送速度的要求。因為,中斷方式下,每次中斷均需儲存斷點和現場;中斷返回時,要恢複斷點和現場。同時,進入中斷和從中斷返回均使CPU指令隊列被清除。這些原因,使得中斷方式難以滿足高速外設對傳輸速度的要求。)
     採用DMA方式,在一段時間內,由DMA控制器取代CPU,獲得匯流排控制權,從而實現記憶體與外設或者記憶體不同地區間的大量資料快速傳遞。

   2.DMA的工作過程
    1.當外設準備就緒,希望進行DMA傳送時,向DMA控制器(DMAC)發出DMA請求訊號(DREQ)。DMAC收到此訊號後,向CPU發出匯流排請求訊號(HOLD)。
  2.CPU在完成當前匯流排操作後立即對DMA請求訊號做出響應:先放棄對匯流排的控制(包括控制匯流排、資料匯流排、地址匯流排),然後將有效HLDA訊號加到DMAC上。此時,CPU便放棄對匯流排的控制,DMAC獲得匯流排的控制權。
  3.DMAC獲得匯流排的控制權後,向地址匯流排發出地址訊號,指出傳送過程需使用的記憶體位址(DMAC內部設有“地址寄存器”,在DMA操作過程中,每傳送一位元組資料,DMAC自動修改地址寄存器的值,以指向下一個記憶體位址)。同時,向外設發出DMA應答訊號(DACK),實現該外設與記憶體之間進行DMA傳送。
  4.在DMA傳送期間,DMAC發出記憶體和外設的讀/寫訊號。
  5.為了決定資料區塊傳輸的位元組數,在DMAC內部必須有一個“位元組計數器”。在開始時,由軟體佈建資料區塊的長度,在DMA傳送過程中,每傳送一位元組,位元組計數器減1,減為0時,該次DMA傳輸結束。
  6.DMA過程結束時,DMAC向CPU發出結束訊號(撤消HOLD請求),將匯流排控制權交還CPU。

二.DMA傳送的方式
DMA傳送的方式分為三種:I/O介面到儲存空間、儲存空間到I/O介面、儲存空間到儲存空間
   1.I/O介面到儲存空間方式
    當想要由I/O介面到儲存空間的資料傳送時,來自I/O介面的資料利用DMAC送出控制訊號,將資料輸送到資料匯流排D0-D7上,同時DMAC送出儲存空間單元地址及控制訊號,將存於D0-D7上的資料寫入選中的儲存單元中。這樣就完成了I/O介面到儲存空間的一個位元組的傳送。同時DMAC修改“地址寄存器”和“位元組計數器”的內容。
   2.儲存空間到I/O介面方式
    與上面情況類似,在進行傳送時,DMAC送出儲存空間地址和控制訊號,將選中的儲存空間單元的內容讀入資料匯流排的D0-D7上,然後,DMAC送出控制訊號,將資料寫到指定的連接埠中去,再DMAC修改“地址寄存器”和“位元組計數器”的內容。
   3.儲存空間到儲存空間方式
    這種方式的DMA資料傳送是用“資料區塊”方式傳送(連續進行多個位元組的傳輸,只有當“位元組計數器”減為0,才完成一次DMA傳送)。首先,送出儲存空間源的地址和控制訊號,將選中記憶體單元的資料暫存,然後修改“地址寄存器”和“位元組計數器”的值,接著,送出儲存空間目標的地址和控制訊號,將暫存的資料通過資料匯流排寫入到儲存空間的目的地區域中,最後修改“地址寄存器”和“位元組計數器”的內容,當“位元組計數器”的值減少到零時可結束一次DMA。

 

三.S3C2410的DMA訪問相關操作
1.(本文採用S3C2410開發板)S3C2410支援4通道DMA控制器,在系統匯流排和外圍匯流排之間。每個通道都能實現快速資料傳送。每個通道能處理下面4種情況:
     1.源和目標器件都在系統匯流排AHB上。
     2.源器件在系統匯流排AHB上,目標器件在外圍匯流排APB上。
     3.源器件在外圍匯流排APB上,目標器件在系統匯流排AHB上。
     4.源和目標器件都在外圍匯流排APB上。
DMA操作可以通過軟體或者硬體來初始化。如果DCON寄存器選擇採用硬體(H/W)DMA請求模式,那麼DMA控制器可以從對應通道的DMA請求源中選擇一個。如果DCON寄存器選擇採用軟體(S/W)DMA請求,那麼這些DMA請求源將沒有任何意義。DMA請求源如下表所列。

        nXDREQ0和nXDREQ1代表兩個外部源,I2SSDO和I2SSDI分別代表IIS的傳輸和發送。

2.DMA工作模式
DMA的工作模式共有兩種:單一服務模式和整體服務模式。
在單一服務模式下,一次DMA請求完成一項原子操作(操作不可間斷) 。
在整體服務模式下,一次DMA請求完成一批原子操作,直到CURR_TC等於0,表示完成一次整體服務。

3.DMA狀態機器描述
DMA可以有3種FSM(Finite State Machine,有限狀態機器)進行操作。
狀態1:初始狀態,DMA等待一個DMA請求,若請求到達,進入狀態2。此階段,DMA ACK和INT REQ 為0。
狀態2:在此狀態,DMA ACK 變為1,計數器CURR_TC的值從DCONn[19:0 ]裝載。DMA ACK保持1,直到它被清0。
狀態3:在此狀態,對DMA進行原子操作的sub-FSM(子狀態機器)進行初始化。sub-FSM 從源地址讀取資料後將資料寫入目標地址。對於這種操作方式,資料大小和傳輸大小應給予考慮。在整體服務方式中,這種操作重複直到計數器CURR_TC變為0,然而在單一模式中只進行一次。當子FSM完成每個原子操作,主FSM倒計CURR_TC。另外,當CURR_TC為0 和中斷設定DCONn[29]為1時,主FSM發出INT REQ(插斷要求訊號),假如以下任一種情況發生,要清除DMA ACK 。
     (1)在單一模式下,主FSM的3種狀態執行完後就停止,並等待下一個DMA請求。對於每個原子操作,DMA ACK先置1,完成後清0。
     (2)在整體服務模式下,主FSM一直在狀態3等待,直到CURR_TC變為0。因此,DMA ACK在整個傳送過程中置1,CURR_TC變為0時則清0。

4.DMA基本時序
DMA服務意味著在DMA操作中執行一次讀寫周期,形成一個DMA操作。為S3C2410的DMA操作的基本時序。
nXDREQ請求生效並經過2CLK周期同步後,nXDACK響應並開始生效,但至少還要經過3CLK的周期延遲,DMA控制器才可獲得匯流排的控制權,並開始資料轉送。當DMA操作完成後,XnXDACK被設無效。

5.請求和答應的協議有兩種:請求(Demand)和握手(Handshake)模式。(區別:在一個傳輸末尾,DMA檢測兩次同步的XnXDREQ的狀態)
請求模式:如果XnXDREQ保持有效,則下一個傳輸開始馬上開始,否則它會一直等到XnXDREQ有效。
握手模式:如果XnXDREQ無效,則DMA在兩個同步周期內將XnXDACK設無效,否則它一直等到XnXDREQ無效。

6.傳輸大小
DMA的一次原子操作中,可以是Unit模式(傳輸一個Data Size)和brust模式(傳輸4個Data Size)。在DCON[28]中設定。

7.Data Size:指一次原子操作的資料位元寬,可以為8,16,32。在DCON[21:20]中設定。

 

四.DMA控制器
S3C2410每個DMA通道有9個控制寄存器,4個通道,共有36個寄存器。每個DMA通道有6個用於控制DMA傳輸,3個用於監控DMA控制器的狀態。要進行DMA操作,首先需要對這些寄存器進行正確配置。下面介紹相關寄存器。(由於圖太多,這裡沒有貼出來,大家可以在三星的S3C2401 Data Sheet裡面找到對應的表)
1、DMA初始化資料來源(DISRC)寄存器組:分別對應著4個相關寄存器,主要用於初始化傳輸的資料來源的基地址。
2、DMA初始化資料來源控制(DISRCC)寄存器:主要用於選擇資料來源的位置(在APB還是在AHB上)以及決定地址遞增還是固定。
3、DMA初始化目標(DIDST)寄存器:主要用於初始化傳輸目標開始地址。
4、DMA初始化目標控制(DIDSTC)寄存器:主要用於選擇目標的位置(在APB還是在AHB上)以及決定地址遞增還是固定。
5、DMA控制(DCON)寄存器:主要功能選擇請求模式或者握手模式、選擇DREQ/DACK同步、使能/禁止CURR_TC中斷設定、選擇Data Size、選擇單一服務或整體服務模式、選擇DMA請求源及初始化傳輸計數器等。
6、DMA狀態(DSTAT)寄存器:主要用於讀取DMA控制器的狀態及傳輸計數器的當前值。
7、DMA當前源(DCSRC)寄存器:主要用於讀取DMA控制器當前源地址的值。
8、DMA當前目標(DCDST)寄存器:主要用於讀取DMA控制器當前目標地址的值。
9、中斷屏蔽觸發(DMASKTRIG)寄存器:用於屏蔽PCI裝置的插斷要求。

四.DMA控制器
S3C2410每個DMA通道有9個控制寄存器,4個通道,共有36個寄存器。每個DMA通道有6個用於控制DMA傳輸,3個用於監控DMA控制器的狀態。要進行DMA操作,首先需要對這些寄存器進行正確配置。下面介紹相關寄存器。(由於圖太多,這裡沒有貼出來,大家可以在三星的S3C2401 Data Sheet裡面找到對應的表)
1、DMA初始化資料來源(DISRC)寄存器組:分別對應著4個相關寄存器,主要用於初始化傳輸的資料來源的基地址。
2、DMA初始化資料來源控制(DISRCC)寄存器:主要用於選擇資料來源的位置(在APB還是在AHB上)以及決定地址遞增還是固定。
3、DMA初始化目標(DIDST)寄存器:主要用於初始化傳輸目標開始地址。
4、DMA初始化目標控制(DIDSTC)寄存器:主要用於選擇目標的位置(在APB還是在AHB上)以及決定地址遞增還是固定。
5、DMA控制(DCON)寄存器:主要功能選擇請求模式或者握手模式、選擇DREQ/DACK同步、使能/禁止CURR_TC中斷設定、選擇Data Size、選擇單一服務或整體服務模式、選擇DMA請求源及初始化傳輸計數器等。
6、DMA狀態(DSTAT)寄存器:主要用於讀取DMA控制器的狀態及傳輸計數器的當前值。
7、DMA當前源(DCSRC)寄存器:主要用於讀取DMA控制器當前源地址的值。
8、DMA當前目標(DCDST)寄存器:主要用於讀取DMA控制器當前目標地址的值。
9、中斷屏蔽觸發(DMASKTRIG)寄存器:用於屏蔽PCI裝置的插斷要求。

================================================================================== 詳細設計
S3C2410資料手冊裡可以找到有關DMA的寄存器的配置資訊。根據實驗目的,要想讓實現記憶體間DMA傳輸,步驟如下:
     1.首先當然是選擇DMA通道;
     2.設定DMA資料來源地址(對DISRC操作);
     3.設定DMA資料來源地址控制寄存器(對DISRCC操作);
     4.設定DMA目標地址(對DIDST操作);
     5.設定DMA資料來源地址控制寄存器(對DIDSTC操作);
     6.初始化DMA控制寄存器(對DCON操作);
     7.開啟DMA通道(DMASKTRIG操作)。
具體寄存器設定如下(假設選擇DMA0通道):
     rDISRC0=srcAddr;  //設定DMA資料來源地址
     rDISRCC0=(0<<1) | (0<<0); //地址遞增,資料來源地址在AHB上
     rDIDST0=dstAdr;
     rDIDSTC0=(0<<1) | (0<<0);
     rDCON0=tc |(1UL<<31) | (1<<30) | (1<<29) | (burst<<28) | (1<<27) | (0<<23) | (1<<22) | (dsz<<20) | (tc);
     //定義DCON寄存器HS , AHB ,TC interrupt , whole, SW request mode , relaod off
    rDMASKTRIG0=(1<<1)|1;  //DMA on(開啟DMA通道), SW_TRIG

編碼設計:
       1.DMA傳輸函數void DMA_M2M(int ch, int srcAddr, int dstAddr, int tc, int dsz, int burst)
       2.DMA測試函數void Test_DMA(void)
       3.測試主函數void Main(void)
void DMA_M2M(int ch,int srcAddr,int dstAddr,int tc,int dsz,int burst)
{
    int i,time;
    volatile U32 memSum0=0,memSum1=0;
    DMA *pDMA;
    int length=tc*(burst ? 4:1)*((dsz==0)+(dsz==1)*2+(dsz==2)*4);
   
    Uart_Printf("[DMA%d MEM2MEM Test]/n",ch);
    switch(ch)
    {
    case 0:
            pISR_DMA0 =(int)Dma0Done;//DMA0的中斷服務程式
           rINTMSK &=~(BIT_DMA0);  //允許DMA0中斷
            pDMA = (void *)0x4b000000;
            break;
    case 1:
            pISR_DMA1 = (int)Dma1Done;
            rINTMSK &= ~(BIT_DMA1);  
            pDMA = (void *)0x4b000040;break;
    case 2:
        pISR_DMA2 = (int)Dma2Done;
            rINTMSK &= ~(BIT_DMA2);  
            pDMA = (void *)0x4b000080;break;
    case 3:
                pISR_DMA3 = (int)Dma3Done;
                rINTMSK &= ~(BIT_DMA3);  
                pDMA = (void *)0x4b0000c0; break;
    }
                                                                              
                                             
    Uart_Printf("DMA%d %8xh->%8xh,size=%xh(tc=%xh),dsz=%d,burst=%d/n",ch,srcAddr,dstAddr,length,tc,dsz,burst);
    Uart_Printf("Initialize the src./n");
   
    for(i=srcAddr;i<(srcAddr+length);i+=4)
    {
    *((U32 *)i)=i^0x55aa5aa5;
    memSum0+=i^0x55aa5aa5;
    }

    Uart_Printf("DMA%d start/n",ch);
   
    dmaDone=0;
   
    rDISRC0=srcAddr;
    rDISRCC0=(0<<1)|(0<<0); // inc,AHB源來自於AHB
    rDIDST0=dstAddr;
    rDIDSTC0=(0<<1)|(0<<0); // inc,AHB目的為AHB
    rDCON0=tc|(1UL<<31)|(1<<30)|(1<<29)|(burst<<28)|(1<<27)|/
            (0<<23)|(1<<22)|(dsz<<20)|(tc);
    //HS,AHB,TC interrupt,whole, SW request mode,relaod off
    //    rINTMSK=~(BIT_DMA0);
    rDMASKTRIG0=(1<<1)|1; //DMA on, SW_TRIG

    //    Timer_Start(3);//128us resolution      
    while(dmaDone==0);
    //    time=Timer_Stop();
   
        printf("DMA%d end/n", ch);

        // Uart_Printf("DMA transfer done. time=%f, %fMB/S/n",(float)time/ONESEC3,
        // length/((float)time/ONESEC3)/1000000.);
    rINTMSK |= (BIT_DMA0 | BIT_DMA1 | BIT_DMA2 | BIT_DMA3);
   
    for(i=dstAddr;i<dstAddr+length;i+=4)
    {
            memSum1+=*((U32 *)i)=i^0x55aa5aa5;
    }
   
    Uart_Printf("memSum0=%x,memSum1=%x/n",memSum0,memSum1);
    if(memSum0==memSum1)
            Uart_Printf("DMA test result--------O.K./n");
    else
            Uart_Printf("DMA test result--------ERROR!!!/n");
}

void Test_DMA(void)
{
    //DMA Ch 0
    DMA_M2M(0,0x31020000,0x31020000+0x80000,0x80000,0,0); //byte,single
}

void Main(void)
{            
    int i;
    U8 key;
    U32 mpll_val = 0 ;

     Port_Init();  //連接埠初始化
    Isr_Init();   //中斷初始化
    Uart_Init(0,115200);  //串口初始化 傳輸速率為115200
     Uart_Select(0);  //選者串口0
     ChangeClockDivider(1,1);          // 1:2:4
     ChangeMPllValue(0xa1,0x3,0x1);    // FCLK=202.8MHz

        i=0;
        Uart_Printf("/nBegin to start UART test,OK? (Y/N)/n");
        key = Uart_Getch();
       
        if(key=='y'||key=='Y')
                Test_DMA();
        else
                Uart_Printf("/nOh! You quit the test!/n");
        Uart_Printf("/n====== UART Test End ======/n");
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.