OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5595|回复: 17

stm32f466串口使用空闲中断+DMA方式,受干扰后接收卡死,如何重置串口?

[复制链接]

1

主题

6

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2015-2-7
在线时间
4 小时
发表于 2020-12-2 10:26:18 | 显示全部楼层 |阅读模式
1金钱
本帖最后由 xw19185 于 2020-12-2 10:31 编辑

stm32f466串口使用空闲中断+DMA方式,平时都能正常接收数据,但当一个外设临时重启时,可能会发一些乱码,就会引起MCU的串口接收卡死,如何处理为好?自己尝试重置串口,但没成功,只有复位整个MCU才能恢复正常。重置串口代码如下:void ResetUart2(void)        
{
        HAL_UART_Init(&huart2);
        if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_ORE) !=RESET)
               __HAL_UART_CLEAR_OREFLAG(&huart2);
        if((__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) != RESET)) //接收中断
               Rx2.Buffer[0] = (uint8_t)(huart2.Instance->DR & 0x00FF);
        HAL_UART_AbortReceive(&huart2);
       __HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_TC);//清空闲中断
       __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);//开空闲中断
       __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TCIF1_5);
       HAL_UART_Receive_DMA(&huart2,rx2BufDMA,RXBUF_DMALEN);        //开uart2串口DMA通信}
}      


串口空闭中断代码如下:
void rx2InterruptFunction(void)
{
        BaseType_t xHigherPriorityTaskWoken;
        if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_ORE) !=RESET)
                __HAL_UART_CLEAR_OREFLAG(&huart2);
        if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) != RESET)
        {
                __HAL_UART_CLEAR_IDLEFLAG(&huart2);
                HAL_UART_DMAStop(&huart2);        //关DMA串口通信
                Rx2.length =RXBUF_DMALEN - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);// 总的buf长度减去剩余buf长度,得到接收到数据的长度
                __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TCIF1_5);//清传输完成标志
                __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TEIF1_5);//清传输错误标志        
                memcpy(RxBuffer,rx2BufDMA,Rx2.length);
                RxBuffer[Rx2.length]='\0';
                RxBuffer[Rx2.length+1]='\0';
                HAL_UART_Receive_DMA(&huart2,rx2BufDMA,RXBUF_DMALEN);//开DMA串口通信
                xSemaphoreGiveFromISR(Rx2SemHandle,&xHigherPriorityTaskWoken); //释放设置模式二值信号量
                Rx2.pointer=0;
        }   
}





正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

84

帖子

1

精华

高级会员

Rank: 4

积分
666
金钱
666
注册时间
2013-10-21
在线时间
88 小时
发表于 2020-12-2 12:23:15 | 显示全部楼层
HAL库的串口接收是默认开启错误检测的,你是否对于串口的错误回调函数进行清除错误标志位的判断?
  1. void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
  2. {
  3.         /*清除错误中断标志位,防止卡死*/
  4.         __HAL_UART_CLEAR_PEFLAG(huart);
  5. }
复制代码

回复

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2015-2-7
在线时间
4 小时
 楼主| 发表于 2020-12-2 14:23:50 | 显示全部楼层
旮旯旭 发表于 2020-12-2 12:23
HAL库的串口接收是默认开启错误检测的,你是否对于串口的错误回调函数进行清除错误标志位的判断?

根据你的提示加了__HAL_UART_CLEAR_PEFLAG(),但结果还是一样。
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2015-2-7
在线时间
4 小时
 楼主| 发表于 2020-12-2 15:21:53 | 显示全部楼层
跟踪了一下,重复出错多次,只有一次出错时进了HAL_UART_ErrorCallback(),其它都没进,还是卡住。
回复

使用道具 举报

3

主题

1155

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7462
金钱
7462
注册时间
2015-1-15
在线时间
1367 小时
发表于 2020-12-2 16:15:57 | 显示全部楼层
STM32F466是ST的芯片?
一分耕耘一分收获。
回复

使用道具 举报

4

主题

84

帖子

1

精华

高级会员

Rank: 4

积分
666
金钱
666
注册时间
2013-10-21
在线时间
88 小时
发表于 2020-12-2 16:19:52 | 显示全部楼层
xw19185 发表于 2020-12-2 15:21
跟踪了一下,重复出错多次,只有一次出错时进了HAL_UART_ErrorCallback(),其它都没进,还是卡住。

可能性很多的,你工程可以贴上来?
使用串口空闲中断接收,你除了空闲的状态,如果因为外设启动向你设备发送数据,你的接收缓冲区多大,会不会进入了接收完成中断的callback了?
如果进了RxCpltCallback,你是不是进行了处理?
回复

使用道具 举报

4

主题

84

帖子

1

精华

高级会员

Rank: 4

积分
666
金钱
666
注册时间
2013-10-21
在线时间
88 小时
发表于 2020-12-2 16:25:42 | 显示全部楼层
xw19185 发表于 2020-12-2 15:21
跟踪了一下,重复出错多次,只有一次出错时进了HAL_UART_ErrorCallback(),其它都没进,还是卡住。

在使用串口空闲中断的时候需要注意2点
1.你的接收缓冲区足够大,保证通信最大接收数据量你的接收缓冲区不会溢出。
2.为防止1的情况出现,你需要对对应串口的接收完成中断处理HAL_UART_RxCpltCallback
   重新开启接收

按照你的描述大概率进入了接收完成中断回调函数,然后你的函数里面没有重新开启接收。

你再看看。
回复

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
发表于 2020-12-2 16:57:29 | 显示全部楼层
本帖最后由 jiangyy 于 2020-12-2 16:59 编辑

1.回调函数处理
  1. USART_RECEIVETYPE UsartType1;
  2. /*********************************usart1 begin****************************************/
  3. void HAL_USART1_IDLECallback(UART_HandleTypeDef *huart)
  4. {
  5.         if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
  6.         {
  7.                 HAL_UART_DMAStop(&huart1);
  8.                 UsartType1.rx_len =  RECEIVELEN - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
  9.                 UsartType1.receive_flag = 1;

  10.                 if(UsartType1.receive_flag)//如果产生了空闲中断
  11.                 {
  12.                   UsartType1.receive_flag = 0;//清零标记
  13.                   handle_UART1();//处理串口1应用
  14.                   memset(UsartType1.usartDMA_rxBuf, 0, sizeof(UsartType1.usartDMA_rxBuf));
  15.                   __HAL_UART_CLEAR_IDLEFLAG(&huart1);
  16.                   HAL_UART_Receive_DMA(&huart1,UsartType1.usartDMA_rxBuf,RECEIVELEN);
  17.                 }
  18.         }
  19. }

  20. //DMA发送函数
  21. void Usart1SendData_DMA(uint8_t *pdata, uint16_t Length)
  22. {
  23.         while(UsartType1.dmaSend_flag == USART_DMA_SENDING);
  24.         UsartType1.dmaSend_flag = USART_DMA_SENDING;
  25.         HAL_UART_Transmit_DMA(&huart1, pdata, Length);
  26. }
复制代码
2.结构体定义
  1. #define RECEIVELEN                         64               //长度根据应用自定义
  2. #define SENDLEN                         120              //长度根据应用自定义
  3. #define USART_DMA_SENDING         1                          //发送未完成
  4. #define USART_DMA_SENDOVER         0                         //发送完成

  5. typedef struct
  6. {
  7. uint8_t receive_flag:1;//空闲接收标记
  8. uint8_t dmaSend_flag:1;//发送完成标记
  9. uint8_t fpgaSend_flag:1;//发送完成标记
  10. uint16_t rx_len;//接收长度
  11. uint8_t usartDMA_rxBuf[RECEIVELEN];        //DMA接收缓存
  12. uint8_t usartDMA_txBuf[SENDLEN];        //DMA发送缓存
  13. uint8_t usartFPGA_Buf[RECEIVELEN];        //FPGA处理缓存
  14. uint8_t usartPRINTF_Buf[14];                //打印处理缓存
  15. }USART_RECEIVETYPE;

  16. extern USART_RECEIVETYPE UsartType1;
  17. void HAL_USART1_IDLECallback(UART_HandleTypeDef *huart);
  18. void Usart1SendData_DMA(uint8_t *pdata, uint16_t Length);
复制代码
3.中断开启
  1. HAL_UART_Receive_DMA(&huart1, UsartType1.usartDMA_rxBuf, RECEIVELEN);
  2. __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
复制代码
希望对你有帮助,我使用的是STM32CUBEIDE编程的
回复

使用道具 举报

3

主题

821

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3359
金钱
3359
注册时间
2011-11-10
在线时间
207 小时
发表于 2020-12-2 18:16:05 | 显示全部楼层
检查你的memcpy(RxBuffer,rx2BufDMA,Rx2.length);如果数据量很大会不会内存溢出。建议尽量打个标志然后回主函数处理,加个if(Rx2.length>n),判断是否是无效数据,如果是无效的也不需要进行memcpy了。
回复

使用道具 举报

5

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
73
金钱
73
注册时间
2018-7-19
在线时间
15 小时
发表于 2020-12-3 20:52:43 | 显示全部楼层
jiangyy 发表于 2020-12-2 16:57
1.回调函数处理
2.结构体定义
3.中断开启

非常感谢啊!
回复

使用道具 举报

5

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
73
金钱
73
注册时间
2018-7-19
在线时间
15 小时
发表于 2020-12-3 20:53:19 | 显示全部楼层
旮旯旭 发表于 2020-12-2 16:25
在使用串口空闲中断的时候需要注意2点
1.你的接收缓冲区足够大,保证通信最大接收数据量你的接收缓冲区 ...

谢谢啊
回复

使用道具 举报

5

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
73
金钱
73
注册时间
2018-7-19
在线时间
15 小时
发表于 2020-12-3 20:55:23 | 显示全部楼层
c2007s 发表于 2020-12-2 18:16
检查你的memcpy(RxBuffer,rx2BufDMA,Rx2.length);如果数据量很大会不会内存溢出。建议尽量打个标志然后回主 ...

谢谢啊
回复

使用道具 举报

5

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
73
金钱
73
注册时间
2018-7-19
在线时间
15 小时
发表于 2020-12-3 21:08:58 | 显示全部楼层
谢谢各位的回复。我的接收缓冲足够大(3K),外设重启发送的数据不可能溢出。另外我也加了回调函数,如下:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart->Instance==USART2) //判断是否是串口2
        {
                HAL_UART_DMAStop(&huart2);        //关DMA串口通信
                Rx2.length =0;// 总的buf长度减去剩余buf长度,得到接收到数据的长度
        Rx2.pointer=0;
        __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TCIF1_5);//清传输完成标志
                __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TEIF1_5);//清传输错误标志        
        BC28_RxBuffer[Rx2.length+1]='\0';
                HAL_UART_Receive_DMA(&huart2,rx2BufDMA,RXBUF_DMALEN);//开DMA串口通信
        }
}

正常情况下都没问题,外设重启一般都是由我的MCU来控制的,我可以先关闭串口,然后再重启外设,延时10秒后开启串口,都能正常工作。
但如果我不关闭串口,直接重启就会出问题。

想试着重置串口,如上 ResetUart2(),不成功,只有重启MCU才行。一直找不到问题,不知道重置串口为什么不成功?

之前没用DMA方式,用串口中断和空闲中断来处理,能适应外设重启不出问题。(串口会有溢出,清溢出标志可解决)。
回复

使用道具 举报

5

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
73
金钱
73
注册时间
2018-7-19
在线时间
15 小时
发表于 2020-12-3 21:18:11 | 显示全部楼层
我的缓存足够大(3K),外设重启时也不可能溢出,跟踪了一下也没进回调函数,回调函数如下:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart->Instance==USART2) //判断是否是串口2
        {
                HAL_UART_DMAStop(&huart2);        //关DMA串口通信
                Rx2.length =0;// 总的buf长度减去剩余buf长度,得到接收到数据的长度
        Rx2.pointer=0;
        __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TCIF1_5);//清传输完成标志
                __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TEIF1_5);//清传输错误标志        
        BC28_RxBuffer[Rx2.length+1]='\0';
                HAL_UART_Receive_DMA(&huart2,rx2BufDMA,RXBUF_DMALEN);//开DMA串口通信
        }
}
使用了FreeRTOS,串口失效时,其它任务都能正常运行。

外设重启一般都是MCU主动控制的,测试过先关闭串口再重启外设,延时10秒再开串口就都正常。

不知为何ResetUart2()函数没能正确重置串口通信?     
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2015-2-7
在线时间
4 小时
 楼主| 发表于 2020-12-3 21:20:37 | 显示全部楼层
我的缓存足够大(3K),外设重启时也不可能溢出,跟踪了一下也没进回调函数,回调函数如下:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart->Instance==USART2) //判断是否是串口2
        {
                HAL_UART_DMAStop(&huart2);        //关DMA串口通信
                Rx2.length =0;// 总的buf长度减去剩余buf长度,得到接收到数据的长度
        Rx2.pointer=0;
        __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TCIF1_5);//清传输完成标志
                __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TEIF1_5);//清传输错误标志        
        BC28_RxBuffer[Rx2.length+1]='\0';
                HAL_UART_Receive_DMA(&huart2,rx2BufDMA,RXBUF_DMALEN);//开DMA串口通信
        }
}
使用了FreeRTOS,串口失效时,其它任务都能正常运行。

外设重启一般都是MCU主动控制的,测试过先关闭串口再重启外设,延时10秒再开串口就都正常。

不知为何ResetUart2()函数没能正确重置串口通信?     
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2015-2-7
在线时间
4 小时
 楼主| 发表于 2020-12-3 22:41:37 | 显示全部楼层
我的缓存足够大(3K),外设重启时也不可能溢出(现在还是加了判断,安全一点),跟踪了一下也没进回调函数,回调函数如下:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart->Instance==USART2) //判断是否是串口2
        {
                HAL_UART_DMAStop(&huart2);        //关DMA串口通信
                Rx2.length =0;// 总的buf长度减去剩余buf长度,得到接收到数据的长度
        Rx2.pointer=0;
        __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TCIF1_5);//清传输完成标志
                __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TEIF1_5);//清传输错误标志        
        BC28_RxBuffer[Rx2.length+1]='\0';
                HAL_UART_Receive_DMA(&huart2,rx2BufDMA,RXBUF_DMALEN);//开DMA串口通信
        }
}
使用了FreeRTOS,串口失效时,其它任务都能正常运行。

外设重启一般都是MCU主动控制的,测试过先关闭串口再重启外设,延时10秒再开串口就都正常。

不知为何ResetUart2()函数没能正确重置串口通信?     

另外之前没用DMA,采用串口中断+空闲中断能适应外设重启,有时会有串口溢出标志,清一下就可以了。
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2015-2-7
在线时间
4 小时
 楼主| 发表于 2020-12-3 22:42:19 | 显示全部楼层
jiangyy 发表于 2020-12-2 16:57
1.回调函数处理
2.结构体定义
3.中断开启

我的缓存足够大(3K),外设重启时也不可能溢出(现在还是加了判断,安全一点),跟踪了一下也没进回调函数,回调函数如下:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart->Instance==USART2) //判断是否是串口2
        {
                HAL_UART_DMAStop(&huart2);        //关DMA串口通信
                Rx2.length =0;// 总的buf长度减去剩余buf长度,得到接收到数据的长度
        Rx2.pointer=0;
        __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TCIF1_5);//清传输完成标志
                __HAL_DMA_CLEAR_FLAG(&hdma_usart2_rx, DMA_FLAG_TEIF1_5);//清传输错误标志        
        BC28_RxBuffer[Rx2.length+1]='\0';
                HAL_UART_Receive_DMA(&huart2,rx2BufDMA,RXBUF_DMALEN);//开DMA串口通信
        }
}
使用了FreeRTOS,串口失效时,其它任务都能正常运行。

外设重启一般都是MCU主动控制的,测试过先关闭串口再重启外设,延时10秒再开串口就都正常。

不知为何ResetUart2()函数没能正确重置串口通信?     

另外之前没用DMA,采用串口中断+空闲中断能适应外设重启,有时会有串口溢出标志,清一下就可以了。
回复

使用道具 举报

4

主题

84

帖子

1

精华

高级会员

Rank: 4

积分
666
金钱
666
注册时间
2013-10-21
在线时间
88 小时
发表于 2020-12-4 13:06:07 | 显示全部楼层
xw19185 发表于 2020-12-3 22:42
我的缓存足够大(3K),外设重启时也不可能溢出(现在还是加了判断,安全一点),跟踪了一下也没进回调函 ...

先保证逻辑下,单独的串口测试功能通过把,你如果是系统下调试你都不知道是什么原因导致的,先创建单独的串口任务测试是否一样有这个问题,在一步步测试
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-4-30 04:00

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表