数据意外变化导致条件判断流程异常

1. 问题描述

用户使用的 MCU 型号是 STM32H750VB。 在客户的代码中有多个条件语句,在条件里面的变量数值没有变化的情况下执行了条件里面的逻辑。
有点类似如下 C 语句 :

If(变量 A !=0)
{
	//执行一些指令
}

即变量 A 在明明没有变化且条件不满足的情况下, 程序运行时偏偏执行了条件内部的代码. 很奇怪的现象。一时很难判断是编译器的问题还是芯片问题.

了解到客户的代码中使用了第三方库, xx.o 文件, 像这样的条件有 80 多个, 每次出现问题的具体变量并不是固定哪一个, 但是在大概 10 分钟内肯定会有其中一个出现执行逻辑问题。随意动一下代码问题就不出现, 或者出现的位置发生变化 ; 用 KEIL 编译器去设置断点, 想看该变量信息, 也会导致问题不再出现。

2. 问题分析

一开始查看 errta sheet, 看到以下相关内容 :
在这里插入图片描述

即怀疑问题跟 AXI SRAM 相关. 查看客户的这些变量, 确实是存放在 AXI SRAM 中. 由于任何修改代码都可能导致问题不再出现, 因此所有尝试须建立在不修改代码的基础上, 不然无法说明问题。
于是让客户用 STM32CubeProgrammer 以 hot plug 模式连接 MCU, 按照勘误手册中 2.2.9 节所描述的 workaround 方式将 AXI_TARG7_FN_MOD 寄存器的 READ_ISS_OVERRIDE 位通过地址的方式直接修改 :

在这里插入图片描述
结果发现并没什么效果. 于是排除了这种可能性.
一开始也怀疑问题可能跟 Cache 有关, 于是测试下关闭 Cahce 会怎么样. 通过 KEIL 调试模式下,暂停住 CPU 运行, 然后手动关闭 D-Cache :
在这里插入图片描述
结果发现问题消失不见 ! 说明问题肯定跟 Cache 有关.
但客户的代码最终肯定是不能关闭 Cache 的, 想到内核中有一个寄存器可以打开全局 Cache 的write throght 模式, 如下编程手册中的 CACR 寄存器的 FORCEWT 位 :
在这里插入图片描述
结果发现, 客户的代码本身就已经打开 :
在这里插入图片描述
看样子此模式与此问题无关. 得换个思路.

考虑到问题跟内存数据有关, 代码又不能动. 但是得想办法让内存中数据的位置动动, 看看会有什么效果 ?

通过修改 KEIL 的链接配置文件.sct 文件, 将变量随意动动, 结果发现问题也会消失不见 ! 这说明,数据的地址跟问题绝对有关联.那么具体是哪些数据呢 ?

为了精确定位到与哪些变量有关, 查看 KEIL 生成的 map 文件, 按地址倒序将每个程序中所用到的.o 的对应变量逐个挪移动 DTCM RAM 中.

DTCM_RAM_SYSTABLE 0x20000000 0x20000 
{
	 task_runtime.o (+RW)
	 task_addr.o (+RW)
	 ;…
	 authenticator_lg.o (+ZI)
	 cmpuartdevmgrembedded.o (+ZI)
	 cmpcandevmgrembedded.o (+ZI)
	 ;}

为什么要倒序呢? 主要是因为, 假如先挪低地址的变量, 肯定会导致高地址的变量向低地址移动.这好比, 如果先抽掉下面的砖头, 那么上面的砖头会自动移动下面去. 假如先抽掉上面的砖头情况就不一样了, 下面的砖头还会保持不动. 这就是为什么先挪移上面的砖头的意义, 也就是所谓的倒序.

通过这种方式, 最终定位到问题跟 heap_4.o 文件以及用户使用到的第三方提供的 xx.o 文件中的ZI 数据有关. 只要保持这两种数据位置不变, 那么问题就可以稳定触发, 一旦其中任何一个位置有所变动, 问题就消失不见.
在这里插入图片描述
现在我们知道规律了, 那么只要固定好这两种 ZI 数据位置不变的情况下, 再去尝试修改代码, 结果发现, 此时修改代码不再会对结果产生影响! 换句话说, 现在可以自由修改代码了.

考虑到此问题与 Cache 有关, 于是接下来通过 MPU 设置将 heap_4.o 所在区域的 Cache 功能关闭, 结果发现问题消失.

 MPU_InitStruct.Enable = MPU_REGION_ENABLE;
 MPU_InitStruct.BaseAddress = 0x30020000;
 MPU_InitStruct.Size = MPU_REGION_SIZE_128KB; 
 MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
 MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
 MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
 MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
 MPU_InitStruct.Number = MPU_REGION_NUMBER4;
 MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
 MPU_InitStruct.SubRegionDisable = 0x0;
 MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
 
 HAL_MPU_ConfigRegion(&MPU_InitStruct);

在这里插入图片描述
Heap_4.o 的 ZI 数据是存放在 SRAM2 中的 0x3002 E050 位置.

SRAM2_Data_4 0x3002E050 0x0000A000
{ 
 	heap_4.o (+ZI)
}

现在的现象是,Heap_4.o 的 ZI 数据只需要固定在这个位置, 问题就能稳定重现,只不过将其对应的cache 关闭, 问题则消失.
那么此区域默认的 Cache 属性是怎么样的呢? 这个在 AN4839 中可以找到其默认属性:
在这里插入图片描述
于是我们通过代码, 将其 MPU 属性再次配置其默认属性:
在这里插入图片描述

 MPU_InitStruct.Enable = MPU_REGION_ENABLE;
 MPU_InitStruct.BaseAddress = 0x30020000;
 MPU_InitStruct.Size = MPU_REGION_SIZE_128KB; 
 MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
 MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
 MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
 MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
 MPU_InitStruct.Number = MPU_REGION_NUMBER4;
 MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
 MPU_InitStruct.SubRegionDisable = 0x0;
 MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
 
 HAL_MPU_ConfigRegion(&MPU_InitStruct);

结果问题可以重现. 这再次说明, cache 属性对结果有影响.

但是此时还无法对其产生的过程细节进行解释.

与此同时, 尝试关闭客户使用第三方库 xx.o 文件中的数据 cache, 问题也同样会消失。这说明, 此问题跟客户所使用的第三方库是有关系的, 其数据在 cache 中产生了一致性问题.

于是询问客户这个第三方库是如何来的? 他们回复是一家欧洲公司提供的, 且是以 M4 内核编译的.
很明显, 在使用原则上, M4 编译出来的.o 文件, 就不应该用在 H7 工程上.

以 M4 为内核编译的.o 文件放到 M7 工程中会产生什么样的影响? 虽然理论上, M7 内核的指令集是向下兼容的, 但是也需要考虑 M7 内核相关的一些特性, 比如 Cache, memory barrier 等等. 不能完全确保不会出问题, 最保险就是重新以 M7 内核编译这个.o 文件.

由于这个第三方.o 文件客户自己也是无法知道其内部是如何实现的, 因此, 问题的具体产生过程是没办法进一步调查了. 但定位到这个.o 文件已经是当前能得到的最终结果.

3. 小结

本文最终问题的真相虽有点匪夷所思, 但这正反映了当前国内软件应用上的混乱情况. 本文所描述的问题根本原因虽然很另类, 但所涉及到的方法却对开发者有一定的参考意义, 在不能动代码的情况下, 需要挪动数据的位置, 这就必须对编译器有一定的了解. 虽也不至于太难, 但对很多开发都来说, 对编译器的了解未必很深, 因此, 一开始很多人就会卡住。另外, 对 MPU 的了解也是一大门槛. 因此, 特奉上此文, 以供参考.

参考文献

在这里插入图片描述

本文档参考ST官方的《【应用笔记】LAT1281+数据意外变化导致条件判断流程异常v1.0》文档。
参考下载地址:https://download.csdn.net/download/u014319604/89039129

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/491759.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

程序员卷王的简历

这真是一份淋漓尽致、低入尘埃、舔到骨髓的优势。 但从一个hr的角度来看,依然有可以继续提升的地方。 比如: 优势第一条本身就有问题,不懂劳动法?你怎么还会有劳动法这个概念!你知道“劳动法”本身,这个…

自动采集实时海量主流电商平台API数据接口,让你拥有一手绝对好牌!

前言 你是否曾为获取重要数据而感到困扰?是否因为数据封锁而无法获取所需信息?是否因为数据格式混乱而头疼?现在,所有这些问题都可以迎刃而解。 平时需要从某些电商网站上抓取数据,那么这里以淘宝为示例给大家演示。这…

selenium元素定位--xpath定位--层级与逻辑组合定位

其他元素非唯一时,又不想用xpath绝对定位时,需要用到层级与逻辑定位. 一、层级属性结合定位: 遇到元素没有class、name、id等或属性动态变化情况时,可以找父节点元素,父级节点没有id时,可以继续往上找id&…

HeidiSQL导出SQL文件

目前开发阶段的数据库可视化工具逐渐转为了HeidiSQL,本文讲一讲导出到sql文件的小细节,给自己做个记录补充。 安装或数据库可视化工具比较可参考: windows下全免费手动搭建php8mysql8开发环境及可视化工具安装 导出 原来用Navicat的时候&am…

git下载安装教程

git下载地址 有一个镜像的网站可以提供下载: https://registry.npmmirror.com/binary.html?pathgit-for-windows/图太多不截了哈哈,一直next即可。

macOS Sonoma 14.4.1 (23E224) 正式版发布,ISO、IPSW、PKG 下载

macOS Sonoma 14.4.1 (23E224) 正式版发布,ISO、IPSW、PKG 下载 2024 年 3 月 26 日凌晨,macOS Sonoma 14.4.1 更新修复了一个可能导致连接到外部显示器的 USB 集线器无法被识别的问题。它还解决了可能导致 Java 应用程序意外退出的问题,并修…

淘宝详情数据采集(商品上货,数据分析,属性详情,价格监控),海量数据值得get

淘宝详情数据采集涉及多个环节,包括商品上货、数据分析、属性详情以及价格监控等。在采集这些数据时,尤其是面对海量数据时,需要采取有效的方法和技术来确保数据的准确性和完整性。以下是一些关于淘宝详情数据采集的建议: 请求示…

基于 MCSDK5.4.8 电机库修改两电阻采样方法

1. 前言 在当前使用的电机电阻采样方式中分为单电阻,双电阻,三电阻三种方式,其中在 ST MCSDK5.4 库中支持了两种采样方式,单电阻和三电阻,在市面还存在另外一种采样方式,即双电阻采样,本文讨论…

机器学习:数据降维主成分分析PCA

一、引言 1.数据分析的重要性   在当今的信息爆炸时代,数据已经渗透到各个行业和领域的每一个角落,成为决策制定、科学研究以及业务发展的重要依据。数据分析则是从这些数据中提取有用信息、发现潜在规律的关键手段。通过数据分析,我们能够…

【QGIS基于边界裁剪DEM】

文章目录 1、前言2、操作步骤 1、前言 QGIS内置的栅格裁剪工具(如Raster Clipping)操作简便,允许用户使用矢量图层作为裁剪掩膜,灵活定义裁剪区域。基于QGIS对相关数据依据边界进行裁剪,可以更好地进行数据可视化展示…

iOS - Runtime - Class-方法缓存(cache_t)

文章目录 iOS - Runtime - Class-方法缓存(cache_t)1. 散列表的存取值 iOS - Runtime - Class-方法缓存(cache_t) Class内部结构中有个方法缓存(cache_t),用散列表(哈希表)来缓存曾经调用过的方法,可以提高…

车载以太网AVB交换机 TSN交换机 时间敏感网络 6端口 百兆 SW100TSN

SW100 TSN时间敏感网络AVB交换机 为6端口百兆车载以太网交换机,其中包含5通道100BASE-T1泰科MATEnet接口和1个通道100/1000BASE-T标准以太网(RJ45接口),可以实现纳米级时间同步,车载以太网多通道交换,Bypass数据采集和监控等功能&…

深度学习中常用计算距离的几种算法对比与python实现

前言 距离度量在许多机器学习算法中扮演着至关重要的角色,无论是监督学习还是无监督学习。选择适当的距离度量可以显著影响模型的性能。 在高维数据集中,欧几里得距离可能会受到所谓的“维度诅咒”的影响,因为随着维度的增加,数…

linux在使用重定向写入文件时(使用标准C库函数时)使处理信号异常(延时)--问题分析

linux在使用重定向写入文件时(使用标准C库函数时)使处理信号异常(延时)–问题分析 在使用alarm函数进行序号处理测试的时候发现如果把输出重定向到文件里面会导致信号的处理出现严重的延迟(ubuntu18) #include <stdio.h> #include <stdlib.h> #include <unist…

API成网络攻击常见载体,如何确保API安全?

根据Imperva发布的《2024年API安全状况报告》&#xff0c;API成为网络攻击者的常见载体&#xff0c;这是因为大部分互联网流量&#xff08;71%&#xff09;都是API调用&#xff0c;API是访问敏感数据的直接途径。根据安全公司Fastly的一项调查显示&#xff0c;95%的企业在过去1…

线性数据结构----(数组,链表,栈,队列,哈希表)

线性数据结构 数组链表栈使用场景 队列应用场景 哈希表特点哈希函数&#xff0c;哈希值&#xff0c;哈希冲突键值对 Entry 开放寻址法和拉链法 参考文档 数组 数组(Array) 是一种很常见的数据结构。由相同类型的元素组成&#xff0c;并且是使用一块连续的内存来存储的。 在数组…

模板方法模式(继承的优雅使用)

目录 前言 UML plantuml 类图 实战代码 AbstractRoutingDataSource DynamicDataSource DynamicDataSourceContextHolder 前言 在设计类时&#xff0c;一般优先考虑使用组合来替代继承&#xff0c;能够让程序更加的灵活&#xff0c;但这并不意味着要完全抛弃掉继承。 …

使用Urllib库创建第一个爬虫程序

Urllib 是 Python 的标准库&#xff0c;它提供了一系列用于处理 URL 的函数和类&#xff0c;包括发送 HTTP 请求、处理 HTTP 响应、解析 URL 等功能。可以使用 urllib 来编写简单的网络爬虫。 request&#xff1a;它是最基本的HTTP请求模块&#xff0c;可以用来模拟发送请求。只…

CUDA安装 Windows版

目录 一、说明 二、安装工具下载 三、CUDA安装 四、cuDNN配置 五、验证安装是否成功 一、说明 windows10 版本安装 CUDA &#xff0c;首先需要下载两个安装包 CUDA toolkitcuDNN 官方教程 CUDA&#xff1a;https://docs.nvidia.com/cuda/cuda-installation-guide-micro…

面试题-Elasticsearch集群架构和调优手段(超全面)

对于Elasticsearch&#xff08;ES&#xff09;&#xff0c;我了解并有经验。在我之前的公司&#xff0c;我们有一个相对大型的ES集群&#xff0c;以下是该集群的架构和一些调优手段的概述&#xff1a; 1. 集群架构 集群规模&#xff1a;我们的ES集群由15个节点组成&#xff0c…