[资料分享] 关于TI DSP的EDMA的调试

Jacktang   2017-3-27 08:43 楼主
在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自动维护的表项时导致了很糟糕的内存访问错误

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复