RT-Thread论坛
直播中

好名字

11年用户 968经验值
擅长:可编程逻辑
私信 关注
[问答]

串口接收的bufferSize由1024变更为3072后数据接收出错,为什么?

所有功能正常的程序,为了在加快OTA下载的速度,将原来的串口接收数组的长度1024变为3072时反而接收不到数据了,后来查看了一下内存具体如下:
free
total   : 45708
used    : 34944
maximum : 35540
项目MCU的型号是STM32F103ZET6,ROM大小512,RAM大小64KB,所以目前没查到是什么原因造成的。之前是用3072测试OK的,后来因为功能增加所以增加了一些变量,及逻辑代码。然后就不行了,只能降低串口的bufferSize大小,不然串口数据json解析出错。然后改为1024以后json数据解析正常,所有功能正常。
有哪位大佬遇到类似状况???


回帖(2)

颜婷

2025-9-17 17:03:41
TT系统串口里面有一个fifo,好像是2048?还是多少,你这个是不是造成里面这个队列超时啥的了
举报

硕达科讯

2025-9-19 17:49:21

根据您描述的情况,串口接收缓冲区从1024增大到3072后出现数据接收错误,结合STM32F103ZET6的64KB RAM使用情况分析,根本原因可能是栈溢出内存碎片导致堆栈碰撞。以下是具体分析和解决方案:




问题根源分析




  1. 栈空间不足(最常见原因):



    • STM32默认栈大小通常为 1-2KB(查看启动文件startup_stm32f103xe.s中的Stack_Size定义)。

    • 当缓冲区定义为局部变量(例如在函数内部声明uint8_t buffer[3072])时,该数组会占用栈空间。

    • 栈空间不足会导致:

      • 函数调用时局部变量覆盖其他内存区域(如全局变量、堆空间)。

      • 中断发生时,寄存器压栈操作破坏缓冲区数据。


    • 现象符合:增大缓冲区后解析出错,缩小后正常。




  2. 内存布局冲突



    • 全局RAM占用分析:

      • RAM总量:64KB = 65536字节。

      • 当前使用:used = 34944字节 + 额外全局变量(功能新增部分)。

      • 缓冲区增大后占用:3072字节(需连续空间)。


    • 若缓冲区定义为全局变量,可能因内存碎片无法分配连续大块内存,或与堆栈边界碰撞。




  3. 中断响应延迟



    • 缓冲区增大后,串口中断服务程序(ISR)处理时间变长(如数据拷贝)。

    • 高波特率下可能造成数据丢失(但通常表现为丢包而非解析错误)。






解决方案


✅ 方法1:将缓冲区改为全局变量(推荐)


原因:全局变量分配在.bss/.data段,避开栈空间限制。


// 在文件顶层定义全局数组(非函数内部)
uint8_t uart_rx_buffer[3072];  // 替换原有局部变量

void USART1_IRQHandler(void) {
  // 直接使用uart_rx_buffer
}

✅ 方法2:增大栈空间



  1. 修改启动文件(startup_stm32f103xe.s):
    Stack_Size      EQU     0x00000C00   ; 原值可能是0x400(1024字节),改为3072字节(0xC00)

  2. 确保链接脚本(.ld文件)中栈空间匹配。


✅ 方法3:动态分配缓冲区(需安全验证)


void UART_Receive() {
  uint8_t *buffer = malloc(3072);
  if (buffer) {
    // 使用缓冲区
    free(buffer);  // 及时释放
  }
}

风险:需检查堆空间是否充足(启动文件中的Heap_Size)。




验证步骤




  1. 检查缓冲区定义位置



    • 若在函数内部定义buffer[3072],优先改为全局变量。




  2. 分析启动文件



    • 确认Stack_SizeHeap_Size(建议栈≥2KB,堆≥1KB)。




  3. 监视栈使用情况



    • 调试阶段在main()开头填充栈魔数:
      #define STACK_MAGIC 0xDEADBEEF
      uint32_t *stack_bottom = (uint32_t*)&__initial_sp; // 栈底地址
      *stack_bottom = STACK_MAGIC; // 链接器提供

    • 运行时检查该值是否被覆盖(若被修改则栈溢出)。




  4. 检查.map文件



    • 编译后查看生成的.map文件:

      • 全局变量地址(如uart_rx_buffer)。

      • 栈顶地址(__initial_sp)。

      • 验证uart_rx_buffer末尾地址是否低于栈顶地址(无重叠)。







其他注意事项



  • 中断嵌套问题
    确保USART中断优先级合理,避免高优先级中断打断串口数据处理。

  • DMA替代方案
    若波特率较高(>1Mbps),建议使用DMA传输,减少中断负载:
    HAL_UART_Receive_DMA(&huart1, uart_rx_buffer, 3072);


通过上述调整,3072字节缓冲区应可稳定运行。若仍存在问题,建议结合.map文件和调试器内存监视进一步排查内存布局冲突。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分