打印
[单片机芯片]

CH582串口中断内存溢出导致MCU频繁重启

[复制链接]
3082|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-7-4 07:55 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
1. 遇到问题描述以及解决
1.1 问题一:串口中断导致MCU频繁重启
1.1.1【场景描述】
硬件:沁恒的 CH582F 单片机, 海凌科 24G 雷达模组

引脚:海凌科雷达模组5个引脚和 CH582F 连,单片机PB4引脚(普通GPIO,下拉输入,采用IO查询的方式判断电平)



1.1.2 【问题描述】
烧录程序后,发现 单片机一直 周期性的重启。。。。下图左侧为串口3的接受中断



1.1.3 【问题定位】
雷达:每间隔100ms 从TX引脚输出的数据为

[2023-12-01 07:58:27.167]# RECV HEX>
F4 F3 F2 F1 0D 00 02 AA 03 1E 00 5A 1E 00 64 00 00 55 00 F8 F7 F6 F5
[2023-12-01 07:58:27.267]# RECV HEX>
F4 F3 F2 F1 0D 00 02 AA 03 1E 00 64 1E 00 64 00 00 55 00 F8 F7 F6 F5
[2023-12-01 07:58:27.367]# RECV HEX>
F4 F3 F2 F1 0D 00 02 AA 03 1E 00 64 1E 00 64 00 00 55 00 F8 F7 F6 F5
[2023-12-01 07:58:27.469]# RECV HEX>
F4 F3 F2 F1 0D 00 02 AA 03 1E 00 64 1E 00 64 00 00 55 00 F8 F7 F6 F5
[2023-12-01 07:58:27.562]# RECV HEX>
F4 F3 F2 F1 0D 00 02 AA 03 1E 00 64 1E 00 64 00 00 55 00 F8 F7 F6 F5


将雷达模组拿掉,程序就正常了,因此一个个引脚查问题,最终定位问题为:

软件中开启了串口3的接收中断,雷达模组频繁的发送数据导致单片机频繁进入中断,造成重启

检查软件中的中断咋写的,,,,,

1.1.4 【问题解决】
曾经在ESP32 开发中翻过这样一个错误:【esp32】解决以太网+mqtt堆栈溢出问题 报错 no mem for receive buffer,这个是由于动态申请的内存没有是释放导致栈空间不足,MCU反复重启

数组溢出导致的栈内存被冲刷掉,导致内存溢出而使得MCU重启

问题定位如下, 我的软件串口接收中断竟然是这么写的::::::令人发指!!!!

串口中断将接收到的数据存储到 uart_rx_buffer[]数组中, 但是,,我定义了一个 100 大小的数组,却 user_rx_buffer_write_index & user_rx_buffer_length_mask 去接收数据。。。。

本意是这样的 定义一个 1024 大小的数组,每接收到一个自己 user_rx_buffer_write_index 自加1,然后通过 user_rx_buffer_write_index & user_rx_buffer_length_mask 将范围限制在 1-1024 范围内,防止数组溢出。。。。当时应该是担心占用内存太大,手动将uart_rx_buffer[1024]改为了 uart_rx_buffer[100],但是忘记修改 user_rx_buffer_length_mask变量的值了。。

造成的结果就是,我定义了100维的数组,缺往里边存了 最大1024个字节,那剩下的900字节空间就把其他栈空间占用了,,冲掉了哪些变量的值???不得而知,但是造成的结果就是单片机不断重启了。。。。。。。。

解决方式:

将数组改为 1024 维的,或者数组100维不变,将掩码的值改为99,别造成内存溢出,就可以了,

实测修改后,就不会重启了

uint8_t uart_rx_buffer[100]={0};
uint16_t user_rx_buffer_length_mask = 1024-1;
uint16_t user_rx_buffer_write_index = 0;
uint8_t trigB = 7 ;
uint8_t uart_rx_done = 0;

__INTERRUPT
__HIGH_CODE
void UART3_IRQHandler(void)
{
    uint16_t error;
    int i = 0;
    switch(UART3_GetITFlag())
    {
        case UART_II_LINE_STAT:  // 线路状态错误
            UART3_GetLinSTA();
            break;

        case UART_II_RECV_RDY: // 数据达到设置触发点
          while( R8_UART3_RFC > 1) {  // 这个方式必须保证uart的接收触发中断是大于1字节的
                uart_rx_buffer[user_rx_buffer_write_index & user_rx_buffer_length_mask] = R8_UART3_RBR;
                user_rx_buffer_write_index += 1;
            }
            break;
        case UART_II_RECV_TOUT: // 接收超时,暂时一帧数据接收完成
            for(i = 0; i < R8_UART3_RFC; i++)
            {
                iRxBuff = UART3_RecvByte();
                //UART3_SendByte(iRxBuff);
            }  
            break;

        case UART_II_THR_EMPTY:
            break;
        case UART_II_MODEM_CHG:
            break;
        default:
            break;
    }
}



知识点:

当 b = 2^n 的时候:a % b = a & (b-1)
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_39217004/article/details/134725988

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1903

主题

15576

帖子

11

粉丝