一、EDMA模块介绍
TMS320C6748是一款高性能DSP,非常适合用来跑大数据量的算法,而这样的算法往往需要保证实时性,那么这么大规模的数据怎么进行运算能够让程序跑的最快,我们知道DSP中运算最快的存储单元是RAM区,但是RAM毕竟有限的,无法存储大量数据,因而我们只能把数据存在DDR中,这时我们需要一种工具能够将数据从DDR中导入RAM中运算,算完的结果再发回DDR中存储。大家学习《微机原理》的时候应该听说过DMA吧,简单来说就是CPU把数据传送的源、目的、数据个数等信息交给DMA,让DMA控制数据传输,在此期间,CPU可以运行其他程序,等到DMA控制的数据传输完成,发送中断告诉CPU我的数据传输完成了,你来处理吧,因而提高了算法的速度,Ti公司为TMS320C6748量身设计了增强版直接存储器访问控制器EDMA3。
EDMA3一共有32个通道,通道的优先级可选,可以实现数据传输的无缝链接,为什么是无缝的,后面我们会具体说到。利用EDMA,可以实现片内存储器、片内外设以及外部存储器之间的数据传输。
1、EDMA概述
前面已经介绍过了DMA的原理,下面我们来说EDMA能够完成哪些功能。
(1)一维二维数据传输,包括数据转置,不知道你在写程序时有没有遇到需要转置的数据矩阵,这里的转置其实也是提高算法运算速度的一种手段吧,在DSP配套的MATHLIB文件中提供了一种基于向量寻址的快速算法,我们知道无论什么处理器运算的第一步一定是待计算数据的寻址,然后才是运算,数据寻址其实需要占用非常多的时间,而向量寻址的快速算法可以对一个连续的向量进行高速运算,因为每计算完一次,地址自动加1就行,节省了运算时间。
(2)事件、链式事件触发,也就是说可以利用一个中断,或者事件触发EDMA传输,例如当SPI、UPP传输完数据后给EDMA控制器一个信号,告诉EDMA我的数据准备好了,存入DDR吧。
(3)地址重载,EDMA应用的是PaRAM保存每组要传输数据的信息,源、目的地址,数据个数等信息,其中有一个参量是链接到其他PaRAM的地址,额,有点复杂,下面具体说吧。
(4)乒乓存储,非常实用高效的一种数据流控制方法,简单来说就是将RAM分为两个部分,第一个周期第一段数据由EDMA传入RAM1,第二个周期对RAM1中数据进行处理,同时,第二段数据由EDMA传入RAM2,第三个周期对RAM2中数据进行处理,同时第三段数据由EDMA传入RAM1 ,如此循环,可以对数据进行高效处理。
EDMA通道控制器主要由以下5个部分组成:事件相关寄存器、事件选择器、参数RAM、QDMA检测器、结束和错误检测器。事件寄存器完成对EDMA事件的捕获,一个事件相当于一个同步信号,由它触发某个EDMA通道开始传输数据。如果有多个事件同时发生,由事件选择器对他们进行识别。在EDMA的参数RAM中存放与事件相关的传输参数,这些参数送入传输请求,进而产生对外设读写操作所需要的地址。EDMA的通道控制器和传输器的结构如上图所示。
2、EDMA传输相关
(1)传输数据类型
EDMA3 的传输类型EDMA3 的传输是在3 个维度上定义的:
void main(void)
{
setup_EDMA();//初始化EDMA3寄存器
for(jj=0;jj<2;jj++)
{
for(kk=0;kk<256;kk++)
{
SRC_AA[jj][kk]=kk*(jj+1);
}
}
for(jj=0;jj<2;jj++)
{
for(kk=0;kk<256;kk++)
{
SRC_BB[jj][kk]=kk;
}
}
for(jj=0;jj<256;jj++)
{
SRC_CC[jj]=2jj;
}
for(jj=0;jj<256;jj++)
{
SRC_DD[jj]=3jj;
}
EDMA_event11_Buffer_transfer(1,0,2,2,256);//flag(单行转秩1/矩阵转秩other);转换第x行;数据类型;行数;列数
EDMA_event10_Buffer_transfer(1,1,2,2,256);//flag(单行转秩1/矩阵转秩other);转换第x行;数据类型;行数;列数
CSL_FINST(edma3ccRegs->ESR, EDMA3CC_ESR_E11, SET);
delay(10000);
CSL_FINST(edma3ccRegs->ESR, EDMA3CC_ESR_E11, SET);
delay(10000);
}
/--------------------------------数组转秩-----------------------------------/
// function:完成通道10单行/矩阵转秩存储,需要在函数中修改源、目的地址,当转秩矩阵时,参数为转换第0行
// parameters:flag(单行转秩1/矩阵转秩other);转换第x行;数据类型;行数;列数
int EDMA_event10_Buffer_transfer(Uint16 flag,Uint16 trans_number,Uint16 type_data,Uint16 row,Uint16 column)//参数RAM配置
{
int time_EDMA=0;
edma3ccRegs->PARAMSET[EDMA_EVENT10].OPT = CSL_EDMA3CC_OPT_RESETVAL;//参数RAM复位
// ConfigPaRAM OPT (Enable TC Interrupt & ITC Chaining; Set TCC)//允许产生中断,对应事件10
edma3ccRegs->PARAMSET[EDMA_EVENT10].OPT =
CSL_FMKT(EDMA3CC_OPT_ITCCHEN,ENABLE) |
CSL_FMKT(EDMA3CC_OPT_TCINTEN,ENABLE) |
CSL_FMK(EDMA3CC_OPT_TCC,EDMA_EVENT10)|
CSL_FMKT(EDMA3CC_OPT_TCCMOD,NORMAL) |
CSL_FMKT(EDMA3CC_OPT_FWID,8BIT) |//仅仅针对常数位有效
CSL_FMKT(EDMA3CC_OPT_STATIC,NORMAL) |
CSL_FMKT(EDMA3CC_OPT_SYNCDIM,ASYNC) |
CSL_FMKT(EDMA3CC_OPT_DAM,INCR) |
CSL_FMKT(EDMA3CC_OPT_SAM,INCR);
// Initialize EDMAEvent Src and Dst Addresses
edma3ccRegs->PARAMSET[EDMA_EVENT10].SRC = (Uint32)&(SRC_AA);//设置源数组地址
edma3ccRegs->PARAMSET[EDMA_EVENT10].DST = (Uint32)&(DST_BB[0][trans_number]);//设置目的数组地址
// Set EDMA EventPaRAM A,B,C CNT
edma3ccRegs->PARAMSET[EDMA_EVENT10].A_B_CNT =
CSL_FMK(EDMA3CC_A_B_CNT_ACNT,type_data) |//设定传输数据类型
CSL_FMK(EDMA3CC_A_B_CNT_BCNT,column);//设置传输数目
if(flag1)
{
edma3ccRegs->PARAMSET[EDMA_EVENT10].CCNT = 1;
}
else
{
edma3ccRegs->PARAMSET[EDMA_EVENT10].CCNT = row;
}
edma3ccRegs->PARAMSET[EDMA_EVENT10].SRC_DST_BIDX =
CSL_FMK(EDMA3CC_SRC_DST_BIDX_SRCBIDX,type_data) |
CSL_FMK(EDMA3CC_SRC_DST_BIDX_DSTBIDX,rowtype_data);//二维索引
edma3ccRegs->PARAMSET[EDMA_EVENT10].SRC_DST_CIDX =
CSL_FMK(EDMA3CC_SRC_DST_CIDX_SRCCIDX,type_data) |
CSL_FMK(EDMA3CC_SRC_DST_CIDX_DSTCIDX,(1-column)type_datarow+type_data);//三维索引
// Set EDMA EventPaRAM LINK and BCNTRLD
edma3ccRegs->PARAMSET[EDMA_EVENT10].LINK_BCNTRLD =
CSL_FMK(EDMA3CC_LINK_BCNTRLD_LINK,0xFFFF) |
CSL_FMK(EDMA3CC_LINK_BCNTRLD_BCNTRLD,column);
time_EDMA=1;
return time_EDMA;
}
/--------------------------------数组转秩PaRAM参数-----------------------------------*/
// function:完成通道11单行/矩阵转秩存储,需要在函数中修改源、目的地址,当转秩矩阵时,参数为转换第0行
// parameters:flag(单行转秩1/矩阵转秩other);转换第x行;数据类型;行数;列数
int EDMA_event11_Buffer_transfer(Uint16 flag,Uint16 trans_number,Uint16 type_data,Uint16 row,Uint16 column)//参数RAM配置
{
int time_EDMA=0;
edma3ccRegs->PARAMSET[EDMA_EVENT11].OPT = CSL_EDMA3CC_OPT_RESETVAL;//参数RAM复位
// ConfigPaRAM OPT (Enable TC Interrupt & ITC Chaining; Set TCC)//允许产生中断,对应事件10
edma3ccRegs->PARAMSET[EDMA_EVENT11].OPT =
CSL_FMKT(EDMA3CC_OPT_ITCCHEN,ENABLE) |
CSL_FMKT(EDMA3CC_OPT_TCINTEN,ENABLE) |
CSL_FMK(EDMA3CC_OPT_TCC,EDMA_EVENT11)|
CSL_FMKT(EDMA3CC_OPT_TCCMOD,NORMAL) |
CSL_FMKT(EDMA3CC_OPT_FWID,8BIT) |//仅仅针对常数位有效
CSL_FMKT(EDMA3CC_OPT_STATIC,NORMAL) |
CSL_FMKT(EDMA3CC_OPT_SYNCDIM,ASYNC) |
CSL_FMKT(EDMA3CC_OPT_DAM,INCR) |
CSL_FMKT(EDMA3CC_OPT_SAM,INCR);
// Initialize EDMAEvent Src and Dst Addresses
edma3ccRegs->PARAMSET[EDMA_EVENT11].SRC = (Uint32)&(SRC_CC);//设置源数组地址
edma3ccRegs->PARAMSET[EDMA_EVENT11].DST = (Uint32)&(DST_BB[0][trans_number]);//设置目的数组地址
// Set EDMA EventPaRAM A,B,C CNT
edma3ccRegs->PARAMSET[EDMA_EVENT11].A_B_CNT =
CSL_FMK(EDMA3CC_A_B_CNT_ACNT,type_data) |//设定传输数据类型
CSL_FMK(EDMA3CC_A_B_CNT_BCNT,column);//设置传输数目
if(flag1)
{
edma3ccRegs->PARAMSET[EDMA_EVENT11].CCNT = 1;
}
else
{
edma3ccRegs->PARAMSET[EDMA_EVENT11].CCNT = row;
}
edma3ccRegs->PARAMSET[EDMA_EVENT11].SRC_DST_BIDX =
CSL_FMK(EDMA3CC_SRC_DST_BIDX_SRCBIDX,type_data) |
CSL_FMK(EDMA3CC_SRC_DST_BIDX_DSTBIDX,row*type_data);//二维索引
edma3ccRegs->PARAMSET[EDMA_EVENT11].SRC_DST_CIDX =
CSL_FMK(EDMA3CC_SRC_DST_CIDX_SRCCIDX,type_data) |
CSL_FMK(EDMA3CC_SRC_DST_CIDX_DSTCIDX,(1-column)type_datarow+type_data);//三维索引
// Set EDMA EventPaRAM LINK and BCNTRLD
edma3ccRegs->PARAMSET[EDMA_EVENT11].LINK_BCNTRLD =
CSL_FMK(EDMA3CC_LINK_BCNTRLD_LINK,0x4140) |
CSL_FMK(EDMA3CC_LINK_BCNTRLD_BCNTRLD,column);
time_EDMA=1;
return time_EDMA;
}
这里PaRAM.LINK是这么计算的:
每个PaRAM占用32个字,那么PaRAM10就是10*32=320=140h,那么链接地址就是0x4140。