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

STM32基于CubeMX的高速串口收发程序(DMA模式)  

[复制链接]
radio2radio 发布时间:2019-3-8 22:08
本帖最后由 radio2radio 于 2019-3-11 14:32 编辑 3 R$ V( z% B" q5 y0 D
- G4 L; c- [1 }8 y8 Q: x
周末有时间,测试了一下STM32F103的DMA串口收发程序,基于CubeMX的,结果却是令人大失所望。2 H! d  e, p, o) e2 I5 o' B$ [4 w
9 E3 d6 E$ v- {" f1 K  u: g' k
我在去年,测试了一下【中断模式】的,结果是速度超快。
- @8 }( p) o* \速度115200bps和1Mbps,双向同时收发100万字符无差错2Mbps,单方向100万字符无差错。' V' x" Z, {9 B6 ^9 F" f0 Q
详情请见:  STM32基于CubeMX的高速串口收发程序(中断模式)/ E( _  h2 Y( J
& R$ g: R; G+ |6 e" a
那时就有网友,问我为什么不用DMA模式,我也认为DMA的好处多多,只是没有时间验证一下。# @/ L1 n3 S0 P9 R. Z
现在,我得到的结果是,DMA模式用在UART这种低速外设上面,可能性能并不好,不如中断模式的。
3 ]  R6 d& `+ {- }请网友们给看一看,希望我的代码有问题。4 ^/ W. m5 @4 p
先说我的测试结果吧:( n, e% s: T( g" e/ y
STM32F103C8T6 Bluepill板,MCU时钟72MHz,用CubeMX配置出DMA模式的两个串口收发。
8 g" D0 [% P; L$ ?7 m0 G+ N- J+ T添加少量代码,就做成了两个串口互相收发。 与上面说的中断模式的用法一样。
7 U6 J9 E' `9 @! z3 [8 k  w结果是,115200波特率,以10ms间隔发送接收40个字符,单方向正常,双方向同时收发就丢失数据。3 l8 _- b3 }/ S, B
如果时间间隔放到200ms,双方向同时收发,也能正常了。
5 e! `) X& ?7 r6 [0 ?
: G& X" B+ I  N$ I& T下面,看看我用的代码:: }) S' Y- f# y$ x& w/ X
CubeMX的配置过程,就不累叙了,附件里面有配置文件。
$ O. r4 S7 k7 H7 G2 y' n# x! }0 u! Y, l7 ]
  1. //main.c 添加的代码:
    ) C" X% J) b5 J& x3 e/ B& K4 c8 L
  2. 1 m7 Q$ K# V6 `* \
  3. //变量:4 u0 I2 U( u7 E7 K3 v+ v
  4. #define DMA_RX_BUFFER_SIZE            128
    ! C8 J5 x) N+ H
  5. uint8_t UART1_Rx_Buffer[DMA_RX_BUFFER_SIZE] = {0};
    6 S" T  ~/ \9 W
  6. uint8_t UART2_Rx_Buffer[DMA_RX_BUFFER_SIZE] = {0};
    9 \- Y8 I* A* T" `$ N
  7. . K5 E& l. b5 q* w) \5 [9 _  {
  8. uint8_t recv_end_flag1 = 0;
    2 X$ {! t  _) t4 F2 Z5 i
  9. uint8_t rx_len1 = 0;
    ; g) ?  G$ B0 p6 E
  10. uint8_t recv_end_flag2 = 0;* y; g, z. a$ C  M/ L+ S& E! N
  11. uint8_t rx_len2 = 0;
    5 s) R) n% B2 U" K

  12. 1 ^0 L1 h+ J( K. p
  13. 。。。
    ' ]9 p+ e* P6 f

  14. % b) x7 Q# y$ i7 A/ D% _! {( i. d
  15. //初始化
    2 o: X$ \; J2 C) W5 d2 H" b2 N
  16.   __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);* T; u; C8 n  S
  17.   __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);; A) _5 ^; l1 v" I
  18.   , s; D- y# h% ^: j, C  z
  19.   HAL_UART_Receive_DMA(&huart1, UART1_Rx_Buffer, DMA_RX_BUFFER_SIZE);
    7 y3 G( w% Y* \
  20.   HAL_UART_Receive_DMA(&huart2, UART2_Rx_Buffer, DMA_RX_BUFFER_SIZE);7 _: e1 _- a4 k

  21. , A9 q5 g! I0 V6 w& m. }
  22.   。。。
    " G9 }; z1 Q' l4 ]2 ~
  23.   
    5 L9 q% q" j8 U! [, @
  24. //main()" v" \4 w+ l0 Y% j3 ~- u2 a- B
  25.     if(recv_end_flag1 ==1){     //UART1 Rx, UART2 Tx
    : q% ^5 k" F# u" |. Y

  26. . W+ Y- G  f" J2 Y' y, S" j
  27.       HAL_UART_Transmit_DMA(&huart2,UART1_Rx_Buffer,rx_len1);
    * ^) [5 t0 ]" q

  28. & y3 S; h4 B" P1 K+ H1 [5 s
  29.       rx_len1=0;
    + }0 K3 O# Y8 x6 L

  30. 4 [) Y5 ~: u# d3 |% f) Q
  31.       recv_end_flag1=0;7 j7 P3 v* _% `& p0 s. _

  32. 9 N6 J6 X6 B- W; q/ Q, y
  33.       HAL_UART_Receive_DMA(&huart1,UART1_Rx_Buffer,DMA_RX_BUFFER_SIZE);# y2 p9 _, Z. m2 A4 s
  34.     }
    3 T' h/ p& r; {) h2 z. I
  35.     , t8 m( ?* \8 J/ f5 v
  36.     if(recv_end_flag2 ==1){    //UART2 Rx, UART1 Tx# `; _: z% L* q2 Z' c9 r4 Y

  37. . O* q: I( {/ f4 h* B8 g6 i8 i
  38.       HAL_UART_Transmit_DMA(&huart1,UART2_Rx_Buffer,rx_len2);
    - E2 L7 r, V6 E- ]" z

  39.   u- e9 Z0 W* i2 b" D2 C
  40.       rx_len2=0;' ?0 U1 p* O! h; j( \" K5 g

  41. " E' F1 q4 w2 \7 I# j: u
  42.       recv_end_flag2=0;5 A* B- |. r6 K; ~7 y

  43. & V: T: C0 B. r3 t! e- `
  44.       HAL_UART_Receive_DMA(&huart2,UART2_Rx_Buffer,DMA_RX_BUFFER_SIZE);
    & n' j: F3 p+ Z
  45.     }
    ( i% n% c: u: t9 Z
  46.     - j; `  \4 e) f  [, ~) @
  47.     & m+ h9 X1 J7 w# S& K1 f
  48.    
    1 o7 K- D; V8 u7 q2 m4 c, C/ _
  49.     4 H) F" |% X$ X
  50.     . d, L8 |' J' k: Q: @, Z4 o
  51. //stm32f1xx_it.c 中断服务程序里面修改的代码:! t& ~& [$ K2 ~  j: a* R( u2 {3 M; X
  52. / z* K6 {7 d- f' r+ Q
  53. extern uint8_t recv_end_flag1;2 `3 C9 I1 K  o( L" P: k& f8 Z
  54. extern uint8_t rx_len1;
    " z4 }4 S% ^- i- C7 s3 E
  55. extern uint8_t recv_end_flag2;
    : U8 L+ O3 Y2 N# T! [  D
  56. extern uint8_t rx_len2;" T' ]& v8 I0 `  E; w
  57. % u9 C& t7 H4 h
  58. #define BUFFER_SIZE 128
    , e" D. k2 M5 s* f0 a. M0 e. j8 n# ?
  59. + [: G7 f) ^0 Y* f
  60. void USART1_IRQHandler(void)$ d2 Y5 h( m' ~$ v) Y6 H5 e3 x
  61. {
    # i+ `( ^% Q% o" e# D" N3 {% Y
  62.   /* USER CODE BEGIN USART1_IRQn 0 */
    8 e; n- Q7 h) _/ T* I" G7 O
  63.     uint32_t tmp_flag = 0;, A7 g# z& W6 f& [
  64.     uint32_t temp;" n5 w, u& t- I8 m# C1 [

  65. 3 o, X/ E, L6 ]7 E" N( H
  66.   /* USER CODE END USART1_IRQn 0 */    2 _+ p' b9 V8 Z" y/ g# V& L1 p% T
  67.   HAL_UART_IRQHandler(&huart1);
    $ G7 ^2 k* \  c; k- ~
  68.   /* USER CODE BEGIN USART1_IRQn 1 */
    / P9 K! G: ~% X. A! B
  69. 1 Y; P4 U9 B( u1 L
  70.   tmp_flag =  __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE);
      \7 w! g# m( v

  71. ( j# q5 h7 z0 r" e' `6 Y
  72.   if((tmp_flag != RESET)){9 \; n- @5 d+ L, N9 O

  73. 4 v6 n2 U' h9 U$ C9 u: Y
  74.     __HAL_UART_CLEAR_IDLEFLAG(&huart1);. p6 y: B6 v5 h5 \
  75. 6 J) W( H8 E8 S6 h" K$ ?6 R$ m
  76.     HAL_UART_DMAStop(&huart1);$ ]3 W( R% x# H+ P

  77. " O$ U4 t% O4 r& P
  78.     temp  = hdma_usart1_rx.Instance->CNDTR;" M6 A, w$ r! \, Q

  79. 2 c: G' g7 A% K$ e/ i! G
  80.     rx_len1 =  BUFFER_SIZE - temp;0 w0 n/ y$ m2 u- z( U4 u7 M2 e

  81. / \  F% w/ N1 D" u/ v
  82.     recv_end_flag1 = 1;
    " v4 |* F' A% x* M5 B) s
  83.   }5 b% B  ?! y. C& g( t* b
  84.   /* USER CODE END USART1_IRQn 1 */9 T" j5 `- H1 f. K8 ^' P% Q
  85. }3 I' f4 g: t/ X: y( r
  86. : w" B* q- P& q: c8 B; L* T" }( c

  87. / q8 z: i* k8 u) p& d% q" V
  88. /**
      O8 T3 ]& f. M2 F! N( k5 n' G
  89. * @brief This function handles USART2 global interrupt.2 k$ K7 b% Q5 W  t2 j
  90. */& @* n2 _' Z3 N3 w
  91. void USART2_IRQHandler(void)
    % {9 I! E# ?8 |' E% p( B
  92. {
    ) ?6 i# h# l! F3 L$ [
  93.   /* USER CODE BEGIN USART1_IRQn 0 */
    7 x4 e5 O! o2 U6 ~
  94.     uint32_t tmp_flag = 0;
    ; l% ?: |. ^) [6 ~7 p' L  j7 Q
  95.     uint32_t temp;
    0 Y: x- @! w9 C# V
  96. + |, y5 `/ |5 _4 ]) ]# A
  97.   /* USER CODE END USART1_IRQn 0 */    , h2 J, |2 s8 a5 W, d
  98.   HAL_UART_IRQHandler(&huart2);" O* P! \6 V5 Q) C# J6 Q$ g5 d
  99.   /* USER CODE BEGIN USART1_IRQn 1 */
      ]8 k8 K/ b' Q* E  I, F
  100.   X% Z2 x1 A) D( H4 a2 c& ?$ ]. O
  101.   tmp_flag =  __HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE);2 }6 ?) Q1 ~' I- X- x+ b. H

  102. ' R) d7 U# v8 @" y. C$ c' {: O
  103.   if((tmp_flag != RESET)){2 u4 V) p; g. F+ d

  104. * @& ^' X2 B. S
  105.     __HAL_UART_CLEAR_IDLEFLAG(&huart2);
    " Z- J3 n0 Q7 c

  106. & v; M6 ~$ |7 P7 Z
  107.     HAL_UART_DMAStop(&huart2);3 I+ {% H3 b$ h4 x" P8 [  A

  108. # T1 ?! \4 ^) Q1 a
  109.     temp  = hdma_usart2_rx.Instance->CNDTR;
    ! y0 h3 J2 Q( s8 L
  110. 2 s4 L: c7 e: Z  v% _8 F! D4 F" w/ N
  111.     rx_len2 =  BUFFER_SIZE - temp;
    ; G* R9 E/ j. w% l: ]# Z! Z

  112. ; Y1 O' D7 s/ a
  113.     recv_end_flag2 = 1;+ N- a+ P9 }' j& f& ~- [- r0 ]
  114.   }
    ; [* M3 K9 ~) O: {6 s$ H
  115.   /* USER CODE END USART1_IRQn 1 */
      E. L7 O" t) p% w; e5 ]
  116. }- n! b- o5 K; ~% K, L
复制代码
" t0 t& G3 V4 \5 I0 O

& a; ]9 d/ f1 J7 |2 C; y9 C/ d) ^: ~
上面的代码,也是参考了网上网友的帖子。 希望网友指出问题,和给出更好的代码方案。1 W- r, _8 _8 D1 @4 i' N
也还听说串口DMA有三种方法,我这里用的只是其中之一的“空闲中断”法。: g" ?# P# H% x) b: |0 u

7 F' P7 v+ v6 k7 H附完整代码:
) r7 H9 f1 `' t8 }" I2 h) N+ C
6 j2 @. \3 v. i/ t, w

STM32F103-USART-DMA.rar

下载

1.66 MB, 下载次数: 355

评分

参与人数 1 ST金币 +1 收起 理由
生命在于折腾! + 1

查看全部评分

1 收藏 8 评论14 发布时间:2019-3-8 22:08

举报

14个回答
radio2radio 回答时间:2019-3-11 14:26:44
今天,有做了一些测试。从使用的角度来看,一楼附件的程序是可以使用的,只要,7 A9 W' A; R2 H1 m9 Y
1. 数据包长度不超过DMA缓存的长度。2. 发送的间隔不少于200ms。$ J1 t2 I* H" A- Q6 o
就可以115200双向同时收发无差错。
3 o8 ^6 v5 d% P" j7 H; k) S: F0 m% Y; v$ {$ H' p
至于单方向收发,1Mbps,2Mbps,都没有问题的,放心使用。
riceglueball 回答时间:2019-3-21 09:50:33
学习了。
wh8 回答时间:2019-3-21 10:47:35
感谢LZ的分享。个人认为DMA的好处还是能释放CPU。一组大量的数据DMA传输,启动后CPU就不用怎么管了,DMA中断也只在一半完成或全部完成时触发;但无DMA时,每个字节收发时其实CPU都需要入中断操作一次,只不过库函数帮你做了而已。
( Q" t' n: w5 h7 Q! s# A8 u所以个人认为LZ的测试方式其实问题在于,用中断CPU可以收一个马上发一个,虽然两边都CPU占满了但响应肯定快;但DMA是收完全部时再全部返回,那CPU虽然很闲,但响应就肯定慢。这样测试时DMA对CPU占用少的优势就测不出来。
适苦欲死 回答时间:2019-3-21 11:50:19
学习中,之前没有用到DMA,用的好像就是空闲中断
radio2radio 回答时间:2019-3-21 16:36:32
wh8 发表于 2019-3-21 10:47) s/ u' P% V. |# d: f
感谢LZ的分享。个人认为DMA的好处还是能释放CPU。一组大量的数据DMA传输,启动后CPU就不用怎么管了,DMA中 ...
# y* K- u) f7 e- E, `" h: F
同意,谢谢。! C0 J! H" e" K. U( s* V

, J3 W: I% _6 U- q5 ?总之,串口通讯,本身是没有纠错重发功能,速度又很慢的外设。
) v. `, ]5 b" J$ |  U影响丢数据的因素,也就是那么几种,照顾到了就没有问题。
Kevin_G 回答时间:2019-3-25 12:52:36
收藏
eugenia2019 回答时间:2019-5-7 19:06:08
学习了
polarbear7 回答时间:2019-11-7 17:18:25
你这个怎么测试的啊,一点串口一点反应都没有的?
适苦欲死 回答时间:2019-12-23 17:19:02
学习了                                   
happyavr128 回答时间:2020-2-6 15:10:14
学习了
owenouyihui 回答时间:2020-5-9 12:32:41
有测试作为数据支持,不错
生命在于折腾! 回答时间:2020-7-21 18:04:16
谢谢 分享) Y. G0 m! _$ g. L; `
daxinxin12 回答时间:2020-7-23 13:59:38
学习一下DMA的操作
jesseqiao 回答时间:2021-1-19 17:11:51
谢谢了,好用

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版