你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F0 DMA串口接收数据

[复制链接]
STMCU小助手 发布时间:2021-11-24 13:30
5 w* e! {% w! k( Z* c: D
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg

* J+ C/ x* Y5 \6 K$ B0 I3 K0 ?; z% ~( }% J$ W
DMA,全称Direct Memory Access,即直接存储器访问。DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。
7 H# `' @: F- D# _2 f4 a: `- p1 p8 Q) ]/ v" y- H. S$ ]* Q
主要特点:9 Y. ?6 D( W, P$ F
•DMA上多达7个可独立配置的通道(请求); c" z% h2 g9 U! G) }% F% N; S

( m, d6 Z8 }3 D8 [/ K5 g& _•每个通道都连接到专用的硬件DMA请求,软件触发为
  F8 V$ n& I! D3 y) e$ X6 \# _4 Z) b* l
每个频道也都支持。该配置由软件完成。. J( u2 `* y  S' c% q3 r5 j4 L

9 l0 A6 k" g2 C7 y5 G, W2 N8 T•DMA通道的请求之间的优先级是软件可编程的(43 A! m4 q- _4 B
4 M0 Y$ c8 \6 i- i4 _
级别由非常高,高,中,低)或硬件组成(在相等的情况下)) h' P3 V0 [4 e7 R1 p
5 A2 V$ t$ B6 G! \
(请求1的优先级高于请求2的优先级,依此类推)" t9 z1 N+ C; R2 J. l/ `
2 B3 M- _4 h$ E! H
•独立的源和目标传输大小(字节,半字,字),模拟
* x$ x+ h# k* |4 X7 r
2 o7 R7 x& f' |" n8 v包装和拆箱。源/目标地址必须与数据对齐
6 }$ H4 ~& [0 h. {/ k9 `7 j/ ^, U; t
/ K7 e' f8 ^- W$ s* B. f尺寸。8 T. }( L9 ^3 g9 i( H0 ^# B. g

, s3 k! y/ S6 h( r+ X: C& G•支持循环缓冲区管理3 j* C7 ?  G4 d4 o% Z0 v
# l8 S5 X2 g, b3 w
•3个事件标志(DMA半传输,DMA传输完成和DMA传输错误)
7 i; t  F: {  X& c
+ B% Q) z1 V9 J( v" d. ]% W在每个通道的单个中断请求中进行逻辑或运算
9 R! D/ W2 ?6 `4 L) p7 Q
3 q  [& M; K! G' V2 t•内存到内存的传输
2 [8 G+ Q1 l) B- K. K
; y- s! Z, ^% a. T% V! ^6 ~•外围到内存和内存到外围,以及外围到外围
7 G) v" T" E1 S; m
' g) q6 U: n& B+ @6 `* g转移; I  y' r4 a% i9 [% k! l
( `2 i5 Q- p1 w9 y! F0 f
•访问闪存,SRAM,APB和AHB外设作为源和目标
6 r3 \' n1 b; h) `5 n' H* W$ d/ E/ o- [5 o4 ]3 h# T: r
•可编程的数据传输数量:最多65535
7 ?, k0 g7 ?" S" x1 Q; F' V! O3 ?: S; N) w; D/ ?
DMA通道对应的外设情况(F0系列):
% Z, O* G5 C; j) ]7 _7 u! C) V& E5 I% h* }0 D5 ]
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.png

) b9 J1 C- R  d5 \# {: S7 G; J  V6 R1 U9 s7 `) x" [- n# f& x% {9 @
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg
/ B- F3 [) j; U9 s

, y& w2 Q5 q0 S! B2 b$ Q$ n6 h: C+ Y. z/ ?+ e+ c% T+ ~

* C- o4 J& P9 D; Q, O    很多博文会讲解里面的详细定义,对于每一处寄存器的详细操作指导,所以我就不会去多写了。( x$ ?  k; ]) ~5 E8 t6 r. ~; M

( Q# Q. k; G! y) K8 C* p* Y    我只想表达,DMA是一种可以快速相关外设数据交互的一种方法,我们学习哪里用它,怎么用它,至于细节学习,大家去网上所搜DMA相信息即可。   
# y; Z6 F* O8 ]/ u. F% K3 q- U4 O" P  x
    之前讲过DMA的数据发送,现在补充上DMA的接收数据部分。' D- p6 B5 \' q2 i: R2 A6 K2 M3 S+ E
# a0 _2 u) D. q0 S) V5 j1 Z4 o
  利用DMA接收串口数据的配置,大致分为:1.初始化串口并开启DMAR接收功能,配置DMA的外设到内存的数据接收功能,2.等待串口中断提示,并进行处理数据,3.清空DMA,重新等待数据
0 O# b! J, u! V& A& Z  T4 T; ^" B  T% j
01 配置串口与DMA
: X/ d0 `3 x/ P3 o    其中USART2->CR3寄存器的第6 bit用来设置DMA的接收配置,此处比较重要我们设置为USART_CR3_DMAR。 USART2->CR1寄存器中开启帧信息接收完成之后的中断,USART_CR1_IDLEIE,这处可以帮助我们节省CPU的不必要开支,开启此处中断类型,我们只需要在每帧信息接收完成之后,usart才触发中断,我们再解析。其余为正常的usart配置。
9 V* u% R. b/ w& Q& }2 g1 x4 B5 h/ \% ^6 U, y0 @1 Q9 _
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.png

+ m) L5 B1 U+ c3 W  i; b4 S% b* a) O& Y! B
  1. GPIOD->MODER |=   GPIO_MODER_MODER5_1|  //USART2_TX
    ) M  _$ W6 s- o) K# o
  2.                   GPIO_MODER_MODER6_1;  //USART2_RX  ; S, A- h+ a# [' o( x
  3.   /* set baudrate */
    - K. G# F7 z! ]' `4 _: b) t
  4.   USART2->BRR = USART_Baudrate;//115200
    ! ?! X7 M1 n( X; o+ m
  5.   USART2->CR3 |= USART_CR3_DMAT|USART_CR3_DMAR;//USART_CR3_OVRDIS;// 不需要覆写  `' Q/ [7 B1 }0 t& H1 N
  6. ) ?' m. q6 V3 y5 k! n
  7.   /*enable usart2 and enable tx*/- }/ }- c/ c1 r
  8.   USART2->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | USART_CR1_IDLEIE;
复制代码
3 p$ X3 X* f" i0 Q
配置DMA:3 R0 U+ y' i0 H: R* o9 W7 Y- [7 w

( ^3 n8 ~& t' C  k7 H    首先根据上方的映射表,我们初始化了usart2,而usart2 RX对应的DMA通道为DMA1 channel5,所以我们进行DMA1 ch5通道配置。: q* W6 h) G* f  K) K0 P" v4 V' w

! H3 V; m% e) y* i9 E' M  ?第一个为DMA1_Channel5->CPAR寄存器,在下表可知,用来设置对应接收数据的外设的地址,而USART的接收数据的寄存器为RDR,所以寄存器配置为DMA1_Channel5->CPAR = (uint32_t)&(USART2->RDR);
3 a" t7 N1 ?( e; \
) [. t* T6 a$ c/ D
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg
7 c3 m1 q3 {  Q# s, t
6 S% t, A7 K( W6 y, E$ D
( z5 i$ |; d: x& c$ F2 @
0 @. n6 D3 u( }: O" o9 E% [
    设置需要放数据的指定内存位置,根据指导手册可知CMAR为DMA通道用来放置数据的内存地址,所以此处设置为我们定义好的变量的地址。, p4 u( }5 B, r- N# `3 E9 z4 Q

8 T- |1 l) t* h; @% I+ i
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg
! @1 G  B* v: v( e( o6 \

- E9 Q1 i( ^8 P) p" k1 u* @  `    设置单次传送数据量的大小,此处最大可设置为65535byte的数据大小。
  R! P3 a% @8 C% ^5 `; S  B, z  M7 B" [. o# x- s* `% B
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg

, w) U2 ^$ F$ v1 l) Z7 h+ @9 d& c/ C; |3 V; a
最后开启DMA通道。& B8 v  f9 S7 t# q# o0 P! I

( W; _; k1 y3 o& {  E+ u0 b
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg
- Z8 b* s+ f5 p9 _* F( }

, \, v% V, l) o+ y
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.png
2 m  C$ Z5 a( {% x( l# ?
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg

# B$ |2 G1 T5 e; c8 V( I* K  `8 g+ v& g7 u# e# L
  1. void USART2_DMA_Recive(uint8_t *p_data,uint16_t length)
    5 D# b3 w# f0 H, [" f
  2. {
    $ e3 U6 }* S8 r+ q$ b0 P7 G
  3.   DMA1_Channel5->CPAR = (uint32_t)&(USART2->RDR);          //Peripheral address
    ; y3 [6 y/ Y" E+ @* A0 E
  4.   DMA1_Channel5->CMAR = (uint32_t)p_data;                  //memory address7 S1 E. |; o9 Z, w0 D, s, J
  5.   DMA1_Channel5->CNDTR = length;                            //Set the length
    * U0 H( p- F( S! {% i# A( ]: U- I
  6.   DMA1_Channel5->CCR |= DMA_CCR_MINC | DMA_CCR_EN;
    $ c% P9 W7 ]# _- S  ?9 |, @
  7. }
    $ A0 b/ h9 P  j  o1 V% ~: \
复制代码
( w1 ~) c4 W; B7 M: Z/ e/ d  E
02  等待串口中断,处理数据2 M1 `+ y% b1 N, c( H

; p( E5 T! E! J, v* ]$ t% C, ]
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.png

) I: _) }/ y4 p8 Z. h. M  R+ p+ X4 q7 Z7 V( B$ ?, j: j4 R
    此时在debug中,在我们定义好的DMA内存变量,地址在RAM初始完成,后续串口数据接收的时候,DMA会直接将数据置于p_data所对应的内存。
  D1 K, M7 B" B) {  d; \: D3 Q! |' k! }/ t2 C$ c
    然后在中断服务函数我们可以将我们数据进行处理,Uart_Channel_isr[1](USART2->RDR);,这个函数为我自己写的处理函数,中断里面函数都是数据复制,所以我直接在中断执行,一般大家会在中断写个标志,在主循环进行解析。但是DMA接收配合USART_ISR_IDLE标志在STM32平台下并不友好,如果主循环用来解析数据的时候,空闲中断还没有产生,本帧数据还尚未接收完成,但是由于内存数据已经在实时写入,DMA1_Channel5->CNDTR已经有所变化,并早于空闲中断产生,所以主循环就不能用DMA1_Channel5->CNDTR所接收数据长度进行解析了。一般建议,如果解析数据只是单纯的挪移,此时候直接在中断处理即可,对主程序并没有大的阻塞。$ X5 m& [7 s1 t- [  c) ?( C

! f  L; k( o* P9 Y9 S/ l0 q
  1. void USART2_IRQHandler(void)/ r" K6 D  c- L8 p+ I0 e4 _
  2. {
    * E  U8 X' r* v4 u+ _9 q
  3.   if ((USART2->ISR & USART_ISR_ORE) == USART_ISR_ORE) 5 Z3 D, I& B" [8 f' X" R, K
  4.   {  
    # m* |' e7 q5 ^# `+ c4 b; U" K) i
  5.     USART2->ICR |= USART_ICR_ORECF;! M# ?( Z2 r  m* D) \) T
  6.   }: P9 J: v- _2 ^, n. ^

  7.   m# q4 t4 E! Z! q+ ~# c8 h* ]
  8.   if ((USART2->ISR & USART_ISR_IDLE) == USART_ISR_IDLE)  //The new frame data receive
    ( A. A. i3 T! {$ z1 M6 e
  9.   {, X; n, y. R3 p  a
  10.     USART2->ICR |= USART_ICR_IDLECF;    6 Z* l7 b; K/ _8 q* v, T3 T
  11.     Uart_Channel_isr[1](USART2->RDR);/*读取解析数据*/% w3 [$ }6 \7 m# b/ @
  12.    }  
    0 O# e1 C0 N7 O, O" {
  13. }
复制代码
7 H3 g5 t4 d+ V2 o7 T, ?! Z, ]$ g
03 恢复DMA,清空CNDTR,等待下次数据到来' c! E4 s! r6 b8 @4 L; w
    处理完数据之后,及时将DMA标志以及CNDTR清空,否则CNDTR一直不清空,会导致下次接收数据的时候,造成通道的占用,数据使用过之后,就清理掉CNDTR,这样保证每次接收数据的通道有足够的位置。# A# b; _% z) J
  1. static void Usart2_Dma_Reload(uint16_t length)/*清空数据*/
    1 W9 A- W  n& ~# x$ |- {9 c
  2. {) i" ~( x1 v/ {; x1 t" m; Q
  3.   DMA1_Channel5->CCR &= ~(DMA_CCR_EN);             //disable the dma
    2 R4 m3 ?) f! U" f& O% C3 `
  4.   DMA1_Channel5->CNDTR = length;          //Set the length
    + n5 ?; X2 E' B: p7 M+ v+ ^2 F
  5.   DMA1_Channel5->CCR |= DMA_CCR_EN;                //enable the dma, N: h& T# A$ N, a. t
  6. }$ M" K' V. @( t% f2 ]* w) I) e# m
复制代码
/ M( k+ _& u: ]' R: m2 A$ P- c- e

- p9 W. n+ l2 f+ P: m* f
收藏 1 评论0 发布时间:2021-11-24 13:30

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版