【第十三讲】TMS320F28335开发板之DMA模块

直接存储器访问(DMA)模块

 
一、内存与外设进行数据交换的方式
  • 中断方式:每传输一次数据,就必须经历中断处理的全部步骤,而且一般需要借助CPU内部的寄存器作为中介,也就是说CPU需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方,在这个时间中,CPU对于其他的工作来说就无法使用。
  • DMA模式:不用CPU的寄存器作为传输中介,完成存储器和外设间、存储器和存储器间的直接传输,需要注意的是,在DMA工作的时候,CPU必须将系统总线的控制权让给DMAC
    在所有嵌入式系统外设操作中,中断方式(包括查询方式)是广泛使用的操作方式。其特点是需要通过CPU执行ISR来控制整个数据的传输,输入输出都要以CPU的寄存器为中转站。以中断方式数据传输为例,每一次响应中断,CPU都要保护主程序断点的工作现场,而后执行ISR。输出传输操作完毕后,还要恢复断点处的工作现场。因此在某些高频度外设操作的嵌入式应用场合,执行中断方式的输入输出会导致系统频繁切换工作现场,CPU运行效率不高。
    在DMA传输方式下,外设通过DMA控制器(DMAC)向CPU提出接管总线控制权的总线使用请求。CPU在当前总线周期结束后,响应DMA请求,把总线控制权交给DMA控制器。于是在DMAC的控制下,外设和存储器挪用CPU的一个总线周期,直接进行数据交换,而无需CPU进行数据传输控制干预。DMA传输结束后,再将总线使用权交还给CPU。
    在高速大数据量传输场合,DMA方式由于系统开销少,传输效率比中断方式优越。
    注意!不是说所有的数据传输都是需要用DMA,因为DMA的通道是非常有限的。
 
二、F28335的DMA模块的作用:
  1. 减轻CPU“搬运”数据的工作量,释放CPU带宽(核心)。DMA可以管理和实现硬件外设和硬件外设,硬件外设和内存,内存和内存之间的数据传输,这样就不需要CPU的参与,从而减少CPU的工作量。(CPU的优劣不能单纯的用CPU的主频高低来衡量,而是整体的能力高低)
  2. 在缓冲器之间传送“乒-乓”数据,传输数据更加快速
  3. 重新排列数据,方便CPU处理。
 
三、DMA模块总线结构
    DMA是基于事件的模块,因此需要有一个外设中断触发才开始DMA数据传输。6个DMA通道的中断触发源可独立配置,并且每一个通道都具有各自独立的PIE中断,当DMA传送开始或结束时,可通过PIE中断告知CPU。6个通道中,有5个具有相同的性能,而通道1具有一个附加特性:其优先级可以配置成比其他通道的优先级高。DMA模块的核心是一状态机并于地址控制逻辑总线联系在一起。正是因为这个地址控制逻辑总线允许对传输过程中的数据块包括缓冲器间的“乒-乓”数据重新排列。
  1. DMA的基本特点
  • 具有独立PIE中断的6个通道;
  • 外设中断触发源:ADC模块排序器1和2、多通道缓冲串口A和B(McBSP-A,McBSP-B)的发送和接收、XINT1~7和XINT13、CPU定时器、ePWM1~6的ADSOCA和ADSOCB信号以及软件强制触发。
  • 数据源/目的地:L4~L7 16K SARAM、所有XINT区域、ADC模块结果存储器ADCRESULTn、McBSP-A和McBSP-B发送和接收缓冲器、ePWM1~6/HRPWM1~6外设帧3映射的寄存器。
  • 字长度:16位或32位(McBSPs限制为16位)
  • 吞吐量:4个时钟周期/字(对于M吃BSP读操作,5个时钟周期/字)
DMA工作过程: 上面提到过,在DMA工作的时候,CPU必须将系统总线的控制权让给DMAC。
因此,存在着一个总线控制权转移问题。即DMA传输前,CPU要把总线控制权交给DMA控制器,而在结束DMA传输后,DMA控制器应立即把总线控制权再交回给CPU。一个完整的DMA传输过程必须通过下面的4个步骤:
            1.DMA请求
                CPU对DMA控制器初始化,并向外设接口发出操作命令,外设接口提出DMA请求。
            2.DMA响应
                DMA控制器对DMA请求判别优先级及屏蔽,向总线裁决逻辑提出总线请求。当CPU执行完当前                    总线周期即可释放总线控制权。此时,总线裁决逻辑输出总线应答,表示DMA已响应,通过DMA控制器通知外设接口开始DMA传输。
            3.DMA传输
                DMA控制器获得总线控制权之后,CPU即刻挂起或只执行内部操作,由DMA控制器输出读写命令,直接控制RAM与外设接口进行DMA传输。
                在DMA控制器的控制下,在存储器和外部设备之间直接进行数据传送,在传送过程中个不需要与中央处理器的参与。开始时需要提供要传输的数据的起始位置和数据长度。
            4.DMA结束
                在完成规定的成批数据传送后,DMA控制器即释放总线控制权,并向外设接口发出结束信号。当外设接口接收到结束信号后,一方面停止外设设备的工作,另一方面向CPU提出中断请求,使CPU从不介入的状态解脱,并执行一段检查本次DMA传输操作正确性的代码。最后,带着本次操作结果及状态继续执行原来的程序。
                由此可见,DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与外设设备开辟一条直接传送的通道。
2.外设中断事件触发源
 
    上图为外设中断触发选择电路结构图,从上图可以看出MODE.CHx[PERINTSEL位]来选择每个DMA通道(DMA模块共6个DMA通道)的中断触发源,一个有效的中断触发事件将锁存在CONTROL寄存器的[PERINTELG位],并且如果相应的中断和DMA通道被使能(MODE.CHx[PERINTE位]和CONTROL.CHx[RUNSTS位]),则DMA通道将会响应中断事件。一旦接收到外设中断事件信号,DMA会自动向中断源发送清零信号,以保证后续中断事件的发生。
    无论MODE.CHx[PERINTSEL位]的值是什么,软件总可以通过CONTROLCHx[PERINTFRC位]给通道一个强制触发事件。同样,软件也可以通过CONTROL.CHx[PERINTCLR位]清除一个悬挂的DMA触发源。
    一旦特定的中断触发源将通道的CONTROL.CHx[PERINTELG位]置位后,该位将保持悬挂状态直到状态机的优先逻辑启动该通道的数据传送;当数据传送开始之后,该标志位将被清零。如果外设中断事件与清除[PERINTELG位]标志位同时发生,外设中断事件有优先权,且PERINTELG位仍保持置位。
 
3.DMA总线
    DMA总线包含22位的地址线,32位的读总线和32位的写总线。连接到DMA总线上的存储器和寄存器通过接口与CPU存储器或外设总线共享资源。
 
4.流水线(PipeLine)时序
DMA包括4级流水线操作。当DMA配置成使用McBSPs作为数据源时,在传送数据过程中,读DRR寄存器会使DMA总线暂停一个时钟周期。
 
5.28335 DMA配置函数(简单介绍几个,方便下面的实验)
    DMACHx(DMA Channel):x=1~6
  • void DMACHxAddrConfig(volatile Unit16 *DMA_Dest,volatile Unit16 *DMA_Source)
        参数解析:配置DMA的数据目的地地址源地址(跟函数中参数的排序相同,下同)
  • 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)“打包”过程配置
        参数解析:配置源地址“打包”过程每个“打包”所含帧的个数、源地址每个“打包”完成之后的地址偏移增量、配置目的地址“打包”过程每个“打包”所含帧的个数、目的地址每个“打包”完成之后的地址偏移增量。
  • 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位)、通道中断模式选择(开始或结束)、通道中断使能。
 
*6.CPU仲裁和通道优先级(具体用到可以查相关资料)
 
7.地址指针和传送控制(以上对函数参数的解释如果不太理解可以结合下面的来看)
    DMA状态机是两级嵌套循环。
  • BURST_SIZE寄存器定义帧的长度大小(每帧最多32个16位字)内循环
  • TRANSFER_SIZE寄存器定义整个传送过程中共传送多少个这样的帧数据,外循环;每次传送可以产生一个CPU中断(若中断使能),该中断可以通过MODE.CHx[CHINTMODE]位配置为在每次传送开始或结束时刻产生。
  • 在MODE.CHx[ONESHOT]位默认设置下,DMA在每接收一个中断触发事件信号时传送一帧数据。此时若单个触发事件要求输送的数据大于允许传送字的最大值,这是不允许某一触发事件独占DMA总线。此时可以通过配置MODE.CHx[ONESHOT]位配置来完成整个数据帧的传递任务。需要注意的是,这种模式下可能会发生某一触发事件独占大部分DMA带宽的情况。
  • 每个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工作于当前工作的寄存器组时,对映射寄存器组编程,为下次传送做准备。
*******************************************************************************************************************以上就是硬件理论部分,下面是实验部分:
1.Example_2833xDMA_ram_to_ram.c 【DMA从RAM传输数据到另一个RAM】 本次实验使用的是定时器0作为外部中断事件源
 
  1. // TI File $Revision: /main/3 $
  2. // Checkin $Date: May 12, 2008 14:23:19 $
  3. //###########################################################################
  4. //
  5. // FILE: Example_2833xDMA_Ram_to_Ram.c
  6. //
  7. // TITLE: DSP2833x DMA Ram to Ram
  8. // ASSUMPTIONS:
  9. //
  10. // This program requires the DSP2833x header files.
  11. //
  12. // As supplied, this project is configured for "boot to SARAM"
  13. // operation. The 2833x Boot Mode table is shown below.
  14. // For information on configuring the boot mode of an eZdsp,
  15. // please refer to the documentation included with the eZdsp,
  16. //
  17. // $Boot_Table:
  18. //
  19. // GPIO87 GPIO86 GPIO85 GPIO84
  20. // XA15 XA14 XA13 XA12
  21. // PU PU PU PU
  22. // ==========================================
  23. // 1 1 1 1 Jump to Flash
  24. // 1 1 1 0 SCI-A boot
  25. // 1 1 0 1 SPI-A boot
  26. // 1 1 0 0 I2C-A boot
  27. // 1 0 1 1 eCAN-A boot
  28. // 1 0 1 0 McBSP-A boot
  29. // 1 0 0 1 Jump to XINTF x16
  30. // 1 0 0 0 Jump to XINTF x32
  31. // 0 1 1 1 Jump to OTP
  32. // 0 1 1 0 Parallel GPIO I/O boot
  33. // 0 1 0 1 Parallel XINTF boot
  34. // 0 1 0 0 Jump to SARAM <- "boot to SARAM"
  35. // 0 0 1 1 Branch to check boot mode
  36. // 0 0 1 0 Boot to flash, bypass ADC cal
  37. // 0 0 0 1 Boot to SARAM, bypass ADC cal
  38. // 0 0 0 0 Boot to SCI-A, bypass ADC cal
  39. // Boot_Table_End$
  40. //
  41. //
  42. // DESCRIPTION:
  43. //
  44. // Code will perform a block copy from L5 SARAM to L4 SARAM of 1024 words. Transfer will be started
  45. // by Timer0. Will use 32-bit datasize to decrease the transfer time.
  46. // Code will end in local_DINTCH1_ISR once the transfer is complete
  47. //
  48. // Watch Variables:
  49. // DMABuf1
  50. // DMABuf2
  51. //
  52. //###########################################################################
  53. //
  54. // Original source by: M.P.
  55. //
  56. // $TI Release: DSP2833x/DSP2823x Header Files V1.20 $
  57. // $Release Date: August 1, 2008 $
  58. //###########################################################################
  59. #include "DSP28x_Project.h" // Device Headerfile and Examples Include File
  60. #define BUF_SIZE 1024 // Sample buffer size
  61. // DMA Defines
  62. #define CH1_TOTAL DATA_POINTS_PER_CHANNEL
  63. #define CH1_WORDS_PER_BURST ADC_CHANNELS_TO_CONVERT
  64. #pragma DATA_SECTION(DMABuf1,"DMARAML4"); //将L4 SRAM中的数据传输到DMABuf1
  65. #pragma DATA_SECTION(DMABuf2,"DMARAML5"); //将L5 SRAM中的数据传输到DMABuf2
  66. volatile Uint16 DMABuf1[1024];
  67. volatile Uint16 DMABuf2[1024];
  68. volatile Uint16 *DMADest;
  69. volatile Uint16 *DMASource;
  70. interrupt void local_DINTCH1_ISR(void);
  71. void main(void)
  72. {
  73. Uint16 i;
  74. // Step 1. Initialize System Control:
  75. // PLL, WatchDog, enable Peripheral Clocks
  76. // This example function is found in the DSP2833x_SysCtrl.c file.
  77. InitSysCtrl();
  78. // Step 2. Initialize GPIO:
  79. // This example function is found in the DSP2833x_Gpio.c file and
  80. // illustrates how to set the GPIO to it's default state.
  81. // InitGpio(); // Skipped for this example
  82. // Step 3. Clear all interrupts and initialize PIE vector table:
  83. // Disable CPU interrupts
  84. DINT;
  85. // Initialize the PIE control registers to their default state.
  86. // The default state is all PIE interrupts disabled and flags
  87. // are cleared.
  88. // This function is found in the DSP2833x_PieCtrl.c file.
  89. InitPieCtrl();
  90. // Disable CPU interrupts and clear all CPU interrupt flags:
  91. IER = 0x0000;
  92. IFR = 0x0000;
  93. // Initialize the PIE vector table with pointers to the shell Interrupt
  94. // Service Routines (ISR).
  95. // This will populate the entire table, even if the interrupt
  96. // is not used in this example. This is useful for debug purposes.
  97. // The shell ISR routines are found in DSP2833x_DefaultIsr.c.
  98. // This function is found in DSP2833x_PieVect.c.
  99. InitPieVectTable();
  100. // Interrupts that are used in this example are re-mapped to
  101. // ISR functions found within this file.
  102. EALLOW; // Allow access to EALLOW protected registers
  103. PieVectTable.DINTCH1= &local_DINTCH1_ISR;
  104. EDIS; // Disable access to EALLOW protected registers
  105. IER = M_INT7 ; //Enable INT7 (7.1 DMA Ch1)
  106. EnableInterrupts();
  107. CpuTimer0Regs.TCR.bit.TSS = 1; //Stop Timer0 for now
  108. //Step 5. User specific code, enable interrupts:
  109. // Initialize DMA
  110. DMAInitialize(); //DMA初始化
  111. // Initialize Tables
  112. for (i=0; i<BUF_SIZE; i++)
  113. {
  114. DMABuf1[i] = 0; //16位数据
  115. DMABuf2[i] = i; //16位数据
  116. }
  117. // Configure DMA Channel
  118. DMADest = &DMABuf1[0]; //取目的地址指针指向DMABuf1数组
  119. DMASource = &DMABuf2[0]; //取源地址指针指向DMABuf2数组
  120. DMACH1AddrConfig(DMADest,DMASource); //DMA通道1源地址和目的地址配置
  121. DMACH1BurstConfig(31,2,2); //Will set up to use 32-bit datasize, pointers are based on 16-bit words //这里配置成传送32位的帧数据(每16位对应1个偏移增量,这里32位,对应2个偏移增量)
  122. DMACH1TransferConfig(31,2,2); //so need to increment by 2 to grab the correct location //配置传送模式,一个传送32个帧
  123. DMACH1WrapConfig(0xFFFF,0,0xFFFF,0); //配置“打包”过程
  124. //Use timer0 to start the x-fer.
  125. //Since this is a static copy use one shot mode, so only one trigger is needed
  126. //Also using 32-bit mode to decrease x-fer time
  127. DMACH1ModeConfig(DMA_TINT0,PERINT_ENABLE,ONESHOT_ENABLE,CONT_DISABLE,SYNC_DISABLE,SYNC_SRC,OVRFLOW_DISABLE,THIRTYTWO_BIT,CHINT_END,CHINT_ENABLE); //模式配置 THIRTYTWO_BIT决定了工作模式是32位; DMA_TINT0 定时器0中断,具体可以“Open Declaration”来看该变量的含义
  128. StartDMACH1(); //DMA 通道1启动
  129. //Init the timer 0
  130. CpuTimer0Regs.TIM.half.LSW = 512; //load low value so we can start the DMA quickly //定时器0初始化
  131. CpuTimer0Regs.TCR.bit.SOFT = 1; //Allow to free run even if halted
  132. CpuTimer0Regs.TCR.bit.FREE = 1;
  133. CpuTimer0Regs.TCR.bit.TIE = 1; //Enable the timer0 interrupt signal
  134. CpuTimer0Regs.TCR.bit.TSS = 0; //restart the timer 0
  135. for(;;){}
  136. }
  137. // INT7.1
  138. interrupt void local_DINTCH1_ISR(void) // DMA Channel 1
  139. {
  140. // To receive more interrupts from this PIE group, acknowledge this interrupt
  141. PieCtrlRegs.PIEACK.all = PIEACK_GROUP7;
  142. // Next two lines for debug only to halt the processor here
  143. // Remove after inserting ISR Code
  144. asm (" ESTOP0");
  145. for(;;);
  146. }
加载工程的方法这里不说了,这是说一下我们要监测的变量DMABuf1和DMABuf2这两个数组,分别选中后右键变量名添加“Add Watch Expression”,DMABuf2为源地址,DMABuf1为目的地址,只要DMABuf1中有了值,就说明DMABuf2中的值成功传送到DMABuf1
运行后:
2.Example_2833xDMA_xintf_to_ram.c  【DMA 从外扩RAM传输数据到内部RAM】
这个工程就不给大家演示了,和上一个实验差不多的。只是这次是将外部接口的XINT7区域内的数据输送到内部RAM,如果正确的话,结果同上一个实验是一样的,大家可以自己按照上面的步骤试试看。
 
本将结束,下一讲再见啦
  • 6
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
DSP28335是一款数字信号处理器,DMA(Direct Memory Access)是一种数据传输方式。在DSP28335中,DMA可以用来实现高速数据传输,提高系统的效率和性能。 引用\[1\]提到了DSP28335的官方例程,官方例程是指由DSP28335官方提供的示例代码,这些代码包含了各种功能的实现方法。官方例程可以帮助开发者快速上手DSP28335的开发,了解各个功能的使用方法。如果你想下载DSP28335的官方例程,可以参考《DSP28335入门教程:官方例程的下载》。 引用\[2\]和引用\[3\]提到了关于DMA在DSP28335中的应用。DMA可以用来实现数据的高速传输,提高系统的效率。在这个例子中,DMA被用来将四个通道的采样数据存放到DMABuf1数组中。每个通道采样10次,分别存放在DMABuf1\[0-9\]、DMABuf1\[10-19\]、DMABuf1\[20-29\]、DMABuf1\[30-39\]中。具体的存放方式是通过循环,每一帧将ADCRESULT0、ADCRESULT1、ADCRESULT2、ADCRESULT3的值存放到对应的DMABuf1位置中。 综上所述,DSP28335结合DMA可以实现高速数据传输,提高系统的效率和性能。官方例程可以帮助开发者快速上手DSP28335的开发,了解各个功能的使用方法。如果你想下载DSP28335的官方例程,可以参考《DSP28335入门教程:官方例程的下载》。 #### 引用[.reference_title] - *1* *2* *3* [DSP28335入门教程:ADC to DMA 前篇(官方例程Example_2833xAdcToDMA的分析)](https://blog.csdn.net/qq_40692629/article/details/88622324)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隨意的風

如果你觉得有帮助,期待你的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值