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

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

[复制链接]
radio2radio 发布时间:2019-3-8 22:08
本帖最后由 radio2radio 于 2019-3-11 14:32 编辑

周末有时间,测试了一下STM32F103的DMA串口收发程序,基于CubeMX的,结果却是令人大失所望。

我在去年,测试了一下【中断模式】的,结果是速度超快。
速度115200bps和1Mbps,双向同时收发100万字符无差错2Mbps,单方向100万字符无差错。
详情请见:  STM32基于CubeMX的高速串口收发程序(中断模式)

那时就有网友,问我为什么不用DMA模式,我也认为DMA的好处多多,只是没有时间验证一下。
现在,我得到的结果是,DMA模式用在UART这种低速外设上面,可能性能并不好,不如中断模式的。
请网友们给看一看,希望我的代码有问题。
先说我的测试结果吧:
STM32F103C8T6 Bluepill板,MCU时钟72MHz,用CubeMX配置出DMA模式的两个串口收发。
添加少量代码,就做成了两个串口互相收发。 与上面说的中断模式的用法一样。
结果是,115200波特率,以10ms间隔发送接收40个字符,单方向正常,双方向同时收发就丢失数据。
如果时间间隔放到200ms,双方向同时收发,也能正常了。

下面,看看我用的代码:
CubeMX的配置过程,就不累叙了,附件里面有配置文件。

  1. //main.c 添加的代码:

  2. //变量:
  3. #define DMA_RX_BUFFER_SIZE            128
  4. uint8_t UART1_Rx_Buffer[DMA_RX_BUFFER_SIZE] = {0};
  5. uint8_t UART2_Rx_Buffer[DMA_RX_BUFFER_SIZE] = {0};

  6. uint8_t recv_end_flag1 = 0;
  7. uint8_t rx_len1 = 0;
  8. uint8_t recv_end_flag2 = 0;
  9. uint8_t rx_len2 = 0;

  10. 。。。

  11. //初始化
  12.   __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
  13.   __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
  14.   
  15.   HAL_UART_Receive_DMA(&huart1, UART1_Rx_Buffer, DMA_RX_BUFFER_SIZE);
  16.   HAL_UART_Receive_DMA(&huart2, UART2_Rx_Buffer, DMA_RX_BUFFER_SIZE);

  17.   。。。
  18.   
  19. //main()
  20.     if(recv_end_flag1 ==1){     //UART1 Rx, UART2 Tx

  21.       HAL_UART_Transmit_DMA(&huart2,UART1_Rx_Buffer,rx_len1);

  22.       rx_len1=0;

  23.       recv_end_flag1=0;

  24.       HAL_UART_Receive_DMA(&huart1,UART1_Rx_Buffer,DMA_RX_BUFFER_SIZE);
  25.     }
  26.    
  27.     if(recv_end_flag2 ==1){    //UART2 Rx, UART1 Tx

  28.       HAL_UART_Transmit_DMA(&huart1,UART2_Rx_Buffer,rx_len2);

  29.       rx_len2=0;

  30.       recv_end_flag2=0;

  31.       HAL_UART_Receive_DMA(&huart2,UART2_Rx_Buffer,DMA_RX_BUFFER_SIZE);
  32.     }
  33.    
  34.    
  35.    
  36.    
  37.    
  38. //stm32f1xx_it.c 中断服务程序里面修改的代码:

  39. extern uint8_t recv_end_flag1;
  40. extern uint8_t rx_len1;
  41. extern uint8_t recv_end_flag2;
  42. extern uint8_t rx_len2;

  43. #define BUFFER_SIZE 128

  44. void USART1_IRQHandler(void)
  45. {
  46.   /* USER CODE BEGIN USART1_IRQn 0 */
  47.     uint32_t tmp_flag = 0;
  48.     uint32_t temp;

  49.   /* USER CODE END USART1_IRQn 0 */   
  50.   HAL_UART_IRQHandler(&huart1);
  51.   /* USER CODE BEGIN USART1_IRQn 1 */

  52.   tmp_flag =  __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE);

  53.   if((tmp_flag != RESET)){

  54.     __HAL_UART_CLEAR_IDLEFLAG(&huart1);

  55.     HAL_UART_DMAStop(&huart1);

  56.     temp  = hdma_usart1_rx.Instance->CNDTR;

  57.     rx_len1 =  BUFFER_SIZE - temp;

  58.     recv_end_flag1 = 1;
  59.   }
  60.   /* USER CODE END USART1_IRQn 1 */
  61. }


  62. /**
  63. * @brief This function handles USART2 global interrupt.
  64. */
  65. void USART2_IRQHandler(void)
  66. {
  67.   /* USER CODE BEGIN USART1_IRQn 0 */
  68.     uint32_t tmp_flag = 0;
  69.     uint32_t temp;

  70.   /* USER CODE END USART1_IRQn 0 */   
  71.   HAL_UART_IRQHandler(&huart2);
  72.   /* USER CODE BEGIN USART1_IRQn 1 */

  73.   tmp_flag =  __HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE);

  74.   if((tmp_flag != RESET)){

  75.     __HAL_UART_CLEAR_IDLEFLAG(&huart2);

  76.     HAL_UART_DMAStop(&huart2);

  77.     temp  = hdma_usart2_rx.Instance->CNDTR;

  78.     rx_len2 =  BUFFER_SIZE - temp;

  79.     recv_end_flag2 = 1;
  80.   }
  81.   /* USER CODE END USART1_IRQn 1 */
  82. }
复制代码



上面的代码,也是参考了网上网友的帖子。 希望网友指出问题,和给出更好的代码方案。
也还听说串口DMA有三种方法,我这里用的只是其中之一的“空闲中断”法。

附完整代码:

STM32F103-USART-DMA.rar

下载

1.66 MB, 下载次数: 363

评分

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

查看全部评分

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

举报

14个回答
radio2radio 回答时间:2019-3-11 14:26:44
今天,有做了一些测试。从使用的角度来看,一楼附件的程序是可以使用的,只要,
1. 数据包长度不超过DMA缓存的长度。2. 发送的间隔不少于200ms。
就可以115200双向同时收发无差错。

至于单方向收发,1Mbps,2Mbps,都没有问题的,放心使用。
riceglueball 回答时间:2019-3-21 09:50:33
学习了。
wh8 回答时间:2019-3-21 10:47:35
感谢LZ的分享。个人认为DMA的好处还是能释放CPU。一组大量的数据DMA传输,启动后CPU就不用怎么管了,DMA中断也只在一半完成或全部完成时触发;但无DMA时,每个字节收发时其实CPU都需要入中断操作一次,只不过库函数帮你做了而已。
所以个人认为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
感谢LZ的分享。个人认为DMA的好处还是能释放CPU。一组大量的数据DMA传输,启动后CPU就不用怎么管了,DMA中 ...

同意,谢谢。

总之,串口通讯,本身是没有纠错重发功能,速度又很慢的外设。
影响丢数据的因素,也就是那么几种,照顾到了就没有问题。
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
谢谢 分享
daxinxin12 回答时间:2020-7-23 13:59:38
学习一下DMA的操作
jesseqiao 回答时间:2021-1-19 17:11:51
谢谢了,好用

所属标签

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