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

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, 下载次数: 270

评分

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

查看全部评分

收藏 7 评论13 发布时间:2019-3-8 22:08

举报

13个回答
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中 ...

同意,谢谢。

总之,串口通讯,本身是没有纠错重发功能,速度又很慢的外设。
影响丢数据的因素,也就是那么几种,照顾到了就没有问题。
Kevin201707 回答时间: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
学习了                                   
12下一页

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

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