目录
前言
一.创建一个EDMA事件句柄
二.从PRAM(参数RAM区域)中分配事件的重载/连接参数
三.给EDMA事件分配传输结束代码,一般分配的结束代码等于EDMA事件通道号
四.配置EDMA事件的参数RAM的6个寄存器值
4.1.配置过程中需要禁止EDMA传输中断
4. 2.参数RAM配置
4.3.寄存器配置接口:
五.配置EDMA相关中断以及ISR
5.1. 安装EDMA向量中断号(物理中断号)
5.2. 是否允许一次传输结束后产生中断(使能传输结束中断)
5.3. 挂接传输结束中断的中断服务程序(ISR)
5.4. 使能EDMA事件号的EDMA传输
六.示例程序
6.1.示例程序1
6.2.示例程序2
前言
本文以DM642的VP口为例,描述了基于CSL的EDMA的使用方法,包括EDMA的创建,初始化等.本文中是通过VP的FIFO的阀值设置,触发(启动)EDMA的传输.当FIFO的接收到的数据或者需要发送的数据达到自己设定的阀值,将启动一次EDMA的传输,修改相应的EMDA参数RAM的寄存器值.关于阀值的设置详细见文档“采集功能的配置步骤”。
一.创建一个EDMA事件句柄
调用接口函数EDMA_Handle EDMA_open(int chaNum, Uint32 flags);
在使用EDMA之前,都必须先调用这个函数.
示例:
如果需要打开VP0的通道A的Y,U,V的传输,对应的事件号EDMA_CHA_VP0EVTYA=16, EDMA_CHA_VP0EVTUA=17,EDMA_CHA_VP0EVTVA=18
EDMA_Handle EDMA_VPAY_handle, EDMA_VPAu_handle, EDMA_VPAV_handle;
EDMA_VPAY_handle = EDMA_open(EDMA_CHA_VP0EVTYA, EDMA_OPEN_RESET);
EDMA_VPAU_handle = EDMA_open(EDMA_CHA_VP0EVTUA, EDMA_OPEN_RESET);
EDMA_VPAV_handle = EDMA_open(EDMA_CHA_VP0EVTVA, EDMA_OPEN_RESET);
参数flags-----EDMA_OPEN_RESET,表示复位EDMA通道,禁止中断,清除中断标志.
具体示例见示例程序1
二.从PRAM(参数RAM区域)中分配事件的重载/连接参数
函数接口:EDMA_Handle EDMA_allocTable(int tableNum);
此函数是为了实现复杂的数据传输方式,在传输BT656模式中,设置两帧数据,每一帧数据分为两场:顶场和底场,第一帧的顶场传输完成连接到底场,底场数据传输完成连接到第二帧的顶场,顶场数据传输完成连接到底场数据,底场数据传输完成再连接到第一帧的顶场数据传输,用四个RLD形成一个循环,每次底场数据传输完成产生中断,通过中断函数,把这一帧的顶场和底场数据入队列,让DSP进行后续处理,
由于BT656由一个亮度分量和两个色度分量组成,因此,需要3*4个重载/连接参数
具体示例见示例程序1
三.给EDMA事件分配传输结束代码,一般分配的结束代码等于EDMA事件通道号
函数接口:int EDMA_intAlloc(int tcc);
具体示例见示例程序1
四.配置EDMA事件的参数RAM的6个寄存器值
4.1.配置过程中需要禁止EDMA传输中断
EDMA_intDisable(chan->tcc[0]);
EDMA_intDisable(chan->tcc[1]);
4. 2.参数RAM配置
函数接口:void EDMA_config(EDMA_Handle hEdma, EDMA_Config *config);
typedef struct {
Uint32 opt; //通道选择
Uint32 src; //源地址
Uint32 cnt; //阵列(二维)/帧(一维)计数
Uint32 dst; //目的地址
Uint32 idx; //阵列/帧索引
Uint32 rld; //重载地址参数
} EDMA_Config;
EDMA_config(chan->hEdma[i], &cfgEdma);//配置EDMA通道事件RAM
EDMA_config(chan->hRld[4 * i], &cfgEdma); //配置对应通道事件的传输事件RAM组
4.3.寄存器配置接口:
EDMA_OPT_RMK(pri,esize,ds2,sum,dd2,dum,tcint,tcc,tccm,atcint,atcc,pdts,pdtd,link,fs);
EDMA_SRC_RMK(src)
EDMA_CNT_RMK(frmcnt,elecnt);
EDMA_DST_RMK(dst);
EDMA_IDX_RMK(frmidx,eleidx);
EDMA_RLD_RMK(elerld,link);
术语陈述:
对于传704*576大小的Y数据
EDMA_CNT_RMK(frmcnt,elecnt);
如果配置了EDMA传输的数据宽度为32位.一帧为704个数据,那么frmcnt=576,elecnt=704/4(字节)
这里的帧表示对数据的打包形式或者是说一种数据组织结构的总称,上面的例子表示704个数据为一帧.
EDMA_IDX_RMK(frmidx,eleidx);采用帧索引的话,eleidx=0,frmidx=704(一帧的数据个数).
具体示例见程序示例2
五.配置EDMA相关中断以及ISR
5.1. 安装EDMA向量中断号(物理中断号)
EDMA的中断号为8,为固定的
函数接口:Void IRQ_map(Uint32 eventId,, int intNumber);
IRQ_map(IRQ_EVT_EDMAINT, irqId);
具体示例见程序示例2
5.2. 是否允许一次传输结束后产生中断(使能传输结束中断)
函数接口: void EDMA_intEnable(Uint32 tccIntNum);
void EDMA_intDisable(Uint32 tccIntNum);
void EDMA_intClear(Uint32 tccIntNum)
EDMA_intClear(chan->tcc[0]);
EDMA_intEnable(chan->tcc[0]);
EDMA_intClear(chan->tcc[1]);
EDMA_intEnable(chan->tcc[1]);
具体示例见程序示例2
5.3. 挂接传输结束中断的中断服务程序(ISR)
函数接口: EDMA_IntHandler EDMA_intHook(int tccNum, EDMA_IntHandler funcAddr);
EDMA_intHook(chan->tcc[0], captureEdmaISR);
EDMA_intHook(chan->tcc[1], captureEdmaISR);
具体示例见程序示例2
5.4. 使能EDMA事件号的EDMA传输
函数接口: void EDMA_enableChannel(EDMA_Handle hEdma);
for(i = 0; i < numEdmaChans; i ++)
{
EDMA_disableChannel(chan->hEdma[i]);
EDMA_clearChannel(chan->hEdma[i]);
EDMA_enableChannel(chan->hEdma[i]);
}
IRQ_enable(IRQ_EVT_EDMAINT);
具体示例见程序示例2
六.示例程序
6.1.示例程序1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for(j = 0; j <( _VPORT_NUM_EDMA_CHANS)&& retVal == IOM_COMPLETED; j ++)
{
if( (chan->hEdma[j] = EDMA_open(chan->edmaChanNum[j], EDMA_OPEN_RESET))==EDMA_HINV //分配一个事件的重载或连接参数RAM表(6个字)
|| (chan->hRld[4 * j] = EDMA_allocTable(-1))==EDMA_HINV
|| (chan->hRld[4 * j + 1] = EDMA_allocTable(-1))==EDMA_HINV
|| (chan->hRld[4 * j + 2] = EDMA_allocTable(-1))==EDMA_HINV
|| (chan->hRld[4 * j + 3] = EDMA_allocTable(-1))==EDMA_HINV
/*分配传输结束代码==EDMA事件号*/
|| (chan->tcc[j] = EDMA_intAlloc(chan->edmaChanNum[j])) == -1)
{
retVal = IOM_EALLOC;
msg_print("entrymdCreateChan ---retVal=%d----------jinx",retVal);
}/* if((port->...*/
msg_print("entry mdCreateChan ---retVal=%d--------------------jinx",retVal);
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6.2.示例程序2
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EDMA_Config cfgEdma;
for(i = 0; i < numEdmaChans; i ++)
{
Int optFld1 = EDMA_OPT_RMK(//YEVT通道事件参数RAM
edmaPri, // 1,EDMA传输具有最高优先级
EDMA_OPT_ESIZE_32BIT,
EDMA_OPT_2DS_NO, //0,表示一维源
EDMA_OPT_SUM_NONE, //0,表示固定源地址
EDMA_OPT_2DD_YES, // 1,表示二维目的
EDMA_OPT_DUM_INC, // 1,目的地址根据2DS和FS位增加
EDMA_OPT_TCINT_NO, // 0,禁止传输结束中断
EDMA_OPT_TCC_OF(0), // 0,传输结束代码为0
EDMA_OPT_TCCM_OF(0),//0,传输事件结束代码最大设置
EDMA_OPT_ATCINT_NO, // 0,禁止将要结束事件中断
EDMA_OPT_ATCC_DEFAULT,
EDMA_OPT_PDTS_DISABLE,//源地址为片内外设传输方式0,禁止片内外设读
EDMA_OPT_PDTD_DISABLE,//目的地址为片内外设传输方式0,禁止片内外设写
EDMA_OPT_LINK_YES, // 1,事件参数连接使能
EDMA_OPT_FS_NO //0,数据或者阵列同步
);
Int optFld2a = EDMA_OPT_RMK(
edmaPri,
EDMA_OPT_ESIZE_32BIT,
EDMA_OPT_2DS_NO,
EDMA_OPT_SUM_NONE,
EDMA_OPT_2DD_YES,
EDMA_OPT_DUM_INC, // 1,目的地址根据2DS和FS位增加
(i == 0 ? EDMA_OPT_TCINT_YES:EDMA_OPT_TCINT_NO),
EDMA_OPT_TCC_OF(i == 0 ? chan->tcc[0] & 0x0f : 0),
EDMA_OPT_TCCM_OF(i == 0 ? chan->tcc[0] >> 4 : 0),
EDMA_OPT_ATCINT_NO,
EDMA_OPT_ATCC_DEFAULT,
EDMA_OPT_PDTS_DISABLE,
EDMA_OPT_PDTD_DISABLE,
EDMA_OPT_LINK_YES,
EDMA_OPT_FS_NO
);
Int optFld2b = EDMA_OPT_RMK(
edmaPri,
EDMA_OPT_ESIZE_32BIT,
EDMA_OPT_2DS_NO,
EDMA_OPT_SUM_NONE,
EDMA_OPT_2DD_YES,
EDMA_OPT_DUM_INC, // 1,目的地址根据2DS和FS位增加
(i == 0 ? EDMA_OPT_TCINT_YES:EDMA_OPT_TCINT_NO),
EDMA_OPT_TCC_OF(i == 0 ? chan->tcc[1] & 0x0f : 0),
EDMA_OPT_TCCM_OF(i == 0 ? chan->tcc[1] >> 4 : 0),
EDMA_OPT_ATCINT_NO,
EDMA_OPT_ATCC_DEFAULT,
EDMA_OPT_PDTS_DISABLE,
EDMA_OPT_PDTD_DISABLE,
EDMA_OPT_LINK_YES,
EDMA_OPT_FS_NO
);
thrld = (i == 0) ? chan->yThrld : chan->cThrld;
cfgEdma.src = EDMA_SRC_RMK(chan->edmaAddr[i]);
if(chan->interlaced) //隔行扫描模式 noted by jinx 2008.06.23
{
if(!(params->cmode & _VPORT_MASK_RAW))//BT.656
{
/* to merge the two fields together */
/* EDMA is configured to transfer only field 1 initially */
/* line pitch is twice the line size */
/* this requires that the threlhold is the same as line size */
/* first field */
//#define EDMA_CNT_RMK(frmcnt,elecnt)
//阵列数为288-1;数据计数=704/4,
//因为设置为32位数据宽度,而thrld表示2字的个数,
//因此转换为数据计数的时候需要把thrld*2,即(thrld << 1)
//noted by jinx 2008.06.12
cfgEdma.cnt =
EDMA_CNT_RMK((chan->numEventsFld1) - 1, (thrld << 1));
if(chan->mergeFlds) {
//#define EDMA_IDX_RMK(frmidx,eleidx)
//thrld << 4表示隔行存放数据,留出存放场2或者场1的一行数据存储空间,
//thrld << 3表示连续存储,即存放完此场的一行数据后,接着还是存放此场的下一行数据
cfgEdma.idx = EDMA_IDX_RMK(thrld << 4, 0);
} else {
cfgEdma.idx = EDMA_IDX_RMK(thrld << 3, 0);
}
/* hard code the first two frames as current and reload buffers */
/* first field */
cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i + 1]);
cfgEdma.opt = optFld1;
cfgEdma.dst =
EDMA_DST_RMK(*((Int *)(&chan->viops[0].frame.iFrm.y1) + i));
EDMA_config(chan->hEdma[i], &cfgEdma);//配置EDMA通道事件RAM
EDMA_config(chan->hRld[4 * i], &cfgEdma); //配置对应通道事件的传输事件RAM组
cfgEdma.dst =
EDMA_DST_RMK(*((Int *)(&chan->viops[1].frame.iFrm.y1) + i));
cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i + 3]);
EDMA_config(chan->hRld[4 * i + 2], &cfgEdma);
/* second field */
cfgEdma.opt = optFld2a;
cfgEdma.cnt =
EDMA_CNT_RMK((chan->numEvents-chan->numEventsFld1) - 1,
(thrld << 1));
cfgEdma.dst =
EDMA_DST_RMK(*((Int *)(&chan->viops[0].frame.iFrm.y2) + i));
cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i + 2]);
EDMA_config(chan->hRld[4 * i + 1], &cfgEdma);
cfgEdma.opt = optFld2b;
cfgEdma.dst =
EDMA_DST_RMK(*((Int *)(&chan->viops[1].frame.iFrm.y2) + i));
cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i]);
EDMA_config(chan->hRld[4 * i + 3], &cfgEdma);
}
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~