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

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

[复制链接]
STMCU小助手 发布时间:2021-11-24 13:30

$ e+ N2 t( J( B- m
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg

; b. b2 \& a% Z* o
8 m  p5 R8 g7 P& E! D, BDMA,全称Direct Memory Access,即直接存储器访问。DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。6 J$ B7 B! L6 ^2 J+ u+ @+ D& o

! s0 [  ?$ u3 K4 \7 c- v主要特点:) S( {$ |  G* Z6 r: f8 _
•DMA上多达7个可独立配置的通道(请求)
. r* W+ F9 n2 ^* O1 e! g3 Z  S/ R% k3 g
•每个通道都连接到专用的硬件DMA请求,软件触发为
$ O, d( b# _  b' j8 y4 G7 Z7 q' v0 m# c/ f6 B2 J
每个频道也都支持。该配置由软件完成。$ l+ N: B  m/ \8 V

: c0 y" h' R$ k•DMA通道的请求之间的优先级是软件可编程的(4
' ]$ E. a& n7 s3 E$ C5 Q1 A* c  C- g  y9 R! W8 t2 N. w
级别由非常高,高,中,低)或硬件组成(在相等的情况下)
* x) }1 _$ ]1 Q5 [8 i: _/ f3 ^/ B+ K, v' o4 k+ z
(请求1的优先级高于请求2的优先级,依此类推)# J/ ~$ f( S: X! R

! f" V1 X2 K' G•独立的源和目标传输大小(字节,半字,字),模拟* v: v  Z# a3 s; ~2 `* R. ?- Q: o
/ G! z! \. P2 w6 S" I
包装和拆箱。源/目标地址必须与数据对齐
) x+ B& I0 }2 r) Y$ e
$ q/ W' A) j% O* x- f/ }$ \尺寸。+ `! g& J9 _) Y! ^4 h7 `' b  ^
# T/ J7 K1 N8 p8 S
•支持循环缓冲区管理, ?9 s# Z/ W2 r8 t! Y

( r1 i' v# n/ I•3个事件标志(DMA半传输,DMA传输完成和DMA传输错误)) Z. w) n# E" e  O& q1 [5 @! \, D$ {% ^

9 {' H% Y7 \+ U) N9 B在每个通道的单个中断请求中进行逻辑或运算
8 K) o+ w0 Z- n
0 z4 e' P) _' n( R- l; r6 L* ~& p•内存到内存的传输
# K+ N4 F6 v' F( T  B1 W( I4 K/ G; [/ Q- _
•外围到内存和内存到外围,以及外围到外围
3 c; `3 L/ q; V4 \0 {# w
% L0 ]; z, F/ x5 a转移" z; I6 e5 c+ `: X0 z
' G* S( a# {2 V2 T8 C
•访问闪存,SRAM,APB和AHB外设作为源和目标
* A6 _9 U4 A# T0 b
8 a# A$ Q4 q4 r' D8 V•可编程的数据传输数量:最多65535: t3 B4 Y9 G; u8 ]! u
0 e* g5 v) y+ X& W% b* Q% q2 H
DMA通道对应的外设情况(F0系列):
8 K+ W% I" L% ?8 c& h( Q  ~
% J, R8 c" m' [) m- X8 b
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.png

' S$ T4 [4 L# K0 G6 ^# @1 S2 L# y1 n! p8 u
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg

' ]& Z1 z5 j2 _5 z; b
* _/ e4 d0 M8 L/ |' Y* x4 k+ Y* D
% m# T( J: f4 e0 ]1 E
    很多博文会讲解里面的详细定义,对于每一处寄存器的详细操作指导,所以我就不会去多写了。& B! d$ [7 w4 c+ `7 S8 t
' T2 x. |+ Q  |$ g& U# |
    我只想表达,DMA是一种可以快速相关外设数据交互的一种方法,我们学习哪里用它,怎么用它,至于细节学习,大家去网上所搜DMA相信息即可。    ( H3 b" K; l" \& ^6 M
- Q+ {2 M" q% t
    之前讲过DMA的数据发送,现在补充上DMA的接收数据部分。
' V& q3 S6 Z, ]" H1 Q% I0 Z: G5 x$ e" |- {$ {
  利用DMA接收串口数据的配置,大致分为:1.初始化串口并开启DMAR接收功能,配置DMA的外设到内存的数据接收功能,2.等待串口中断提示,并进行处理数据,3.清空DMA,重新等待数据% l& V2 v% T' I) o  }4 B/ P+ H

" H3 Y- t1 E' G2 C( d' x! F01 配置串口与DMA- e% g6 }: {# a7 f+ [
    其中USART2->CR3寄存器的第6 bit用来设置DMA的接收配置,此处比较重要我们设置为USART_CR3_DMAR。 USART2->CR1寄存器中开启帧信息接收完成之后的中断,USART_CR1_IDLEIE,这处可以帮助我们节省CPU的不必要开支,开启此处中断类型,我们只需要在每帧信息接收完成之后,usart才触发中断,我们再解析。其余为正常的usart配置。, X2 u2 W4 w+ {5 ?2 J+ n

$ ?$ n7 _4 \  p8 [  l- R5 u
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.png
  ?& x& Z  ~6 V' L+ c7 j

1 Z" b! R! B% T* l- X
  1. GPIOD->MODER |=   GPIO_MODER_MODER5_1|  //USART2_TX
    * ^4 U2 L+ l5 {5 I9 Q9 Q7 {
  2.                   GPIO_MODER_MODER6_1;  //USART2_RX  
    - E7 F3 h9 J: V% v3 F
  3.   /* set baudrate */* c3 O$ Z" k- t# |% C. o
  4.   USART2->BRR = USART_Baudrate;//115200! K  d9 ^, w# {) j
  5.   USART2->CR3 |= USART_CR3_DMAT|USART_CR3_DMAR;//USART_CR3_OVRDIS;// 不需要覆写
    8 a8 K/ i4 w7 ?" h
  6. . b1 c( L$ b& z, W
  7.   /*enable usart2 and enable tx*/
    : d+ \' N7 f. I$ }% N
  8.   USART2->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | USART_CR1_IDLEIE;
复制代码
# }- E' e6 z3 W# j7 P+ ?
配置DMA:
% ~+ R' x( k7 U3 z
& ]: x- W- {. Z! v9 i% V% S    首先根据上方的映射表,我们初始化了usart2,而usart2 RX对应的DMA通道为DMA1 channel5,所以我们进行DMA1 ch5通道配置。, ?7 M! J7 V$ T6 C3 j/ d6 v

9 {* }; `9 i6 R( ]/ O4 E+ B  E第一个为DMA1_Channel5->CPAR寄存器,在下表可知,用来设置对应接收数据的外设的地址,而USART的接收数据的寄存器为RDR,所以寄存器配置为DMA1_Channel5->CPAR = (uint32_t)&(USART2->RDR);
& [% Z9 m9 P) b/ k* T1 V/ M! N; e; W6 D" }+ y7 n% y8 }/ r
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg
4 O7 u; B0 {4 z+ [* c

5 z9 j9 B! O* Q8 K
% j  d, o1 P& J7 k! `% s0 C9 G& ?. m3 E/ y! S
    设置需要放数据的指定内存位置,根据指导手册可知CMAR为DMA通道用来放置数据的内存地址,所以此处设置为我们定义好的变量的地址。) S# P# y0 o1 b% ^
+ _: K8 Q( D+ H
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg
, l/ g+ r+ X# f% W8 Y: ?  A' [
9 }6 N- X7 O$ r. s* q; ?  U; |
    设置单次传送数据量的大小,此处最大可设置为65535byte的数据大小。4 A$ l+ N' k8 ^! C9 u. w- `
2 W% }( U7 A) q/ }0 I) Z
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg

) T0 b' ^; X/ L
+ T% W/ `: F/ H6 v最后开启DMA通道。2 p/ s- F- T) g, Y  P: v
- P0 J8 ~5 q/ i" Y- q/ d
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg
  z2 F, X; w4 R# w

' B; {1 \# i+ M, A& Y
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.png

% e0 m+ a6 _& u( Y% Z$ R
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.jpg

& q8 Z) O* e) X6 n( `; z/ c; M0 Q! U& _: S( l, X3 D
  1. void USART2_DMA_Recive(uint8_t *p_data,uint16_t length)) }8 x* b9 W  ~" o
  2. {
    - L! K- ]+ s; s. b# g1 m, V7 ], e
  3.   DMA1_Channel5->CPAR = (uint32_t)&(USART2->RDR);          //Peripheral address
    * N0 p" {- v. P/ h
  4.   DMA1_Channel5->CMAR = (uint32_t)p_data;                  //memory address+ j/ l3 [  `- }% y6 M2 h9 a; k
  5.   DMA1_Channel5->CNDTR = length;                            //Set the length
    ' i+ R, `! j" d% @
  6.   DMA1_Channel5->CCR |= DMA_CCR_MINC | DMA_CCR_EN;2 M* N# C- u) o. x% X# F1 `
  7. }( K7 J* v) a/ \/ m- m
复制代码
2 h& ~/ a; V6 Q3 D9 N  a) \# k
02  等待串口中断,处理数据$ h2 l1 Z' ^  z& x, V; B5 z  Y

2 g4 }+ @/ T6 n: j2 M* ]
aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X3BuZy91Y2RZbUdYTGlhOThxM0tXM2pWY0ZMdU9m.png
4 d; _. K. X+ i: _- T4 x

4 I# t1 n; V& L' }- \    此时在debug中,在我们定义好的DMA内存变量,地址在RAM初始完成,后续串口数据接收的时候,DMA会直接将数据置于p_data所对应的内存。
+ {6 K! e& t8 o" y
+ Q; L& E, Q6 A( w    然后在中断服务函数我们可以将我们数据进行处理,Uart_Channel_isr[1](USART2->RDR);,这个函数为我自己写的处理函数,中断里面函数都是数据复制,所以我直接在中断执行,一般大家会在中断写个标志,在主循环进行解析。但是DMA接收配合USART_ISR_IDLE标志在STM32平台下并不友好,如果主循环用来解析数据的时候,空闲中断还没有产生,本帧数据还尚未接收完成,但是由于内存数据已经在实时写入,DMA1_Channel5->CNDTR已经有所变化,并早于空闲中断产生,所以主循环就不能用DMA1_Channel5->CNDTR所接收数据长度进行解析了。一般建议,如果解析数据只是单纯的挪移,此时候直接在中断处理即可,对主程序并没有大的阻塞。+ ~/ i! ^* r3 n2 W

, D+ I" D' r5 Y0 H: _! L- N3 v% y# l
  1. void USART2_IRQHandler(void)
    6 k. L' A! ?( W
  2. {% Q' i5 A* c( L9 Z
  3.   if ((USART2->ISR & USART_ISR_ORE) == USART_ISR_ORE)
    ' U4 ]- X& \" z; H5 W
  4.   {  
    8 ^, N5 E6 j- K+ o! R& D
  5.     USART2->ICR |= USART_ICR_ORECF;' p' q! Q+ R$ r! H3 p
  6.   }
    * f3 {8 s) P+ x( h

  7. # N( y4 \" G! U% H! o8 y# [
  8.   if ((USART2->ISR & USART_ISR_IDLE) == USART_ISR_IDLE)  //The new frame data receive 9 w; |- a# D, {: I0 |
  9.   {
    : C2 M6 S% c& f" n2 @6 L
  10.     USART2->ICR |= USART_ICR_IDLECF;   
    8 E$ M  M! k2 p" R6 z$ n2 |
  11.     Uart_Channel_isr[1](USART2->RDR);/*读取解析数据*/
    . }0 K! R% a: K& Q% t; l
  12.    }  
    & m5 r4 F6 f+ N  _! {8 S, u
  13. }
复制代码

' n# s9 _% U5 E- I03 恢复DMA,清空CNDTR,等待下次数据到来: X: Z- t, F6 A" |5 t6 K
    处理完数据之后,及时将DMA标志以及CNDTR清空,否则CNDTR一直不清空,会导致下次接收数据的时候,造成通道的占用,数据使用过之后,就清理掉CNDTR,这样保证每次接收数据的通道有足够的位置。
7 w& u' l; B8 G; s! j4 F, w, q- ^
  1. static void Usart2_Dma_Reload(uint16_t length)/*清空数据*/
    : }0 L/ f- a! C, {
  2. {1 w/ C; z: Q9 K; w* ]; _2 n% p/ f
  3.   DMA1_Channel5->CCR &= ~(DMA_CCR_EN);             //disable the dma
      p, B( Q1 O+ K3 g- r  A
  4.   DMA1_Channel5->CNDTR = length;          //Set the length
    ) u3 y; C# l4 Z- j
  5.   DMA1_Channel5->CCR |= DMA_CCR_EN;                //enable the dma& P1 u  a4 i: q) ?7 W
  6. }
    / p9 B. m6 l4 O5 v/ E
复制代码

; {- j1 S/ x1 k- P; j3 W+ {8 R' c" V8 ~4 v9 Q: N
收藏 1 评论0 发布时间:2021-11-24 13:30

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版