6000裏面EDMA 的使用心得!!!

這是以前在網上看到的,也記不清哪網站了,感覺說的很到位,貼出來共享一下..總感覺TI的文檔語焉不詳。不過想想也對,250頁的文檔是誰都要寫到鬱悶的。而且一個懂了的人給初學者講東西總會自然的略過一些看似當然的關鍵。
      這幾天遇到的問題就是EDMA可以工作,卻不能連續不斷的轉起來。而問題的所在就在於文檔沒讀清楚。
      文檔(SPRU234,下同)在第一章的第一節的圖1-2就給出了EDMA的控制塊圖。現在看到控制塊圖當然聯想到實際的工作流程,但是似乎文檔並沒有解釋EDMA的工作流程。
      在EDMA工作中,總共使用了兩個參數表,其中的一個是由EDMA控制器維護的,而另一個是由用戶維護的。EDMA控制器維護的參數表規則的排列在整個參數表的開始部分,一個通道一個,誰也不多誰也不少。而用戶維護的參數表則被稱作Reload channel parameters,隨意分佈在整個參數表的後半部分。現在看來,能知道EDMA控制器是用了兩個參數表就可以很好的理解EDMA的工作方式。
      非連續的工作:
      EDMA可以工作在連續的和非連續的狀態。數據非連續的時候可以採用單次的非連續工作狀態。這時用戶在初始化的時候直接初始化EDMA所維護的參數表就可以了。如下面的例子:
*edmaHandle = EDMA_open(eventId, EDMA_OPEN_RESET);
if(*edmaHandle == EDMA_HINV)
    test_exit(FAIL);
/* allocate TCC for Y event */
if((tcc = EDMA_intAlloc(-1)) == -1)
    test_exit(FAIL) ;
/* Configure EDMA parameters */
EDMA_configArgs(
    *edmaHandle,
    EDMA_OPT_RMK(
    EDMA_OPT_PRI_MEDIUM, /* medium priority */
    EDMA_OPT_ESIZE_32BIT, /* Element size 32 bits */
    EDMA_OPT_2DS_NO, /* 1-dimensional source(FIFO) */
    EDMA_OPT_SUM_NONE, /* fixed src address mode(FIFO) */
    EDMA_OPT_2DD_YES, /* 2-dimensional destination */
    EDMA_OPT_DUM_INC, /* destination increment */
    EDMA_OPT_TCINT_YES, /* Enable transfer complete */
    /* indication */
    EDMA_OPT_TCC_OF(tcc & 0xF),
    EDMA_OPT_TCCM_OF(((tcc & 0x30) >> 4)),
    EDMA_OPT_ATCINT_NO, /* Disable Alternate Transfer */
    /* Complete Interrupt */
    EDMA_OPT_ATCC_OF(0),
    EDMA_OPT_PDTS_DISABLE, /* disable PDT(peripheral device */
    /* transfer) mode for source */
    EDMA_OPT_PDTD_DISABLE, /* disable PDT mode for dest */
EDMA_OPT_LINK_NO, /* Enable linking */
    EDMA_OPT_FS_NO/* NO=Array YES=Block synchronization */
    ),
    EDMA_SRC_RMK(srcAddr),
    EDMA_CNT_RMK(EDMA_CNT_FRMCNT_OF((frameCount - 1)),
    EDMA_CNT_ELECNT_OF(elementCount)),
    EDMA_DST_RMK(dstAddr),
    EDMA_IDX_RMK(EDMA_IDX_FRMIDX_OF((elementCount * 4)),
    EDMA_IDX_ELEIDX_OF(0)), /* note: 32-bit element size */
    /* no RLD in 2D and no linking */
    EDMA_RLD_RMK(EDMA_RLD_ELERLD_OF(elementCount), EDMA_RLD_LINK_OF(0))
);
      在這裏,LINK參數是被忽略的,這一點可以從TI給的例子中看到(52頁開始)。相對於很多DMA控制器來說,這些參數顯得很簡單而TI的講述非常詳細。
      連續工作方式:
      非連續的工作方式很好理解,TI也講得很詳細,而TI在講述連續工作方式的時候卻一筆帶過。和非連續的方式不同之處在於用戶需要初始化兩張表,而只能維護其中的一張,另一張是由EDMA控制器自動維護的。其中的EDMA維護的這張表是在EDMA工作期間使用的,而用戶維護的這張表是在EDMA開始新工作的時候重載的。
      用戶在初始化階段必須先初始化EDMA通道對應的參數表,之後在參數表的後半部分申請一張空閒的參數表,並將其初始化。如文檔中1.16.4.3所示的例子,其中62頁示例的就是通道對應的參數表,而63頁示例的就是需要重載的參數表。
      EDMA在接受了這樣的參數表之後,首先判斷是否達成DMA完成條件(參考TI文檔),如果未完成,開始將參數表中的ELECNT自減,減到零則FRMCNT減一,而後從ELERLD參數中重載ELECNT,在開始新的一個Frame。周而復始。當FRMCNT也減完了則從重載表重新裝入參數開始新一輪的工作。用戶則可以根據工作需要在EDMA控制器重載參數之前對重載參數設置以開始不同的工作。
      下面的例子是TI在例子中給出的一個三張表的例子,根據這些例子,用戶甚至可以使用4張表或者更多,最多可以單一通道使用22張表(C64X)。而多通道則可以使用N+21張表。
/*首先申請通道對應的參數表*/
    hEdma = EDMA_open(EDMA_CHA_TINT1, EDMA_OPEN_RESET);
/*然後申請兩個參數表,用於PING-PONG模式*/
    hEdmaPing = EDMA_allocTable(-1);
    hEdmaPong = EDMA_allocTable(-1);
/*令Edma所維護的參數表的參數與Ping的相同*/
    cfgEdma = cfgEdmaPing;
  
/*初始化重載列表,注意EDMA所維護的列表指向了Pong,而Ping、Pong的表分別指向了自身,這樣Edma首先以Ping模式工作(因爲其參數與Ping相同),而後以Pong模式工作*/
    cfgEdmaPing.rld = EDMA_RLD_RMK(0,hEdmaPing);
    cfgEdmaPong.rld = EDMA_RLD_RMK(0,hEdmaPong);
    cfgEdma.rld       = EDMA_RLD_RMK(0,hEdmaPong); 
    /*配置參數*/
    EDMA_config(hEdma, &cfgEdma);   
    EDMA_config(hEdmaPing, &cfgEdmaPing);
    EDMA_config(hEdmaPong, &cfgEdmaPong);   
下面是Ping和Pong的參數:
EDMA_Config cfgEdmaPing = {  
    EDMA_OPT_RMK(
      EDMA_OPT_PRI_LOW,
      EDMA_OPT_ESIZE_32BIT,
      EDMA_OPT_2DS_NO,
      EDMA_OPT_SUM_NONE,
      EDMA_OPT_2DD_NO,
      EDMA_OPT_DUM_INC,
      EDMA_OPT_TCINT_YES,
      EDMA_OPT_TCC_OF(TCCINTNUM),
      EDMA_OPT_TCCM_OF(0),
      EDMA_OPT_ATCINT_NO,
      EDMA_OPT_ATCC_OF(0),
      EDMA_OPT_PDTS_DEFAULT,
      EDMA_OPT_PDTD_DEFAULT,
      EDMA_OPT_LINK_YES,
      EDMA_OPT_FS_NO
    ),
    EDMA_SRC_OF(&ping_data),
    EDMA_CNT_OF(BUFF_SZ),
    EDMA_DST_OF(ping),
    EDMA_IDX_OF(0x00000004),
    EDMA_RLD_OF(0x00000000)
};                         
/* Create the EDMA configuration structure for pong transfers */
EDMA_Config cfgEdmaPong = {
    EDMA_OPT_RMK(
      EDMA_OPT_PRI_LOW,
      EDMA_OPT_ESIZE_32BIT,
      EDMA_OPT_2DS_NO,
      EDMA_OPT_SUM_NONE,
      EDMA_OPT_2DD_NO,
      EDMA_OPT_DUM_INC,
      EDMA_OPT_TCINT_YES,
      EDMA_OPT_TCC_OF(TCCINTNUM),
EDMA_OPT_TCCM_OF(0),
      EDMA_OPT_ATCINT_NO,
      EDMA_OPT_ATCC_OF(0),
      EDMA_OPT_PDTS_DEFAULT,
      EDMA_OPT_PDTD_DEFAULT,
      EDMA_OPT_LINK_YES,
      EDMA_OPT_FS_NO
    ),
    EDMA_SRC_OF(&pong_data),
    EDMA_CNT_OF(BUFF_SZ),
    EDMA_DST_OF(pong),
    EDMA_IDX_OF(0x00000004),
    EDMA_RLD_OF(0x00000000)
};
      這樣的方式很像是運動場的徑賽場地,運動員從抽頭跑入,然後一圈一圈的不斷跑下去。使用這種方式似乎可以很好的避免內存訪問衝突,我在調試過程中試圖修改EDMA自動維護的表項時導致了很糟糕的內存訪問錯誤。
      就這樣吧,可能不是很清晰,不斷修改中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章