博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于TI DSP的EDMA
阅读量:2178 次
发布时间:2019-05-01

本文共 4169 字,大约阅读时间需要 13 分钟。

几天调下来,总感觉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页开始)。相对于很多控制器来说,这些参数显得很简单而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自动维护的表项时导致了很糟糕的内存访问错误。
     就这样吧,可能不是很清晰,不断修改中。

转载地址:http://unckb.baihongyu.com/

你可能感兴趣的文章
Spring源码剖析3:Spring IOC容器的加载过程
查看>>
Spring源码剖析4:懒加载的单例Bean获取过程分析
查看>>
Spring源码剖析5:JDK和cglib动态代理原理详解
查看>>
Spring源码剖析6:Spring AOP概述
查看>>
Spring源码剖析7:AOP实现原理详解
查看>>
Spring源码剖析8:Spring事务概述
查看>>
Spring源码剖析9:Spring事务源码剖析
查看>>
重新学习Mysql数据库1:无废话MySQL入门
查看>>
探索Redis设计与实现2:Redis内部数据结构详解——dict
查看>>
探索Redis设计与实现3:Redis内部数据结构详解——sds
查看>>
探索Redis设计与实现4:Redis内部数据结构详解——ziplist
查看>>
探索Redis设计与实现6:Redis内部数据结构详解——skiplist
查看>>
探索Redis设计与实现5:Redis内部数据结构详解——quicklist
查看>>
探索Redis设计与实现8:连接底层与表面的数据结构robj
查看>>
探索Redis设计与实现7:Redis内部数据结构详解——intset
查看>>
探索Redis设计与实现9:数据库redisDb与键过期删除策略
查看>>
探索Redis设计与实现10:Redis的事件驱动模型与命令执行过程
查看>>
分布式系统理论基础1: 一致性、2PC和3PC
查看>>
分布式系统理论基础2 :CAP
查看>>
分布式系统理论基础3: 时间、时钟和事件顺序
查看>>