DMA

来源:互联网 发布:linux route指令 编辑:程序博客网 时间:2024/06/03 03:50

摘自:
http://blog.sina.com.cn/s/blog_a7c071b30102wxaz.html
http://blog.csdn.net/ocean_ele/article/details/51417908


一.内存与外设进行数据交换的方式

a.中断方式:每传输一次数据,就必须经历中断处理的全部步骤,而且一般需要借助CPU内部的寄存器作为中介,也就是说CPU需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方,在这个时间中,CPU对于其他的工作来说就无法使用。

b.DMA模式:不用CPU的寄存器作为传输中介,完成存储器和外设间、存储器和存储器间的直接传输,需要注意的是,在DMA工作的时候,CPU必须将系统总线的控制权让给DMAC。

二.DMA操作流程

a. 外设可通过DMA控制区想CPU发出DMA请求.b. CPU响应DMA请求,系统转变为DMA方式,并把总线控制权交给DMA控制器.c. 由DMA控制器发送存储器地址,并决定数据块的长度.d. 执行DMA传送.e. DMA操作结束,并把总线控制权交给CPU.

附:微机知识
这里写图片描述

三.28335 DMA配置函数

DMACHx(DMA Channel):x=1~6

void DMACHxAddrConfig(volatile Unit16 *DMA_Dest,volatile Unit16 *DMA_Source)

//配置DMA的数据目的地地址和源地址(跟函数中参数的排序相同,下同)

解释: 源地址有两个,一个A为用于传输时(随每个字节递增),另一个B作为返回的备份(当一帧结束后,重新装载入A)
目的地址有两个,一个A为用于传输时(随每个字节递增),另一个B作为返回的备份(当一帧结束后,重新装载入A)
每次启动DMA相应通道,都会把B装载入A

void DMACHxBurstConfig(Unit16 bsize,int16 srcbstep,int16 desbstep)   

//帧循环、内循环:配置每帧多少字(word)、帧内源地址增加偏移和帧内目的地地址增加偏移。地址增加偏移就是指传输一个字的地址增量

void DMACHxTransferConfig(Unit16 tsize,int16 srctstep,int16 deststep)  

//传送循环、外循环:配置每次触发DMA转移多少帧,帧间源地址增加偏移和帧间目的地地址增加偏移。地址增加偏移就是指传输一个帧的地址增量

void DMACHxWrapConfig(Unit16 srcwsize,int16 srcwstep,Unit16 deswsize,int16 deswstep) 

//“打包”过程配置:配置源地址“打包”过程每个“打包”所含帧的个数、源地址每个“打包”完成之后的地址偏移增量、配置目的地址“打包”过程每个“打包”所含帧的个数、目的地址每个“打包”完成之后的地址偏移增量。

解释: Srcwsize:当已经传递的脉冲数为srcwsize+1的整数倍时,源地址(B)增加srcwstep(常为0),并装载入源地址A
Deswsize:当已经传递的脉冲数为deswsize+1的整数倍时,目的地址(B)增加deswstep(常为0),并装载入目的地址A

void DMACHxModeConfig(Unit16 persel,Unit16 perinte,Unit16 oneshot,Unit16 cont,Unit16 synce,Unit16 syncsel,Unit16 ovrinte,Unit16 datasize,Unit16 chintmode,Unit16 chinte)  

//DMA模式寄存器:配置外设触发事件源选择、外设触发事件使能、ONESHOT使能、连续模式使能、外设同步使能、同步模式选择(源同步或目的地同步)、超载中断使能、数据传送模式选择(16位或32位)、通道中断模式选择(开始或结束)、通道中断使能

添注:
这里写图片描述

persel--选择触发源,值为下列选项DMA_SEQ1INT--------ADCDMA_SEQ2INT--------ADC DMA_XINT1  --------外部中断DMA_XINT2  --------外部中断 DMA_XINT3  --------外部中断 DMA_XINT4  --------外部中断 DMA_XINT5  --------外部中断 DMA_XINT6  --------外部中断 DMA_XINT7  --------外部中断 DMA_XINT13 --------外部中断 DMA_TINT0  --------CPU时钟 DMA_TINT1  --------CPU时钟 DMA_TINT2  --------CPU时钟 DMA_MXEVTA  --------McBSP-ADMA_MREVTA  --------McBSP-ADMA_MXREVTB --------McBSP-BDMA_MREVTB  --------McBSP-Bperinte--使能触发源,值为PERINT_DISABLE或PERINT_ENABLEoneshot--使能oneshot模式,值为ONESHOT_DISABLE或ONESHOT_ENABLE。此模式下,一次触发完成全部burst。cont--使能Continuous模式,值为CONT_DISABLE或CONT_ENABLE。此模式下,传送完毕后DMA重新被初始化,并等待触发源。synce--使能外围设备同步,值为SYNC_DISABLE或SYNC_ENABLE。syncsel--同步选择。值为SYNC_SRC或SYNC_DST。ovrinte--使能溢出中断。值为OVRFLOW_DISABLE或OVEFLOW_ENABLE。datasize--每次传送位数。值为SIXTEEN_BIT或THIRTYTWO_BIT。chintmode--通道中断产生模式。CHINT_BEGIN:传送开始发中断。CHINT_END:传送结束发中断。chinte--使能通道中断。值为CHINT_DISABLE或CHINT_ENABLE。

MODE寄存器
这里写图片描述
这里写图片描述

CONTROL寄存器
这里写图片描述
这里写图片描述

/*----------------代码原型--------------------*/void DMACH1ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte){    EALLOW;    // Set up MODE Register:    DmaRegs.CH1.MODE.bit.PERINTSEL = persel;        // Passed DMA channel as peripheral interrupt source    DmaRegs.CH1.MODE.bit.PERINTE = perinte;         // Peripheral interrupt enable    DmaRegs.CH1.MODE.bit.ONESHOT = oneshot;         // Oneshot enable    DmaRegs.CH1.MODE.bit.CONTINUOUS = cont;         // Continous enable    DmaRegs.CH1.MODE.bit.SYNCE = synce;             // Peripheral sync enable/disable    DmaRegs.CH1.MODE.bit.SYNCSEL = syncsel;         // Sync effects source or destination    DmaRegs.CH1.MODE.bit.OVRINTE = ovrinte;         // Enable/disable the overflow interrupt    DmaRegs.CH1.MODE.bit.DATASIZE = datasize;       // 16-bit/32-bit data size transfers    DmaRegs.CH1.MODE.bit.CHINTMODE = chintmode;     // Generate interrupt to CPU at beginning/end of transfer    DmaRegs.CH1.MODE.bit.CHINTE = chinte;           // Channel Interrupt to CPU enable    // Clear any spurious flags:    DmaRegs.CH1.CONTROL.bit.PERINTCLR = 1;          // Clear any spurious interrupt flags    DmaRegs.CH1.CONTROL.bit.SYNCCLR = 1;            // Clear any spurious sync flags    DmaRegs.CH1.CONTROL.bit.ERRCLR = 1;             // Clear any spurious sync error flags    // Initialize PIE vector for CPU interrupt:    PieCtrlRegs.PIEIER7.bit.INTx1 = 1;              // Enable DMA CH1 interrupt in PIE    EDIS;}
/*----------------其他的---------------*/void DMAInitialize(void){    EALLOW;    // Perform a hard reset on DMA    DmaRegs.DMACTRL.bit.HARDRESET = 1;    // Allow DMA to run free on emulation suspend    DmaRegs.DEBUGCTRL.bit.FREE = 1;    EDIS;}
void StartDMACH1(void){    EALLOW;    DmaRegs.CH1.CONTROL.bit.RUN = 1;    EDIS;}

四.详解
1) 28335DMA模块具有独立PIE中断的6个通道 ,字长度为16位或32位(McBSPs限制为16位)。其中DMA总线包含22位的地址线,32位的读总线和32位的写总线。连接到DMA总线上的存储器和寄存器通过接口与CPU存储器或外设总线共享资源。

2) DMA状态机是两级嵌套循环。

BURST_SIZE寄存器定义帧的长度大小(每帧最多32个16位字),内循环;
TRANSFER_SIZE寄存器定义整个传送过程中共传送多少个这样的帧数据,外循环;每次传送可以产生一个CPU中断(若中断使能),该中断可以通过MODE.CHx[CHINTMODE]位配置为在每次传送开始或结束时刻产生。

在MODE.CHx[ONESHOT]位默认设置下,DMA在每接收一个中断触发事件信号时传送一帧数据。此时若单个触发事件要求输送的数据大于允许传送字的最大值,这是不允许某一触发事件独占DMA总线。此时可以通过配置MODE.CHx[ONESHOT]位配置来完成整个数据帧的传递任务。需要注意的是,这种模式下可能会发生某一触发事件独占大部分DMA带宽的情况。

3) 每个DMA通道包含了源地址(SRC_ADDR)和目的地址(DST_ADDR)的映射地址指针。在每次传送开始时,映射(shadow)寄存器中的地址会复制到相应的当前工作(active)寄存器中。

在帧循环(BURST_LOOP)中,每个字传送完毕后,源地址和目的地址的BURST_STEP寄存器中的值会加到当前工作的SRC/DAT_ADDR上,用以修改当前工作的地址指针。
在传送循环(TRANSFER_LOOP)中,每一帧传送完毕后,有两种方法修改当前工作地址指针:

方法一(默认):将SRC/DST_TRANSFER_STEP寄存器中的值加到相应的地址指针上

方法二:“Wrapping(打包)”的过程。该方法中,一个数据打包的地址装在到当前工作的地址指针中(即赋值)。当一个打包过程发生后,相应的SRC/DST_TRANSFER_STEP寄存器内容将被忽略。当SRC/DST_TRANSFER_SIZE所定义的一定数量的帧数据传送完毕后,地址打包过程发生。每个DMA通道包含了两个打包地址指针:SRC_BEG_ADDR和DST_BEG_ADDR。这两个指针已被映射,源打包地址和目的打包地址可以独立配置。与SRC_ADDR和DST_ADDR寄存器一样,在每个传送的开始,当前工作的SRC_BEG_ADDR和DST_BEG_ADDR寄存器将载入与之相对应的映射寄存器的内容。当一定数量的帧数据传送完毕之后,“打包”过程分两步发生,首先当前工作寄存器SRC/DST_BEG_ADDR按照SRC/DST_WARP_STEP寄存器中的定义值增加;然后新的当前工作寄存器SRC/DST_BEG_ADDR内容被加载到SRC/DST_ADDR寄存器中。此外,数据打包计数器(SRC/DST_WRAP_COUNT)寄存器重新载入SRC/DST_WARP_SIZE的值,启动下一个“打包”周期。

在地址指针中,DMA分别包含了当前工作(active)和映射(shadow)寄存器组。当DMA传送开始时,映射寄存器组的内容复制到当前工作的寄存器组。这就允许用户在DMA工作于当前工作的寄存器组时,对映射寄存器组编程,为下次传送做准备。

五.栗子

#include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File#include "DSP2833x_Examples.h"   // DSP2833x Examples Include File#define BUF_SIZE   1024  // Sample buffer size#pragma DATA_SECTION(DMABuf1,"DMARAML4");#pragma DATA_SECTION(DMABuf2,"ZONE6DATA");volatile Uint16 DMABuf1[BUF_SIZE];volatile Uint16 DMABuf2[BUF_SIZE];volatile Uint16 *DMADest;volatile Uint16 *DMASource;interrupt void local_DINTCH1_ISR(void);void init_zone6(void);void main(void){   Uint16 i;// Step 1. Initialize System Control:// PLL, WatchDog, enable Peripheral Clocks// This example function is found in the DSP2833x_SysCtrl.c file.   InitSysCtrl();// Step 2. Initialize GPIO:// This example function is found in the DSP2833x_Gpio.c file and// illustrates how to set the GPIO to it's default state.// InitGpio();  // Skipped for this example// Step 3. Clear all interrupts and initialize PIE vector table:// Disable CPU interrupts   DINT;// Initialize the PIE control registers to their default state.// The default state is all PIE interrupts disabled and flags// are cleared.// This function is found in the DSP2833x_PieCtrl.c file.   InitPieCtrl();// Disable CPU interrupts and clear all CPU interrupt flags:   IER = 0x0000;   IFR = 0x0000;// Initialize the PIE vector table with pointers to the shell Interrupt// Service Routines (ISR).// This will populate the entire table, even if the interrupt// is not used in this example.  This is useful for debug purposes.// The shell ISR routines are found in DSP2833x_DefaultIsr.c.// This function is found in DSP2833x_PieVect.c.   InitPieVectTable();// Interrupts that are used in this example are re-mapped to// ISR functions found within this file.   EALLOW;  // Allow access to EALLOW protected registers   PieVectTable.DINTCH1= &local_DINTCH1_ISR;   EDIS;   // Disable access to EALLOW protected registers   IER = M_INT7 ;                                //Enable INT7 (7.1 DMA Ch1)   EnableInterrupts();   CpuTimer0Regs.TCR.bit.TSS  = 1;               //Stop Timer0 for now//Step 5. User specific code, enable interrupts:  // Initialize DMA     DMAInitialize();    init_zone6();    // Initialize Tables   for (i=0; i<BUF_SIZE; i++)   {     DMABuf1[i] = 0;     DMABuf2[i] = i;   }// Configure DMA Channel    DMADest   = &DMABuf1[0];    DMASource = &DMABuf2[0];    DMACH1AddrConfig(DMADest,DMASource);    DMACH1BurstConfig(31,2,2);         //Will set up to use 32-bit datasize, pointers are based on 16-bit words    DMACH1TransferConfig(31,2,2);      //so need to increment by 2 to grab the correct location    DMACH1WrapConfig(0xFFFF,0,0xFFFF,0);    //Use timer0 to start the x-fer.      //Since this is a static copy use one shot mode, so only one trigger is needed    //Also using 32-bit mode to decrease x-fer time    DMACH1ModeConfig(DMA_TINT0,PERINT_ENABLE,ONESHOT_ENABLE,CONT_DISABLE,SYNC_DISABLE,SYNC_SRC,OVRFLOW_DISABLE,THIRTYTWO_BIT,CHINT_END,CHINT_ENABLE);     StartDMACH1();   //Init the timer 0   CpuTimer0Regs.TIM.half.LSW = 512;    //load low value so we can start the DMA quickly   CpuTimer0Regs.TCR.bit.SOFT = 1;      //Allow to free run even if halted   CpuTimer0Regs.TCR.bit.FREE = 1;    CpuTimer0Regs.TCR.bit.TIE  = 1;      //Enable the timer0 interrupt signal   CpuTimer0Regs.TCR.bit.TSS  = 0;      //restart the timer 0   for(;;);}// INT7.1interrupt void local_DINTCH1_ISR(void)     // DMA Channel 1{   Uint16 i;    // To receive more interrupts from this PIE group, acknowledge this interrupt    PieCtrlRegs.PIEACK.all = PIEACK_GROUP7;  // Next two lines for debug only to halt the processor here  // Remove after inserting ISR Code   for (i=0; i<BUF_SIZE; i++)   {     if(DMABuf1[i] != i)     {        asm ("      ESTOP0");//error        break;     }   }   asm ("      ESTOP0");//ok   for(;;);}// Configure the timing paramaters for Zone 6.// Notes: //    This function should not be executed from XINTF//    Adjust the timing based on the data manual and//    external device requirements.     void init_zone6(void){    EALLOW;    // Make sure the XINTF clock is enabled    SysCtrlRegs.PCLKCR3.bit.XINTFENCLK = 1;    EDIS;     // Configure the GPIO for XINTF with a 16-bit data bus    // This function is in DSP2833x_Xintf.c    InitXintf16Gpio();    // All Zones---------------------------------    // Timing for all zones based on XTIMCLK = SYSCLKOUT     EALLOW;    XintfRegs.XINTCNF2.bit.XTIMCLK = 0;    // Buffer up to 3 writes    XintfRegs.XINTCNF2.bit.WRBUFF = 3;    // XCLKOUT is enabled    XintfRegs.XINTCNF2.bit.CLKOFF = 0;    // XCLKOUT = XTIMCLK     XintfRegs.XINTCNF2.bit.CLKMODE = 0;       // Zone 6------------------------------------    // When using ready, ACTIVE must be 1 or greater    // Lead must always be 1 or greater    // Zone write timing    XintfRegs.XTIMING6.bit.XWRLEAD = 1;    XintfRegs.XTIMING6.bit.XWRACTIVE = 2;    XintfRegs.XTIMING6.bit.XWRTRAIL = 1;    // Zone read timing    XintfRegs.XTIMING6.bit.XRDLEAD = 1;    XintfRegs.XTIMING6.bit.XRDACTIVE = 3;    XintfRegs.XTIMING6.bit.XRDTRAIL = 0;    // don't double all Zone read/write lead/active/trail timing     XintfRegs.XTIMING6.bit.X2TIMING = 0;    // Zone will not sample XREADY signal      XintfRegs.XTIMING6.bit.USEREADY = 0;    XintfRegs.XTIMING6.bit.READYMODE = 0;    // 1,1 = x16 data bus    // 0,1 = x32 data bus    // other values are reserved    XintfRegs.XTIMING6.bit.XSIZE = 3;    EDIS;    //Force a pipeline flush to ensure that the write to    //the last register configured occurs before returning.     asm(" RPT #7 || NOP"); }
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 医保卡被冒用怎么办 理财钱被骗走怎么办 个体户怎么办三方协议 社保户籍错了怎么办 身份证号码变更后驾驶证怎么办 公司倒闭欠工资怎么办 海南买房要社保怎么办? 工商核名不过怎么办 税局要求查账怎么办 完税凭证丢了怎么办 开票开错了怎么办 上海居住证搬家了怎么办 上海无户口 医保怎么办 淘宝账号注销不了怎么办 淘宝账号被覆盖怎么办 淘宝号注册不了怎么办 appleid密码忘了怎么办 蘑菇街用白富美后忘记账号怎么办 不知道宽带账号怎么办 上网用户名忘了怎么办 别人借淘宝号怎么办 不知道ipad密码怎么办 捡的ipad密码怎么办 12306注册名已存在怎么办 忘记网银用户名怎么办 登录用户名忘了怎么办 网银登录错误怎么办 路由器账号忘了怎么办 忘记宽带账号密码怎么办 12123被注册过怎么办 w10不能创建账户怎么办 忘记xp登录密码怎么办 华硕密码忘记了怎么办 电脑账户已停用怎么办 鼠标灯亮不动怎么办 电脑用户名被停用怎么办 电脑截图不清晰怎么办 win10电脑磁盘空间不足怎么办 我的用户名忘记怎么办 12306用户名密码忘记怎么办 电脑开机要密码怎么办