电子产业一站式赋能平台

PCB联盟网

搜索
查看: 136|回复: 0
收起左侧

小白都看得懂的STM32的DMA知识

[复制链接]

395

主题

395

帖子

2304

积分

三级会员

Rank: 3Rank: 3

积分
2304
发表于 2023-11-26 21:00:00 | 显示全部楼层 |阅读模式

c0emyanxtoy64029381833.png

c0emyanxtoy64029381833.png
8 A3 U8 W4 Q3 p) S
一、DMA简介1、DMA简介DMA(Direct Memory Access:直接内存存取)是一种可以大大减轻CPU工作量的数据转移方式。CPU有转移数据、计算、控制程序转移等很多功能,但其实转移数据是可以不需要CPU参与。比如希望外设A的数据拷贝到外设B,只要给两种外设提供一条数据通路,再加上一些控制转移的部件就可以完成数据的拷贝。DMA就是基于以上设想设计的,它的作用就是解决大量数据转移过度消耗CPU资源的问题。有了DMA使CPU更专注于更加实用的操作--计算、控制等。
, c4 x; E1 L. L3 N2、DMA的工作原理   DMA的作用就是实现数据的直接传输,而去掉了传统数据传输需要CPU寄存器参与的环节,主要涉及四种情况的数据传输,但本质上是一样的,都是从内存的某一区域传输到内存的另一区域(外设的数据寄存器本质上就是内存的一个存储单元)。四种情况的数据传输如下:
  • 外设到内存
  • 内存到外设
  • 内存到内存
  • 外设到外设当用户将参数设置好,主要涉及源地址、目标地址、传输数据量这三个,DMA控制器就会启动数据传输,传输的终点就是剩余传输数据量为0。换句话说只要剩余传输数据量不是0,而且DMA是启动状态,那么就会发生数据传输。  4 |' g4 z- p7 o8 Q: A( H9 s
    3、DMA是否影响CPU的运行在X86架构系统中,当DMA运作时,DMA实际上会占用系统总线周期中的一部分时间。也就是说,在DMA未开启前,系统总线可能完全被CPU使用;当DMA开启后,系统总线要为DMA分配一定的时间,以保证DMA和CPU同时运作。那么显然,DMA会降低CPU的运行速度。
    4 g3 ^- B. \3 n' `, N7 Y在STM32控制器中,芯片采用Cortex-M3架构,总线结构有了很大的优化,DMA占用另外的总线,并不会与CPU的系统总线发生冲突。也就是说,DMA的使用不会影响CPU的运行速度。! k5 N. n3 z+ p  _8 h4 W8 k3 x$ O

    ' c' o) E) F1 ]) W# S二、STM32的DMA结构1、DMA的主要特性● 12个 独立的可配置的通道DMA1有7个通道,DMA2 有5个通道 3 A9 Q' \$ c) L, A  H8 Z; U6 `
    ● 每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件发。这些功能通过软件来配置。 7 A+ g2 @3 v1 K8 h; ^! e1 w$ b! Y
    ● 在七个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),假如在相等优先权时由硬件决定(请求0优先于请求1,依此类推) 。   }. b5 W9 K  w/ n* V9 n2 A- V
    ● 独立的源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。 6 ^' B; R3 C- d- K$ l: D
    ● 支持循环的缓冲器管理
    $ P; m  H$ O2 V+ X: B● 每个通道都有3个事件标志(DMA 半传输,DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求。 9 M. ]! Y7 h$ O* A* Z+ h
    ● 存储器和存储器间的传输
    % o- d. r2 c1 r+ U. B! \● 外设和存储器,存储器和外设的传输 1 H2 ?% [% Y) ]8 L0 l2 ~/ ~/ L
    ● 闪存、SRAM 、外设的SRAM 、APB1 APB2和AHB外设均可作为访问的源和目标。
    + r5 u  c) q, z5 L- G0 c● 可编程的数据传输数目:最大为65536
    . D- X9 z1 W0 {2 K) o下面为功能框图:
    " ~( Y# a: ?( B8 t1 e$ D! G0 R/ m" i3 @, ~

    h34tsoyqefv64029381933.png

    h34tsoyqefv64029381933.png

    2 v# Q6 k7 x' G5 p3 D5 d9 K4 d  7 s) _& K& N9 ]" l3 ]
    2、两个DMA控制器结构① DMA1 controller
    1 _& ^# N" S( |5 Q: [# i/ r& B

    beostn2jr4l64029382033.png

    beostn2jr4l64029382033.png
    : J! P: Q0 ~; `; A3 z, V
    ② DMA2 controller9 @& l7 B7 ]+ a& d5 |, c3 ]

    m3qtcpt5ady64029382133.png

    m3qtcpt5ady64029382133.png

    + B0 P; w+ _5 C  u! \9 c3、DMA寄存器列表
    . j" E9 X- @. U' i

    z132ed2owkd64029382233.png

    z132ed2owkd64029382233.png
    / T$ E; C9 s  i& P+ z) ~
    ① 中断类DMA_ISR:DMA中断状态寄存器DMA_IFCR:DMA中断标志位清除寄存器说明:DMA1、DMA2分别有一组寄存器。② 控制传输类DMA_CCRx:DMA通道x配置寄存器 DMA_CNDTRx:DMA通道x数据数量寄存器DMA_CPARx:DMA通道x外设地址寄存器DMA_CMARx:DMA通道x内存地址寄存器
    * P7 ~; A" H1 Q说明:   1> 每一个通道都有一组寄存器。2> DMA_CPARx、DMA_CMARx是没有差别的,它们都可以存放外设的地址、内存的地址。DMA_CPARx、DMA_CMARx只不过起得名字有差别而已。
    2 w- R9 y% k; o4、STM32的DMA工作特点① DMA进行数据传输的必要条件剩余传输数据量大于0DMA通道传输使能通道上DMA数据传输有事件请求前两者都好理解,对于第三点确实需要详细的解释,请看下边的三条。
    & D3 D* h$ v; O3 k6 ~! e2 y② 外设到XX方向的传输假设是ADC到存储器的数据传输,显然ADC的DMA传输的源地址是ADC的数据寄存器。并不是说只要DMA通道传输使能后,就立即进行数据传输。只有当一次ADC转化完成,ADC的DMA通道的传输事件有效,DMA才会从ADC的数据寄存器读出数据,写入目的地址。当DMA在读取ADC的数据寄存器时,同时使ADC的DMA通道传输事件无效。显然,要等到下一次ADC转换完成后,才能启动再一次的数据传输。4 X: o1 _+ j8 U% z$ x2 D6 w
    ③存储器对XX的DMA传输因为数据是准备好的,不像ADC还需要等待数据到位。所以,不需要对应通道的事件。只要使能DMA数据传输就一直传输,直到达到设定的传输量。- h- |3 q. O, C% q3 D2 j
    举个例子:1.内存到内存  DMA传输请求一直有效2.内存到串口   DMA传输请求一直有效一种解释:  存储器对存储器的置位,就相当于相应通道的事件有效。 对应通道的事件有效和存储器对存储器的置位,就是传输的触发位。每次传输的事件置位一次,完成一次传输。如果是由外设引发的DMA传输,则传输完成后,相应传输事件会置为无效,而存储器对存储器的传输,则一次传输完成后,相应事件一直有效,直至完成设定的传输量。④外设以DMA方式工作时,能否再以软件方式进行操作?有一点是肯定的,当外设以DMA方式正在数据传输时,不可能再相应CPU的软件控制命令,否则这不符合逻辑。
    1 b7 G  c) ^6 K6 n& c但是,倘若外设仅仅配置成DMA工作方式,但是DMA请求并未产生,数据传输并没有进行。此时,软件控制命令仍然能够对外设进行控制。这是笔者在串口以DMA方式发送数据情形下,所得到的测试结论。 7 B  d$ f) I, Q" E1 K) t
    三、STM32的DMA软件编程1、“内存到内存”模式传输① 初始化配置
  • /**  * @brief  USART1 TX DMA 配置,内存到内存  * @param  无  * @retval 无  */void DMA_Mem2Mem_Config(void){    DMA_InitTypeDef DMA_InitStructure;        /*开启DMA时钟*/    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);        /*设置DMA源地址*/    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SendBuff;& s& n* k" S" U% m+ O
        /*设置DMA目的地址*/    DMA_InitStructure.DMA_PeripheralBaseAddr =  (uint32_t)ReceiveBuff;      
    0 L3 F9 V+ J7 ~2 {- l    /*方向:从内存SendBuff到内存ReceiveBuff*/            DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;            /*传输大小DMA_BufferSize=SENDBUFF_SIZE*/        DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
    9 @1 k3 A- @3 u' T2 y; b, _    /*ReceiveBuff地址自增*/          DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; 4 S+ k6 Q% J" T
        /*SENDBUFF_SIZE地址自增*/    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;   
    ; c. S3 _9 x+ W9 L) T    /*ReceiveBuff数据单位*/        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;" J/ j+ i# h+ b) s6 x& _
        /*SENDBUFF_SIZE数据单位*/    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;     5 f' c: ?4 c) z$ k; D# U
        /*DMA模式:正常模式*/    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
    2 n1 U+ x$ b0 W& @! q! |, v    /*优先级:中*/        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;  
    ) E; k; l- h3 x" m3 `* x9 \6 |. u3 d    /*使能内存到内存的传输    */    DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;        /*配置DMA1的4通道*/               DMA_Init(DMA1_Channel4, &DMA_InitStructure);                    /*失能DMA1的4通道,一旦使能就开始传输*/    DMA_Cmd (DMA1_Channel4,DISABLE); }
    9 P0 {( O/ Q( r0 c& |9 @- Y② DMA中断配置
  • /*  * @brief  DMA 中断配置  * @param  无  * @retval 无  */void DMA_NVIC_Configuration(void){                                                                          NVIC_InitTypeDef NVIC_InitStructure;                    /* 配置中断源 */    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    NVIC_Init(&NVIC_InitStructure);    * j- b( u( `, V* Z# f
        /* 配置DMA发送完成后产生中断 */                DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);}$ X3 l' R6 o# x! M+ q) C. q: n- A
    ③启动传输
  • DMA_Cmd (DMA1_Channel4,ENABLE);- F- ]; U! j2 i/ Y2 {2 L3 y
    2、利用DMA实现循环传输方法1:单次传输模式当传输结束时,触发DMA中断,在中断程序中首先失能DMA通道,然后修改该通道的传输数据量。最后重新使能DMA通道,注意只有失能的DMA通道才能成功修改传输数据量。
    3 `9 M' c2 x  ?5 t9 i方法2:循环传输模式当传输结束时,硬件自动会将传输数据量寄存器进行重装,进行下一轮的数据传输。
    1 `+ R) b& F- m3 H/ n# Y2 q& e
      R0 H3 ?5 d- d& M! n1 g0 u四、再谈STM32的DMA传输是否影响CPU的运行速度声明:经过笔者测试,当DMA工作在内存到外设的传输和内存到内存的传输时,都不会影响CPU的运行速度。为了给这种现象一个合理的解释,笔者做以下猜测:
    7 ^3 d. d$ T& O( z5 D1、S3C2440的DMA传输S3C2440的SDRAM是外置的,并且SDRAM的数据线、地址线、控制线总共只有一组。假设DMA传输的方向是内存到外设,当DMA运作时,需要占用SDRAM的三类线才才能实现传输;而与此同时CPU也需要通过这三类线来访问SDRAM来读取程序、读写数据。$ p+ Y! k( f' [8 P
    显然,DMA的运行与CPU的运行有交叉点,DMA就会影响到CPU的运行。  K+ @# L( I  j2 w: [2 c5 v* M
    2、STM32的DMA传输  STM32与S3C2440的区别是很大的,S3C2440是微处理器,RAM外置且空间很大;STM32是微控制器,RAM片内集成且空间较小。此时,ST公司就有可能提升DMA的运作效率,使DMA的工作不影响到CPU的运行。  外设与外设之间的DMA传输,因为与CPU的运行没有交叉点(CPU的数据流注意是在Flash、内存、寄存器中传输),所以不会影响CPU的运行速度。唯一有可能影响的是外设与内存或者内存与内存之间的DMA传输。  倘若ST公司的SRAM是一个双口RAM,也就是同时可以由两组接口对RAM进行访问,就可以很好的解决速度影响问题。倘若CPU恒定占有一组接口,而另一组接口留给DMA控制器。那么当外设与内存或者内存与内存之间的DMA传输时,由于不与CPU的访问SRAM接口冲突,所以可以解决速度影响问题。  但其实偶尔还是会影响的,当CPU访问SRAM的空间和DMA访问SRAM的空间相同时,SRAM势必会对这种情况进行仲裁,这可能会影响到CPU的访问SRAM的速度。其实,这种情况的概率也是很小的,所以即使影响CPU的运行速度,也不会很大。
    3 s3 ]: o, h) D$ G. D$ G6 X0 j==========
    " S/ e; b" }+ B0 f2 W) n往期回顾:ADC的低功耗和阻抗问题% H$ P! F; }7 d: n# K
    利用STM32CubeMX解读时钟树# Y+ }! [- G* u( O: c- Y4 \' z/ b
    外部中断为什么会误触发?# ?# Q8 G* j* ^
    读取STM32芯片温度与当前供电电压" d, m0 ?  t" a
    有源晶振和无源晶振的区别==========原文来源:请点击阅读原文作者:鲸小鱼-平台:博客园
    7 y2 ^* r0 s3 F1 \' H* O: [1 Y
    * U% F' f" x' D0 r' n

    dsctyde4gju64029382334.png

    dsctyde4gju64029382334.png

    , h; }- S  [( b
    . y4 K( q% i" |) Z/ ^9 b: @/ m2 V

    zyrzxpwwxqe64029382434.png

    zyrzxpwwxqe64029382434.png
    " i8 H4 K  O+ w5 V7 M; Q* _/ K
    ! L' u+ ~/ H) j& X

    f5poruf522p64029382534.png

    f5poruf522p64029382534.png
  • 回复

    使用道具 举报

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则


    联系客服 关注微信 下载APP 返回顶部 返回列表