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

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

[复制链接]
radio2radio 发布时间:2019-3-8 22:08
本帖最后由 radio2radio 于 2019-3-11 14:32 编辑
5 z) [3 x4 u( c* a2 Q4 ^$ e, H+ o, S% e
周末有时间,测试了一下STM32F103的DMA串口收发程序,基于CubeMX的,结果却是令人大失所望。
' B* h9 ]4 u1 `' `0 A; u5 d. F5 L9 Q/ C7 }/ U* x
我在去年,测试了一下【中断模式】的,结果是速度超快。
+ j6 X7 a  s, p& c7 k/ P3 b速度115200bps和1Mbps,双向同时收发100万字符无差错2Mbps,单方向100万字符无差错。* ~! }2 T! U1 }5 g; d9 R6 Q
详情请见:  STM32基于CubeMX的高速串口收发程序(中断模式)
6 q( z% y" w6 D' x# r5 `( W) B
( k. }. O/ _3 e那时就有网友,问我为什么不用DMA模式,我也认为DMA的好处多多,只是没有时间验证一下。. X  ~5 V1 }  j7 x
现在,我得到的结果是,DMA模式用在UART这种低速外设上面,可能性能并不好,不如中断模式的。
5 n# ~. g5 ~0 G% W' }5 k9 W请网友们给看一看,希望我的代码有问题。
, E" [6 B# }; S; J7 Y/ X. w先说我的测试结果吧:" T7 w) S  n3 y
STM32F103C8T6 Bluepill板,MCU时钟72MHz,用CubeMX配置出DMA模式的两个串口收发。
3 k" d1 P+ a" z- u- L3 X添加少量代码,就做成了两个串口互相收发。 与上面说的中断模式的用法一样。
; p0 Q" y: O" K! m/ N5 r结果是,115200波特率,以10ms间隔发送接收40个字符,单方向正常,双方向同时收发就丢失数据。
8 Z5 {4 m' Y8 g: ]6 U5 n6 {) k如果时间间隔放到200ms,双方向同时收发,也能正常了。
: y/ d! {' S' h  R6 y, y- F
, w: Z/ p$ A9 M: d; f3 t下面,看看我用的代码:7 J3 v% a- w) J; z2 D: t+ h( \
CubeMX的配置过程,就不累叙了,附件里面有配置文件。' w, v  U& U3 D5 w' j% L0 t) ~
/ m  o( m6 Y+ }9 ?" u/ T% r
  1. //main.c 添加的代码:
    2 \$ D7 h& d1 j* |5 e: v
  2. 1 H- B( v/ s. f- h( E, r' Y; p" Q
  3. //变量:7 P% P) w) H( _; Z
  4. #define DMA_RX_BUFFER_SIZE            128
    5 [2 t' z/ M) o" e0 ~
  5. uint8_t UART1_Rx_Buffer[DMA_RX_BUFFER_SIZE] = {0};
    7 E2 z  F9 v' ~, O% E7 [7 K2 P
  6. uint8_t UART2_Rx_Buffer[DMA_RX_BUFFER_SIZE] = {0};  |  n! m4 U, h. a6 X& X
  7. 1 z; m1 U$ K. D& F! Q2 z$ g
  8. uint8_t recv_end_flag1 = 0;2 ~5 b/ d! C7 y7 Z- h
  9. uint8_t rx_len1 = 0;4 v7 F, Y7 h" a% X+ g4 Y' m
  10. uint8_t recv_end_flag2 = 0;) P0 ?& y! Y! J  |
  11. uint8_t rx_len2 = 0;
    ! K% i, [1 t6 u6 @7 ~, b6 m. o3 g; G
  12. 1 V3 x$ r. y" p
  13. 。。。
    $ U2 H! N' o9 q

  14. 5 a+ u; @2 x, Q  D& F& u$ B
  15. //初始化
    ' `% }9 e3 [& a  M
  16.   __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
    - P. F4 @' ^' z4 w( S$ O7 U. N
  17.   __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);% Y+ }- O. l: ]9 M: L" S) H
  18.   
    - V7 Q( R8 H. V+ c( t
  19.   HAL_UART_Receive_DMA(&huart1, UART1_Rx_Buffer, DMA_RX_BUFFER_SIZE);. Z6 [/ V1 L; X
  20.   HAL_UART_Receive_DMA(&huart2, UART2_Rx_Buffer, DMA_RX_BUFFER_SIZE);
    ( m' d3 ]' _* [  |/ `

  21. $ d0 w9 y0 r4 X7 M* I
  22.   。。。
    # f) k& ]' q1 i# u5 f
  23.   
    & P5 j' [3 h9 Z  q; x  d" c) d
  24. //main()+ f9 m$ j1 D; a) R- q5 I* p
  25.     if(recv_end_flag1 ==1){     //UART1 Rx, UART2 Tx
      b  v; K; [  o: ^; l4 v
  26. 1 u6 I6 m: Q. N- R+ Z4 m
  27.       HAL_UART_Transmit_DMA(&huart2,UART1_Rx_Buffer,rx_len1);5 F2 q: _4 [6 x/ }8 t5 F+ u  R

  28. 5 u0 Z+ b6 @/ O
  29.       rx_len1=0;
    3 p+ Y- v% k3 r
  30. . d$ V/ E1 j2 O, Q$ o8 f
  31.       recv_end_flag1=0;
    ' u3 @  R& r! O, s5 D' x' G5 [

  32. 5 T6 ]7 N3 U" {
  33.       HAL_UART_Receive_DMA(&huart1,UART1_Rx_Buffer,DMA_RX_BUFFER_SIZE);
    3 t8 `8 o! Q/ v( h' r$ i
  34.     }% e  J' M& }. _6 p: A
  35.    
    1 V5 B+ `" |9 W0 l9 [, b+ F( u
  36.     if(recv_end_flag2 ==1){    //UART2 Rx, UART1 Tx  V: s- a/ x6 V5 E3 N$ ?1 f
  37. ) f: T2 A% @  v# x% L6 ^" W# D- P- r$ h
  38.       HAL_UART_Transmit_DMA(&huart1,UART2_Rx_Buffer,rx_len2);
    9 s5 U& P" Q5 T5 y2 x# q
  39. 3 O& }. z+ d$ d; x; x
  40.       rx_len2=0;: O& @# w* }9 l- j: X+ ~

  41. : B7 @% _8 w% U/ |3 S4 u
  42.       recv_end_flag2=0;
    % x* `7 R) |# ^& \2 x

  43. + N5 {  e- L2 U% W% v
  44.       HAL_UART_Receive_DMA(&huart2,UART2_Rx_Buffer,DMA_RX_BUFFER_SIZE);* N# I2 r& H# f/ p
  45.     }' |' X! ]* R- d0 q# I
  46.     ; p+ `8 O* k- Z- E7 g  T
  47.    
    4 y+ _% z# @3 `! D6 i1 ^
  48.     $ b0 f2 I0 Y% ]
  49.     - \+ E- C8 `4 d0 u; X! W/ X) Q
  50.    
    " {- F' w/ w/ P7 S" A+ I
  51. //stm32f1xx_it.c 中断服务程序里面修改的代码:
    ! h" |& I1 ?- V7 T: i8 ~" H2 `+ K

  52. ' q0 W! X4 w. P0 P9 }
  53. extern uint8_t recv_end_flag1;4 r7 U; p/ j  c/ i7 p3 \
  54. extern uint8_t rx_len1;
    * a: ]! J- G) H; {: J# N
  55. extern uint8_t recv_end_flag2;* f" P' `) F2 H" Z6 e3 ~0 b. b
  56. extern uint8_t rx_len2;. Q( R4 t6 s! W8 g& t8 ]1 F, V
  57. ; h5 ^+ H) X6 T( {6 H2 q1 M) N
  58. #define BUFFER_SIZE 128
    ' O3 F& `( x9 F* c3 ]. B

  59. 4 x" p, ^/ u1 w( X8 v3 F
  60. void USART1_IRQHandler(void)$ s% z2 D6 |: ]
  61. {
    1 ]8 K2 D' y8 Z; n; f
  62.   /* USER CODE BEGIN USART1_IRQn 0 */: n+ b6 Y' A  O# U
  63.     uint32_t tmp_flag = 0;' K& z7 |! X6 Z9 b
  64.     uint32_t temp;+ \. a5 I6 S' N1 G" A; a
  65. , W0 x4 S, o, ~
  66.   /* USER CODE END USART1_IRQn 0 */    ' H( \) Y/ [. \' N
  67.   HAL_UART_IRQHandler(&huart1);' m# Y' U. j% g, v3 n& T
  68.   /* USER CODE BEGIN USART1_IRQn 1 */
      B% w. v+ Z9 @" w
  69. 8 Z6 K& [5 |" n5 p- |5 n' {
  70.   tmp_flag =  __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE);9 B+ ?7 B$ b' J7 }7 M* Z
  71. " h, f. R; B' c, [" T7 F0 Q8 ~
  72.   if((tmp_flag != RESET)){
    7 s. W- z3 T) `6 f- u- L5 x6 p) y

  73. + \* {# f! w8 C: R
  74.     __HAL_UART_CLEAR_IDLEFLAG(&huart1);% m- _! ?! f7 Y5 H9 c9 }8 P4 W

  75. ; x& i- n9 o# E% i& C0 S& R
  76.     HAL_UART_DMAStop(&huart1);( v# `& f6 V% h$ V. Z; j1 i3 }/ X8 d

  77. 3 s8 o/ z; j# G& Z3 E
  78.     temp  = hdma_usart1_rx.Instance->CNDTR;! }1 j4 n# i; H. q
  79. $ _0 b# u5 l2 N& K+ h' `
  80.     rx_len1 =  BUFFER_SIZE - temp;
    ; {* g  H% x% w: Y1 o# P( i
  81. , y$ ~& M% c, R/ p
  82.     recv_end_flag1 = 1;- C6 o/ J* ~' n; d* K0 c% z
  83.   }+ _5 D6 Y# X( R
  84.   /* USER CODE END USART1_IRQn 1 */% z) i7 I& |2 K% S
  85. }* ?: C! F- q. N9 T9 O1 e
  86.   o) t8 Z6 q* ]  i5 {  ?

  87. ) j6 R' F4 K# ]1 b; V
  88. /**) a8 a( C( o- ^1 R* O
  89. * @brief This function handles USART2 global interrupt.5 Z; }: `' O. [% t7 o
  90. */
    $ C9 \) j+ R: }3 x3 @% C0 d+ D% L
  91. void USART2_IRQHandler(void)' R5 n/ Q+ G! w0 `; n0 h3 H
  92. {
    # v8 \& \+ F0 @  a
  93.   /* USER CODE BEGIN USART1_IRQn 0 */
    ! G2 B4 v* D0 H6 z, _2 D
  94.     uint32_t tmp_flag = 0;
    1 W$ J: E% s2 E3 K4 g. |( u
  95.     uint32_t temp;3 j! M  e' R3 h; n3 N

  96. 3 Q4 O2 o% }% g, t' s- [3 Y4 a% Q
  97.   /* USER CODE END USART1_IRQn 0 */   
    ! |4 p: M  D( i1 E; ^' y) Q/ I
  98.   HAL_UART_IRQHandler(&huart2);; _- x9 ~/ `% Q0 o
  99.   /* USER CODE BEGIN USART1_IRQn 1 */2 m+ ~' F9 w  T; B9 \

  100. 0 D% i7 I, p  M7 E; y# g0 q
  101.   tmp_flag =  __HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE);: e8 a4 V9 D% P& w
  102. 6 t+ P4 f8 U. ?2 w0 s
  103.   if((tmp_flag != RESET)){
    4 N- a3 h8 Q& I: v% S- r4 _. H7 [# X
  104. , _/ c) U) N2 F
  105.     __HAL_UART_CLEAR_IDLEFLAG(&huart2);7 c) [$ S. A3 S  g! J

  106. ' o& K4 @7 u* q0 A
  107.     HAL_UART_DMAStop(&huart2);
    5 K  M: k- G' [$ t" i3 ?

  108. " q+ r: k5 c% t& v+ H6 C
  109.     temp  = hdma_usart2_rx.Instance->CNDTR;  b, Q3 i; P0 R" T% u
  110. 4 t) I/ `/ \3 ~+ E- ~) c
  111.     rx_len2 =  BUFFER_SIZE - temp;7 ?- M: d: c2 c- k7 v8 {

  112. 9 w3 W! N9 S0 |) N0 k2 h1 q/ f" s
  113.     recv_end_flag2 = 1;" P5 W/ o* `0 `8 e( e) a6 r
  114.   }2 _+ o( ^9 V" ?5 i6 j) Z; k0 b& x
  115.   /* USER CODE END USART1_IRQn 1 */2 i9 x; o" |. {3 p& G
  116. }; ^# J- G; w& D. L
复制代码
( ^/ b4 M4 E1 b% Z- p- Q: S, L9 ^
' J- {( p" C9 g7 _9 u+ r# ~

; M6 ~6 d( `4 Z3 s4 @' j上面的代码,也是参考了网上网友的帖子。 希望网友指出问题,和给出更好的代码方案。
! h( Z2 T% o; @7 Q也还听说串口DMA有三种方法,我这里用的只是其中之一的“空闲中断”法。
$ n. t6 a3 X: [  o8 X0 O
9 V3 p  A. w5 @: `1 w0 O& G附完整代码:
* Q& |' b" B# H6 N4 k4 U" H! N5 j4 X* l5 Q

STM32F103-USART-DMA.rar

下载

1.66 MB, 下载次数: 356

评分

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

查看全部评分

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

举报

14个回答
radio2radio 回答时间:2019-3-11 14:26:44
今天,有做了一些测试。从使用的角度来看,一楼附件的程序是可以使用的,只要,/ i1 j2 t. M( z" V6 x$ x
1. 数据包长度不超过DMA缓存的长度。2. 发送的间隔不少于200ms。
- s9 v) J* B3 j: a/ g就可以115200双向同时收发无差错。
6 Y' D+ o6 y( ~4 O1 c: w' A$ w$ J; h) q4 w$ ]; m9 G* M
至于单方向收发,1Mbps,2Mbps,都没有问题的,放心使用。
riceglueball 回答时间:2019-3-21 09:50:33
学习了。
wh8 回答时间:2019-3-21 10:47:35
感谢LZ的分享。个人认为DMA的好处还是能释放CPU。一组大量的数据DMA传输,启动后CPU就不用怎么管了,DMA中断也只在一半完成或全部完成时触发;但无DMA时,每个字节收发时其实CPU都需要入中断操作一次,只不过库函数帮你做了而已。
' d) V4 k$ `( d( W. s所以个人认为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
* k0 L( q- a% X9 b- j感谢LZ的分享。个人认为DMA的好处还是能释放CPU。一组大量的数据DMA传输,启动后CPU就不用怎么管了,DMA中 ...
. m$ b7 E  C9 A5 i, P- d' C! U
同意,谢谢。; Z- {' T# f: \8 {* s

1 P! ?7 I( q4 W0 f. u: r  L总之,串口通讯,本身是没有纠错重发功能,速度又很慢的外设。
& Z  a' m+ f& u" k! Z+ r5 ~影响丢数据的因素,也就是那么几种,照顾到了就没有问题。
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
谢谢 分享2 F8 K( s& n* p- n5 f
daxinxin12 回答时间:2020-7-23 13:59:38
学习一下DMA的操作
jesseqiao 回答时间:2021-1-19 17:11:51
谢谢了,好用

所属标签

相似分享

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