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

奇怪的STM32L051串口接收卡死

[复制链接]
hjl2832 提问时间:2020-6-18 17:40 /
如题:实验现象是用CUBE配置好的代码,HAL库,修改中断函数,增加空闲中断处理不定长数据接收,在使用串口助手进行调试时发现,连续快速点击发送按钮,串口会卡死,为了确认卡死的地方,在所有异常中断中都加了LED指示,最后发现在接收数据时LED指示常亮,证明是卡死在数据接收中。为了验证,在串口助手中设置1MS自动发送,程序不会卡死。但只要在单次发送模式用手连续快速点击发送,100%卡死。怀疑串口助手有问题,换助手后一样。在出现卡死后,程序也不知道跑在哪里了,按复位能恢复;但在用STLINK进入DEBUG模式下跑代码测试,不会出现卡死现象。
中断部分处理代码如下:
  1. void LPUART1_IRQHandler(void)
  2. {
  3. //        uint8_t  RCVBUF;
  4.   /* USER CODE BEGIN LPUART1_IRQn 0 */
  5.   /* USER CODE END LPUART1_IRQn 0 */
  6. //  HAL_UART_IRQHandler(&hlpuart1);
  7.   /* USER CODE BEGIN LPUART1_IRQn 1 */
  8.   HAL_GPIO_WritePin(led1_GPIO_Port,led1_Pin,GPIO_PIN_SET);       
  9. //        HAL_UART_Receive_IT(&hlpuart1,&RCVBUF,1);
  10. //        LPUart1_RX_BUF[LPUart1_REC_Cnt++] = RCVBUF;
  11. //        if(LPUart1_REC_Cnt > LPUart1_BUF_SIZE)
  12. //                                        LPUart1_REC_Cnt =0;       
  13.        
  14. if(__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_RXNE) != RESET)  
  15.     {
  16.                         __HAL_UART_CLEAR_FLAG(&hlpuart1, UART_FLAG_ORE | UART_FLAG_NE | UART_FLAG_PE | UART_FLAG_FE);
  17.       __HAL_UART_CLEAR_FLAG(&hlpuart1, UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_PEF | UART_CLEAR_FEF);
  18.                         if(LPUart1_End_flage == 0)
  19.                         {
  20.                           LPUart1_RX_BUF[LPUart1_REC_Cnt] = LPUART1->ISR;   
  21.         LPUart1_RX_BUF[LPUart1_REC_Cnt] = LPUART1->RDR;   
  22.         LPUart1_REC_Cnt++;
  23.                                 if(LPUart1_REC_Cnt > LPUart1_BUF_SIZE)
  24.                                         LPUart1_REC_Cnt =0;       
  25.                         }
  26.   }
  27. else if(__HAL_UART_GET_FLAG(&hlpuart1,UART_FLAG_IDLE) == SET)
  28.     {
  29.                          __HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);
  30.                         __HAL_UART_CLEAR_FLAG(&hlpuart1, UART_FLAG_ORE | UART_FLAG_NE | UART_FLAG_PE | UART_FLAG_FE);
  31.                printf("UART IT For IDEL \r\n");
  32.         LPUart1_End_flage = 1;
  33.         LPUart1_REC_SIZE = LPUart1_REC_Cnt;
  34.         LPUart1_REC_Cnt = 0;
  35.    }
  36. HAL_GPIO_WritePin(led1_GPIO_Port,led1_Pin,GPIO_PIN_RESET);       
  37.   /* USER CODE END LPUART1_IRQn 1 */
  38. }
复制代码
工程原文件如下,大家有兴趣可以测试验证。


stm32l051_stop.rar (5.19 MB, 下载次数: 11)
收藏 评论8 发布时间:2020-6-18 17:40

举报

8个回答
hjl2832 回答时间:2020-6-18 17:41:39
我在测试时串口助手发送的是128个字节
新建位图图像.jpg

评分

参与人数 1蝴蝶豆 +2 收起 理由
STMCU + 2

查看全部评分

wenyangzeng 回答时间:2020-6-18 20:52:07
IDLE中断需要:
读取SR寄存器的ISR和RDR方可清零状态寄存器,
temp = huart1.Instance->ISR;                 
temp = huart1.Instance->RDR;
废鱼 回答时间:2020-6-18 21:33:59
怀疑时产生了串口接收溢出,看一下串口溢出标志位,当接收指定数据完成以后,需要继续开启串口接收中断。

评分

参与人数 1蝴蝶豆 +3 收起 理由
STMCU + 3

查看全部评分

yklstudent 回答时间:2020-6-19 08:38:01
中断回调函数内就别用打印函数了
hjl2832 回答时间:2020-6-19 10:41:05
yklstudent-1794 发表于 2020-6-19 08:38
中断回调函数内就别用打印函数了

打印函数是为了确认问题位置才加上去的,实际应用当然没有,否则,打印这个的意义在哪里?包括灯的控制也是为了找问题。
mmuuss586 回答时间:2020-6-19 11:34:07
hjl2832 回答时间:2020-6-19 11:47:38
结贴,ST的M0有点扯蛋,其它厂家的芯片都是通过向中断标志写1来清的,它家的数据手册也是这样写的: 新建位图图像.jpg
而且,它的HAL库也是这样执行的:
  1. #define __HAL_UART_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->ICR = (__FLAG__))
复制代码
经过分析卡死现象,认为是接收中断中的开启的条件判断:
  1. if(LPUart1_End_flage == 0)
  2.                         {
  3.                            *******
  4. ********
  5.                         }
复制代码
影响了数据的接收,从而出现卡死,即溢出错误。因为点击过快时,主程序未能及时处理数据的话,有可能出现LPUart1_End_flage结束标志未及时复位为0,这样接收就会出现溢出错误(当然,这里的前提就是因为ST的软件清中断功能无效,毕竟我在中断中第一个事情就是软件清中断__HAL_UART_CLEAR_FLAG),但是实际上,软件清中断标志根本没用。
所以修改代码如下,将读ISR和读RDR放到条件上面,屏蔽软件清中断语句,再进行测试验证:
  1. void LPUART1_IRQHandler(void)
  2. {
  3. //        uint8_t  RCVBUF;
  4.   /* USER CODE BEGIN LPUART1_IRQn 0 */
  5.   /* USER CODE END LPUART1_IRQn 0 */
  6. //  HAL_UART_IRQHandler(&hlpuart1);
  7.   /* USER CODE BEGIN LPUART1_IRQn 1 */
  8.   HAL_GPIO_WritePin(led1_GPIO_Port,led1_Pin,GPIO_PIN_SET);       
  9. //        HAL_UART_Receive_IT(&hlpuart1,&RCVBUF,1);
  10. //        LPUart1_RX_BUF[LPUart1_REC_Cnt++] = RCVBUF;
  11. //        if(LPUart1_REC_Cnt > LPUart1_BUF_SIZE)
  12. //                                        LPUart1_REC_Cnt =0;       
  13.        
  14. if(__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_RXNE) != RESET)  
  15.     {
  16. //                        __HAL_UART_CLEAR_FLAG(&hlpuart1, UART_FLAG_ORE | UART_FLAG_NE | UART_FLAG_PE | UART_FLAG_FE);
  17. //      __HAL_UART_CLEAR_FLAG(&hlpuart1, UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_PEF | UART_CLEAR_FEF);
  18.                          LPUart1_RX_BUF[LPUart1_REC_Cnt] = LPUART1->ISR;   
  19.        LPUart1_RX_BUF[LPUart1_REC_Cnt] = LPUART1->RDR;  
  20.                         if(LPUart1_End_flage == 0)
  21.                         {
  22.                           
  23.         LPUart1_REC_Cnt++;
  24.                                 if(LPUart1_REC_Cnt >LPUart1_BUF_SIZE)
  25.                                         LPUart1_REC_Cnt =0;       
  26.                         }
  27.   }
  28. else if(__HAL_UART_GET_FLAG(&hlpuart1,UART_FLAG_IDLE) != RESET)
  29.     {
  30.                          __HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);
  31. //                        __HAL_UART_CLEAR_FLAG(&hlpuart1, UART_FLAG_ORE | UART_FLAG_NE | UART_FLAG_PE | UART_FLAG_FE);
  32.        printf("UART IT For IDEL \r\n");
  33.                                                    
  34.         LPUart1_End_flage = 1;
  35.         LPUart1_REC_SIZE = LPUart1_REC_Cnt;
  36.         LPUart1_REC_Cnt = 0;
  37.    }
  38.        
  39. HAL_GPIO_WritePin(led1_GPIO_Port,led1_Pin,GPIO_PIN_RESET);       
  40.   /* USER CODE END LPUART1_IRQn 1 */
  41. }
复制代码

神奇的现象出现了,接收不会卡死了。但因为少了包条件判断,回传数据丢包很严重,空闲中断乱来了? 新建位图图像.jpg
从这个事件看,ST的M0,软件清串口中断完全是没用的。




hjl2832 回答时间:2020-6-19 11:56:13
hjl2832 发表于 2020-6-19 11:47
结贴,ST的M0有点扯蛋,其它厂家的芯片都是通过向中断标志写1来清的,它家的数据手册也是这样写的:
而且, ...

这个清中断功能是通过读ISR和RDR寄存器实现了,反而软件写ICR寄存器无效。
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版