STMCU小助手
发布时间:2021-11-24 13:30
9 _2 `8 i0 B. @ DMA,全称Direct Memory Access,即直接存储器访问。DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。/ S9 l( W- A6 F0 l" x1 S ( L) e j* S! _- J2 Q5 l 主要特点: •DMA上多达7个可独立配置的通道(请求)) _9 v" P; G: A/ E4 r •每个通道都连接到专用的硬件DMA请求,软件触发为 / u" h4 s& g, l+ s: C3 U1 i 每个频道也都支持。该配置由软件完成。' D1 h6 c2 s8 i$ ] •DMA通道的请求之间的优先级是软件可编程的(4- L; p! r. r# K j, b1 h1 s 6 O2 l! m3 G; A" } 级别由非常高,高,中,低)或硬件组成(在相等的情况下)0 e9 y3 r# C, L4 d! I; `) z) U # B8 M# P. g1 y8 _1 P (请求1的优先级高于请求2的优先级,依此类推) ! Y& }' G; t9 j8 y3 j" I •独立的源和目标传输大小(字节,半字,字),模拟 包装和拆箱。源/目标地址必须与数据对齐 7 M# O4 d7 `: [, k/ | 尺寸。& W+ X5 P4 E, A% ^6 S |& m6 F' C8 g/ _ ( m/ m$ v7 G3 ]" t •支持循环缓冲区管理1 S/ ?* _* ^* w •3个事件标志(DMA半传输,DMA传输完成和DMA传输错误) 在每个通道的单个中断请求中进行逻辑或运算 •内存到内存的传输5 h+ d7 ]0 Z. x% u! I$ ]5 M 4 M4 Q. |* y5 m( i+ z7 c3 R •外围到内存和内存到外围,以及外围到外围- u: k" {6 T h: k6 w 转移 . o4 p8 e+ T3 a! j& U* ^: D' F; p9 U. k4 d% J •访问闪存,SRAM,APB和AHB外设作为源和目标 •可编程的数据传输数量:最多65535 7 _$ A C$ @/ P DMA通道对应的外设情况(F0系列):( Y4 A# C# R3 K! A* S0 b" v6 _ - A7 V( H" t% [7 y
- V3 Z7 ?! b0 {+ X6 D
3 L: P) f" o1 d( L* p9 \& m 很多博文会讲解里面的详细定义,对于每一处寄存器的详细操作指导,所以我就不会去多写了。 x. R& C7 s- {* \8 F- Y, U 我只想表达,DMA是一种可以快速相关外设数据交互的一种方法,我们学习哪里用它,怎么用它,至于细节学习,大家去网上所搜DMA相信息即可。 ' F& O% w2 _5 j! {" K3 r& a 之前讲过DMA的数据发送,现在补充上DMA的接收数据部分。 ( N d# @- H P' F 利用DMA接收串口数据的配置,大致分为:1.初始化串口并开启DMAR接收功能,配置DMA的外设到内存的数据接收功能,2.等待串口中断提示,并进行处理数据,3.清空DMA,重新等待数据5 Y2 n! i7 `2 o9 T6 P' l) j) F 4 Z* n0 O$ g a5 p 01 配置串口与DMA1 S- _8 {! R" ~$ c Z: ^ 其中USART2->CR3寄存器的第6 bit用来设置DMA的接收配置,此处比较重要我们设置为USART_CR3_DMAR。 USART2->CR1寄存器中开启帧信息接收完成之后的中断,USART_CR1_IDLEIE,这处可以帮助我们节省CPU的不必要开支,开启此处中断类型,我们只需要在每帧信息接收完成之后,usart才触发中断,我们再解析。其余为正常的usart配置。; Z3 G; o% \) p0 I% {! Q& C* ^. k5 D , O5 {( Z8 ^6 U' B! G% @
配置DMA:' ~0 m5 E* n: I2 a% Q' c" D/ S 5 ^( Z; q* w( M' E% F 首先根据上方的映射表,我们初始化了usart2,而usart2 RX对应的DMA通道为DMA1 channel5,所以我们进行DMA1 ch5通道配置。* T- |# j F& v p4 C8 ] 2 w2 _4 P% q9 S: ^5 | 第一个为DMA1_Channel5->CPAR寄存器,在下表可知,用来设置对应接收数据的外设的地址,而USART的接收数据的寄存器为RDR,所以寄存器配置为DMA1_Channel5->CPAR = (uint32_t)&(USART2->RDR); 8 i! X0 n+ x; z
: u: x' `; }, \: z# X! M/ h% K 设置需要放数据的指定内存位置,根据指导手册可知CMAR为DMA通道用来放置数据的内存地址,所以此处设置为我们定义好的变量的地址。( b7 n) V# E: `% j8 P; [ 9 ~8 R/ X9 [$ i% a& }+ I8 W
: d" C* Z' g' A! f5 _- s 设置单次传送数据量的大小,此处最大可设置为65535byte的数据大小。& N) r5 R- U5 O4 {+ r . K* E# o0 A9 }0 Q
最后开启DMA通道。
* G+ s2 ?( c. d1 q* z
02 等待串口中断,处理数据 8 \) Y, J+ {1 u
此时在debug中,在我们定义好的DMA内存变量,地址在RAM初始完成,后续串口数据接收的时候,DMA会直接将数据置于p_data所对应的内存。% k9 D, H4 l, K: a& w& K1 v ' f! y' t. i- B6 A$ _* U$ G 然后在中断服务函数我们可以将我们数据进行处理,Uart_Channel_isr[1](USART2->RDR);,这个函数为我自己写的处理函数,中断里面函数都是数据复制,所以我直接在中断执行,一般大家会在中断写个标志,在主循环进行解析。但是DMA接收配合USART_ISR_IDLE标志在STM32平台下并不友好,如果主循环用来解析数据的时候,空闲中断还没有产生,本帧数据还尚未接收完成,但是由于内存数据已经在实时写入,DMA1_Channel5->CNDTR已经有所变化,并早于空闲中断产生,所以主循环就不能用DMA1_Channel5->CNDTR所接收数据长度进行解析了。一般建议,如果解析数据只是单纯的挪移,此时候直接在中断处理即可,对主程序并没有大的阻塞。 2 O5 |8 f* B! y
03 恢复DMA,清空CNDTR,等待下次数据到来 处理完数据之后,及时将DMA标志以及CNDTR清空,否则CNDTR一直不清空,会导致下次接收数据的时候,造成通道的占用,数据使用过之后,就清理掉CNDTR,这样保证每次接收数据的通道有足够的位置。# h0 _) {2 l6 m3 t! f& e( _
|
【评分有奖】STM32 AI Sidekick聊天工具上线,快来体验一下吧!
ST TouchGFX 实操系列视频+如何选择正确的帧缓冲区策略
ST TouchGFX 实操系列视频++如何添加图像
ST TouchGFX 实操系列视频+如何进行屏幕转换
ST TouchGFX 实操系列视频+控件的淡入淡出
ST TouchGFX 实操系列视频+移动控件的三种方法
ST TouchGFX 实操系列视频+如何创建用户界面(UI)
ST TouchGFX 实操系列视频+如何安装TouchGFX Designer和STM32Cube软件环境
【经验分享】STM32F1 GPIO工作原理
【经验分享】STM32F0xx_DMA收发USART数据配置详细过程
微信公众号
手机版