关于STM32H743 recv()数据错误的问题分析

本文介绍了一种STM32H7微控制器使用TCP接收数据时出现错误的情况,并详细分析了问题原因及解决过程。最终发现是由于DCache未正确关闭导致的数据一致性问题。

问题描述

中位机使用TCP方式接收数据时可能出现数据错误,出错概率极高,大约接收300字节内必出。错误如下:

 

最终结论

中位机使用ST厂商自带的HAL库,该源代码在关闭网络接收的DCache(数据缓存)功能时有bug,可能导致部分区域的DCache未被关闭,从而导致TCP接收时可能从不正确的数据来源区拷贝数据,从而出错。

软件环境

HAL库版本号: STM32H7xx HAL V1.9.0

STM32CubeMX版本: 6.1.0

中位机MCU: STM32H743

LWIP版本: 2.1.2

分析过程

1 思路

出于对网络通信可靠性的极度信任,首先怀疑自己收到数据后的解析与处理有问题。我司通信协议为自定义,较为繁杂,代码中有需要操作数据指针的地方,存在修改接收到数据的可能性。

验证

屏蔽掉数据解析与处理函数后测试,错误依旧,由此定位问题出在网络接收流程;

思路

本次使用的LWIP版本为2.1.2,而本人之前用过的成熟版本为1.4.1,虽说理论上LWIP应该不会存在这么大的坑,但不管怎样先试试。

验证

开启LWIP_DEBUG及相关调试宏,结果发现错误依旧,且LWIP协议栈一切正常,无任何警告输出;

3思路

有无可能是TCP接收存储区不够大、从而导致数据接收溢出?

验证

分析其底层网络接收机制,发现其接收机制为循环队列,队列容量为4,每块大小为1524字节。

 

 

  1. 修改lwipopt.h中相关宏(ETH_RX_BUFFER_SIZE),将其由1524字节增大为2000,错误依旧;
  2. 增大队列容量,将队列容量增大为8,错误依旧;

4 思路

TCP接收顶层函数是一个Task,其优先级为HIGH,已然高于其它任何用户Task。考虑到本工程使用了LWIP,其内部会自行创建几个网络Task,有无可能是TCP接收Task优先级不够高、被其它线程抢占?

验证

1)修改TCP接收任务的优先级为最高(osPriorityRealtime),错误依旧;

2)增大TCP接收任务的堆栈,错误依旧;

思路

网上有同行说可能是CPU处理能力不够,每接收一包后sleep一下。

验证

修改后错误依旧;

思路

网络接收通常会使用DMA,且STM32H743芯片有1级DCache功能。有无可能是DCache未及时刷新导致的数据一致性问题?

验证

    1)查找网络接收数组的分配位置,固定为0x30040200;

 

   2)查找代码中对该存储区域的RAM属性设置,发现未禁止DCache,即:使用DCache;

 

为保证DMA与Cache不产生一致性的问题,STM32官方提供了一系列关闭或清空Cache的库函数。按个人经验,为保险起见,在底层接收函数中应该有规避一致性问题的动作。查询底层接收代码,果然有所发现:

 

按字面来看,应该是OK的。继续往里追查SCB_InvalidateDCache_by_Addr()函数,又有所发现:

 

其中SCB_InvalidateDCache_by_Addr()是ST官方提供的函数。

查数据手册得知,STM32H7平台的Cache操作是以Cache Line作为最小单位的,一个Cache Line是32字节。

正常情况下,该函数的第1个参数addr操作的地址应该要求32字节对齐,第2个参数dsize应该是32字节的整数倍。这样才能保证对Cache的操作是真正以Cache Line为单位。否则一旦传入的addr不按32字节对齐,则将出现问题。果断追查TCP接收循环队列的首地址,果然存在不对齐情况。手动修改之,经测试,完美通过!

 

反思

32字节对齐其实既可以在调用时执行,也可以放在SCB_InvalidateDCache_by_Addr()函数内执行。我个人倾向后者,毕竟调用者究竟是否理解该机制是不敢保证的。

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值