当前位置: 首页 > news >正文

​STM32H723 iPerf 调试笔记:MemManage_Handler 问题分析与解决

问题现象

  • 运行 iperf 代码时触发 MemManage_Handler
  • 调试寄存器值:
    • CFSR = 0x82MMARVALID + DACCVIOL,数据访问违例)。
    • MMFAR = 0xE000ED34(非法访问 SCB 寄存器地址)。

根本原因

  1. 栈溢出

    • 线程栈过小(默认 1024 字),网络任务运行时栈溢出,导致返回地址被篡改,程序跳转到非法地址。
  2. 内存管理不一致

    • 混合使用 malloc/free 和 pvPortMalloc/vPortFree,导致堆损坏或野指针。
  3. 线程逻辑错误

    • 强制覆盖线程模式(mode = IPERF_MODE_SERVER),客户端线程无法启动。
  4. 共享资源竞争

    • 多线程未保护 param 结构体,导致状态不一致。
  5. 非法地址访问

    • 野指针操作或未对齐访问,如直接操作硬件寄存器地址。

解决方案

1. 优化线程栈配置
  • 增大栈大小
    #define TCP_SERVER_THREAD_STACKSIZE 2048  // 单位:字(FreeRTOS 默认)
  • 启用栈溢出检测
    // FreeRTOSConfig.h
    #define configCHECK_FOR_STACK_OVERFLOW 2
    
    void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
        printf("[ERROR] Stack Overflow in Task: %s\n", pcTaskName);
    }
2. 统一内存管理接口
  • 强制使用 FreeRTOS API
    // 分配
    uint8_t *buf = (uint8_t *)pvPortMalloc(IPERF_BUFSZ);
    // 释放
    vPortFree(buf);
3. 修正线程启动逻辑
  • 删除强制模式覆盖
    // 错误代码(删除此行)
    // mode = IPERF_MODE_SERVER;
    
    // 正确逻辑
    if (param.mode == IPERF_MODE_CLIENT) {
        sys_thread_new("iperf_client", iperf_client, NULL, 2048, 4);
    } else if (param.mode == IPERF_MODE_SERVER) {
        sys_thread_new("iperf_server", iperf_server, NULL, 2048, 4);
    }
4. 保护共享资源
  • 添加互斥锁
    static SemaphoreHandle_t param_mutex = xSemaphoreCreateMutex();
    
    void set_iperf_mode(int mode) {
        xSemaphoreTake(param_mutex, portMAX_DELAY);
        param.mode = mode;
        xSemaphoreGive(param_mutex);
    }
5. 修复链接脚本符号
  • 定义 __flash_size__
    /* STM32H723ZETx_FLASH.ld */
    PROVIDE(__flash_start__ = ORIGIN(FLASH));
    PROVIDE(__flash_size__ = LENGTH(FLASH));
6. 调试非法地址访问
  • 捕获 MMFAR 地址
    void MemManage_Handler(void) {
        uint32_t cfsr = SCB->CFSR;
        uint32_t mmfar = SCB->MMFAR;
        printf("CFSR=0x%08lX, MMFAR=0x%08lX\n", cfsr, mmfar);
        while(1);
    }
  • 设置数据断点:在调试器中监控 0xE000ED34 的写操作。

验证步骤

  1. 编译并烧录修复后的代码
  2. 运行客户端/服务器测试
    # 客户端
    iperf -c 192.168.1.100 -p 5001
    # 服务器
    iperf -s -p 5001
  3. 监控输出
    • 确认无 MemManage_Handler 触发。
    • 检查任务栈水位:
      UBaseType_t free_stack = uxTaskGetStackHighWaterMark(NULL);
      printf("Free Stack: %u words\n", free_stack);

关键代码片段

线程创建
sys_thread_new("iperf_server", iperf_server, NULL, 2048, 4);
sys_thread_new("iperf_client", iperf_client, NULL, 2048, 4);
内存分配修正
// iperf_server 中
recv_data = (uint8_t *)pvPortMalloc(IPERF_BUFSZ);
vPortFree(recv_data); // 替换 free()
互斥锁保护共享参数
xSemaphoreTake(param_mutex, portMAX_DELAY);
param.mode = IPERF_MODE_SERVER;
xSemaphoreGive(param_mutex);

总结

问题现象/寄存器值解决方案
栈溢出MMFAR 指向栈地址增大栈,启用溢出检测
内存管理不一致堆损坏,随机崩溃统一使用 pvPortMalloc/vPortFree
线程逻辑错误客户端无法启动删除强制模式覆盖
共享资源竞争参数状态不一致添加互斥锁
非法地址访问MMFAR=0xE000ED34检查野指针,设置数据断点

通过上述步骤,可系统性解决因内存管理、栈溢出和线程逻辑导致的 MemManage_Handler 问题。

http://www.dtcms.com/a/130355.html

相关文章:

  • 入门到精通,C语言十大经典程序
  • 开发一款游戏需要哪些岗位角色参与?
  • CAN协议学习笔记1
  • 文章记单词 | 第29篇(六级)
  • linux下的目录文件管理和基本文件管理的基本操作
  • 5.3 GitHub订阅系统核心架构解密:高并发设计与SQLite优化实战
  • 「Unity3D」图片导入选项取消Read/Write,就无法正确显示导入大小,以及Addressable打包无法正确显示的问题
  • HarmonyOS应用开发指南
  • stm32+ADS1256称重模块,单通道称,多通道称(例如地磅)
  • MySQL一对多关系--多对多关系之间的区别
  • RCFile数据读取流程
  • 前缀和--
  • 消息中间件——RocketMQ(一)
  • 【复旦微FM33 MCU 底层开发指南】高级定时器ATIM
  • 齐次坐标系统:什么是齐次坐标?为什么要引入齐次坐标?
  • Go - 内存逃逸
  • C语言--实现图的基本操作
  • 探秘 LangChain 函数定义
  • Java 性能优化:从原理到实践的全面指南
  • #systemverilog# 关于基于systemveriog验证平台的RTL+TB文件编译顺序问题的讨论
  • c++11--std::forwaord--完美转发
  • zk源码-7.ZAB协议和数据存储二
  • arm_math.h、arm_const_structs.h 和 arm_common_tables.h
  • 游戏引擎学习第217天
  • Day14:关于MySQL的索引——创、查、删
  • 【腾讯云智】20250329笔试算法题
  • QT聊天项目开发DAY02
  • NIPS2024论文 End-to-End Ontology Learning with Large Language Models
  • SpringBoot-Web开发
  • 网络空间安全(56)Laravel框架讲解