【ARMv8M Cortex-M33 系列 7.2 -- HardFault 问题定位 1】

文章目录

    • 问题背景
    • 堆栈对齐要求
      • Cortex-M33 的 FPU 功能

问题背景

rt-thread 在PendSV_Handler退出的时候发生了HardFault_Handler是什么原因?且 LR 的值为0xfffffffd

堆栈对齐要求

在 ARM Cortex-M 架构中,堆栈指针 (SP) 必须始终保持 8 字节对齐。这是因为从 ARMv7-M 开始,堆栈帧可能包含额外的浮点寄存器,而要求 8 字节对齐以实现更有效的访问和与浮点寄存器大小相一致。

在进入异常处理时,处理器会自动将 xPSR、返回地址、LRR12R3R2R1R0 压入堆栈;如果使用浮点单元且由异常激活,则还会压入 S0-S15FPSCR 寄存器。

当从异常返回时,处理器会根据 LR 中的 EXC_RETURN 值来检查堆栈指针,以确保正确地恢复寄存器状态。

发生 HardFault 的原因可能很多,但当你看到 LR(链接寄存器)的值为 0xFFFFFFFD 时,这表明异常返回时处理器试图从进程堆栈指针(PSP)恢复上下文。这个特定的 EXC_RETURN 值意味着在从异常(这种情况下是 PendSV)返回时,发生了与堆栈或上下文恢复有关的问题。

以下是一些可能导致你在 PendSV_Handler 退出时遭遇 HardFault 的原因:

  1. 堆栈指针 (PSP) 不正确:如果 PSP 被错误地设置或在异常处理期间被破坏,它可能不再指向有效的堆栈帧,导致在尝试恢复寄存器时访问了错误的内存地址。
  2. 堆栈溢出:如果任务的堆栈空间不足,可能在堆栈中写入时超过了分配的边界,导致堆栈损坏。
  3. 上下文保存不完整或不正确:在进入 PendSV_Handler 时,必须保存当前任务的上下文,包括所有必要的寄存器。如果保存过程中出错,或者未能保存足够的寄存器状态,那么恢复这些寄存器时会遇到问题。
  4. 上下文恢复到错误的地址:如果保存的程序计数器(PC)或状态寄存器(xPSR)的值不正确,那么在尝试返回到这些地址时会触发 HardFault
  5. 错误的异常返回指令:虽然 LR 的值是正确的 EXC_RETURN,但如果在异常处理的汇编代码中有错误,可能会导致错误的堆栈操作或错误的异常返回。

为了调试此 HardFault,可以采取以下步骤:

  • 检查 PSP 的值:在 HardFault_Handler 中,检查 PSP 是否指向有效的内存区域。
  • 检查堆栈大小:验证所有任务的堆栈大小是否足够,并没有发生堆栈溢出。
  • 使用调试器:如果可能,使用调试器单步执行 PendSV_Handler 中的代码,观察 PSPPCxPSR 的值以及它们的变化。
  • 查看 HardFault_Handler :实现一个 HardFault_Handler 来捕获硬件错误,从中可以读取更多的系统状态和错误信息,例如配置故障状态寄存器 CFSRHFSRMMFARBFAR
  • 审查 RT-Thread 的系统配置:确认 RT-Thread 的配置与你的硬件设备兼容,尤其是关于任务堆栈和堆内存的部分。
  • 堆栈帧对齐检查:确保在进入 PendSV_Handler 之前堆栈帧是正确对齐的,因为 ARM Cortex-M 系列处理器要求堆栈必须8字节对齐。如果启用了自动堆栈对齐检查,STKALIGN 位在 CCR 寄存器内,那么在对齐错误时可能会引发 UsageFault,如果没有启用相关的 UsageFault,则会变成 HardFault

接着上篇文章:【ARMv8M Cortex-M33 系列 7.1 – xPSR | CFSR | HFSR | BFAR | MMFAR 寄存器】 来通过JLink 来对 错误提示信息寄存器进行debug,它们的地址如下:

#define SCB_CFSR        (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
#define SCB_HFSR        (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
#define SCB_MMAR        (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
#define SCB_BFAR        (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */
#define SCB_AIRCR       (*(volatile unsigned long *)0xE000ED0C)  /* Reset control Address Register */
#define SCB_RESET_VALUE 0x05FA0004                               /* Reset value, write to SCB_AIRCR can reset cpu */

通过JTAG 读取上面debug 寄存器SCB_CFSR的值:

mem32 0xe000ed28 1
E000ED28 = 00040000

在这里插入图片描述
INVPC, bit [2]
Invalid PC flag. Sticky flag indicating whether an integrity check error has occurred.

可以看到发生 INVPC 这个错误。

继续 Debug 其它寄存器:

mem32 0xe000ed2c 1
E000ED2C = 40000000

在这里插入图片描述
FORCED, bit [30]
Forced. Indicates that a fault with configurable priority has been escalated to a HardFault exception, because
it could not be made active, because of priority, or because it was disabled.

从上面的解释可以看到问题原因是由于某个异常升级为了 HardFault 异常了,可能是由于这个异常没有enable,所以后面就需要查看如何使能Cortex-M33 的各种异常。

继续 Debug 其它寄存器:

mem32 0xe000ed34 1
E000ED34 = 20000BF4

在这里插入图片描述
ADDRESS, bits [31:0]
Data address for an MemManage fault. This register is updated with the address of a location that produced a
MemManage fault. The MMFSR shows the cause of the fault, and whether this field is valid. This field is
valid only when MMFSR.MMARVALID is set, otherwise it is UNKNOWN.

Attributes
8-bit read/write-one-to-clear register located at 0xE000ED28.
在这里插入图片描述
这个寄存器也就是寄存器CFSR 的 低8bits,由于低8bits 为0,所以,不是memmanage fault 的问题。

mem32 0xe000ed38 1
E000ED38 = 20000BF4

在这里插入图片描述
ADDRESS, bits [31:0]
Data address for a precise BusFault. This register is updated with the address of a location that produced
a BusFault. BFSR shows the reason for the fault. This field is valid only when BFSR.BFARVALID is set,
otherwise it is UNKNOWN.
由于 BFSR.BFARVALID 值为0,所以也不是 Busfault。

当将编译参数中的硬浮点修改为软浮点之后,再去读CFSR 寄存器的值为:

J-Link>mem32 0xe000ed28 1
E000ED28 = 01000000

也就是报出 UNALIGNED 错误(Debug 到最后发现也不是这个问题引起的)。到目前为止仍然没有找到问题所在!!!

那么如何配置不使用fpu功能?
要在 ARM Cortex-M33 上使用 ARM GCC 编译器配置不使用 FPU(浮点单元)功能,需要在编译选项中指定不使用硬件浮点支持。这可以通过设置适当的编译器标志实现。

ARM Cortex-M33 可以配置为带有或不带有 FPU。如果你的 Cortex-M33 核心不包含 FPU,或者你的应用程序不需要浮点运算支持,你应该确保编译器不生成任何浮点指令或链接到浮点库。

以下是如何在编译器选项中禁用 FPU 支持的示例:

-mcpu=cortex-m33 -mthumb -mfloat-abi=soft 

这里的编译器选项说明如下:

  • -mcpu=cortex-m33: 指定目标 CPU 是 Cortex-M33。
  • -mthumb: 指示编译器生成 Thumb 指令集的代码。
  • -mfloat-abi=soft: 指定浮点 Application Binary Interface (ABI) 为软件实现(soft)。

这意味着即使硬件支持浮点运算,也将使用软件库来执行浮点运算。这个选项确保编译器不会生成使用 FPU 的代码。

如果你的应用程序确实包含浮点运算,上述设置会导致所有浮点运算都通过软件库函数实现,而不是使用 FPU。这会导致浮点运算性能降低,但可以避免在不包含 FPU 的 Cortex-M33 核心或者选择不使用 FPU 的情况下,发生与硬件相关的问题。

请确保编译器选项在整个项目的编译和链接过程中保持一致,包括任何库或外部模块。如果链接到了已编译的库,也需要确保这些库是在不使用 FPU 支持的情况下编译的。

最后在Makefile 中的配置如下

#LDS_INC = -L $(LIB_PATH)/lib/gcc/arm-none-eabi/10.2.1/thumb/v8-m.main+fp/hard
LDS_INC = -L $(LIB_PATH)/lib/gcc/arm-none-eabi/10.2.1/thumb/v8-m.main/nofp \-L $(LIB_PATH)/arm-none-eabi/lib/thumb/v8-m.main/nofp
all: $(TARGET) postbuild$(TARGET): $(OBJS)@echo Building target: $@$(LD) $(LDS_INC) -T $(LDS) --gc-sections -Map ra4m2.map -o $@ $(OBJS) -lc -lm -lgcc

Cortex-M33 的 FPU 功能

ARM Cortex-M33 处理器是 ARMv8-M 架构的一部分,可选地包含一个符合 IEEE 754 标准的单精度浮点单元 (FPU),支持所有单精度浮点数据类型的运算。包含 FPU 的 Cortex-M33 可以提高浮点计算的性能,适用于需要执行大量浮点计算的应用程序。

Cortex-M33 的 FPU 支持以下特性:

  • 编译器可以生成硬件 FPU 指令来完成浮点运算,这通常比软件实现更快。
  • FPU 支持单精度(32位)浮点数的加、减、乘、除运算和其他复杂运算。
  • 浮点运算的结果可以直接用于程序流程控制,如浮点比较和分支。

如果选择在 Cortex-M33 上使用 FPU 功能,需要使用 -mfloat-abi=hard-mfloat-abi=softfp 编译器选项来启用硬件浮点支持。这些选项会使编译器产生使用 FPU 的代码,并链接到相应的浮点库。

Q:cortex-m33默认安全状态下如何启动rt-thread os,需要配置哪些内容? 可以一直在安全状态下运行os吗?
A: 要在 Cortex-M33 默认的安全状态下启动 RT-Thread OS,需要执行一系列的初始化步骤来配置处理器,启动操作系统,并确保操作系统及其任务在安全状态下正确运行。

下面是一般需要执行的步骤:

  1. 初始化硬件
    • 配置系统时钟,包括 CPU 时钟、外设时钟等。
    • 初始化必要的外设,如定时器、串口、中断控制器等。
  2. 配置中断向量表
    • 将 RT-Thread 的中断向量表的位置设置到默认的中断向量表寄存器(VTOR)。
  3. 配置堆栈指针
    • 设置 MSP 或 PSP 的值,确保为 RT-Thread OS 的中断和任务提供正确的堆栈。
  4. 初始化 RT-Thread OS
    • 调用 RT-Thread 提供的初始化函数,如 rt_system_scheduler_init 初始化调度器,rt_system_timer_init 初始化系统定时器等。
  5. 创建任务(线程)
    • 使用 RT-Thread 提供的 API,如 rt_thread_create,来创建并初始化操作系统任务。
  6. 启动调度器
    • 调用 rt_system_scheduler_start 来启动 RT-Thread 的调度器。
  7. 附加系统服务和中断处理
    • 将 RT-Thread 的系统服务和中断处理函数附加到 Cortex-M33 的异常和中断向量。
  8. TrustZone 配置(如果使用 TrustZone)
    • 如果打算使用 TrustZone,你需要正确配置安全属性单元(SAU),确保内存和外设的安全状态符合 RT-Thread 的要求。在默认安全状态下,这一步可能不是必需的。 你可以一直在安全状态下运行 RT-Thread OS。

实际上,如果你不需要 TrustZone 提供的安全状态和非安全状态之间的隔离,或者不打算在非安全状态下运行任何代码,那么你可以简单地将整个系统配置为安全状态,并在该状态下运行操作系统。这种情况下,你不需要配置任何有关 TrustZone 的特定内容,系统将作为一个普通的单状态(只有安全状态)系统运行。

如果你使用了 TrustZone 并且需要在系统的非安全状态下运行某些代码,那么你需要在系统启动时配置 TrustZone 的相关设置,并实现从安全状态到非安全状态的切换逻辑。

总之,RT-Thread OS 作为一个灵活的实时操作系统,能够在 Cortex-M33 处理器的安全状态下运行,无论是独立于 TrustZone 特性,还是与 TrustZone 安全特性一起使用。具体配置和启动步骤应参考 RT-Thread OS 的文档和 Cortex-M33 的硬件手册。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

米贸搜|Facebook新手请查收!如何在FB上定位到B类受众?

一、确定目标受众和营销目标 在利用Facebook进行获客之前,B2B企业需要首先明确目标受众和营销目标。目标受众是指潜在的客户或合作伙伴,而营销目标可能是增加销量、提高品牌知名度、获取客户线索等。 Facebook的受众定位可以分成三大类:人口…

对象存储, 开源MinIO docker-compose.yml 文件

文章目录 python SDK 文档地址:docker-compose.yml 文件控制台使用:应用服务中使用样例: python SDK 文档地址: https://min.io/docs/minio/linux/developers/python/API.html docker-compose.yml 文件 version: 3services:min…

C语言中的浮点数存储

首先明确一个概念:C语言中整形是按照二进制存储在内存中,浮点型是按科学计数法存储在内存中(本质上存储的还是二进制数据0和1)。 如果没看懂这句话,没关系!看完以下正文,你就会豁然开朗&#x…

Qt简单使用与初识

🌇个人主页:平凡的小苏 📚学习格言:命运给你一个低的起点,是想看你精彩的翻盘,而不是让你自甘堕落,脚下的路虽然难走,但我还能走,比起向阳而生,我更想尝试逆风…

【汇编】pushf popf

两个指令的作用分别是将16位标志寄存器压入栈、从栈中取出,但是貌似没人做实验验证。 这里做个实验加深理解,顺便总结下几个标志寄存器的作用。 一、结构 8086CPU的flag寄存器的结构如下: OF:判断运算结果是否溢出 CF&#xff1…

VUE--组件的生命周期及其基本应用

VUE的生命周期 上图是实例生命周期的图表,需要注意以下几个重要时期: 创建期:beforeCreated、created 挂载期:beforeMount、mounted 更新期:beforeUpdate、updated 销毁期:beforeUnmount、unmounted 生命周…

蓝桥杯真题(Python)每日练Day2

题目 题目分析 对于本题首先确定其数据结构为优先队列,即邮费最小的衣服优先寄,算法符合贪心算法。可以直接使用queue库的PriorityQueue方法实现优先队列。关于PriorityQueue的使用方法主要有: import queue q queue.Queue()# 队列 pq qu…

JAVA实现向Word模板中插入Base64图片和数据信息

目录 需求一、准备模板文件二、引入Poi-tl、Apache POI依赖三、创建实体类(用于保存向Word中写入的数据)四、实现Service接口五、Controller层实现 需求 在服务端提前准备好Word模板文件,并在用户请求接口时服务端动态获取图片。数据等信息插…

代理IP是什么,代理IP的工作原理是怎么样的?

数字时代,随着数据采集的应用,代理IP也受到越来越多人的关注。但是,很多人对代理IP的具体概念及其工作原理并不是很了解。今天我们就来针对代理IP的相关知识做一个简单的探讨,说说代理IP是什么,它的工作原理又是什么&a…

redis未授权访问全漏洞复现

redis未授权访问全漏洞复现 Redis 有关的漏洞具有明显的时间分段性,在15年11月之前,主要是未授权导致的数据泄露,获得一些账号密码。另外还可以 DoS(参考:Sangfor VMP redis unauthorized access vulnerability&#…

VUE--组件通信(非父子)

一、非父子通信 --- event bus 事件总线 作用:非父子组件之间进行简易的消息传递 步骤: 1、创建一个都能访问到的事件总线(空vue实例)--- utils/EventBus.js import Vue from vue export default new Vue({}) 2、 接收方&…

mysql数据库:迁移数据目录至另一台服务器步骤

一、概述 最近由于项目需要,我们需要进行数据库服务器的更换和迁移工作。迁移计划和步骤如下: 1、首先,在新的数据库服务器上进行环境的搭建和配置,确保数据库版本、配置等一致。 2、然后,将备份的数据库数据导入到…

SpringBoot整合SSE

目录 1.SseController2. SseServiceSseServiceSseServiceImpl 3.SendMessageTask4.将定时任务加入启动类5.参考资料 1.SseController Slf4j RestController RequestMapping("sse") public class SseController {Autowiredprivate SseService sseService;RequestMappi…

【算法练习】leetcode算法题合集之二分查找篇

二分查找 LeetCode69.x的平方根 LeetCode69.x的平方根 只要小于等于就可以满足条件了。 class Solution {public int mySqrt(int x) {int left 0, right x;int ans -1;while (left < right) {int mid (right - left) / 2 left;if ((long) mid * mid < x) {ans mi…

为 OpenCV 编写文档(二)

常用命令 这里通过简短的示例描述了最常用的 doxygen 命令。有关可用命令的完整列表和详细说明&#xff0c;请访问命令参考。 基本命令 brief - 带有简要实体描述的段落 param - 函数参数的描述。 多个相邻语句合并到一个列表中。如果在实际函数签名中找不到具有此名称的参数…

2024潮乎新年盲盒H5版本可易支付对接

前端三十行和三十一行改成你域名 后台.env文件修改数据库 下载地址&#xff1a;YISHEN源码网

驾驭车联网的力量:深入车联网网络架构

车联网&#xff0c;作为移动互联网之后的新风口&#xff0c;以网联思想重新定义汽车&#xff0c;将其从简单的出行工具演化为个人的第二空间。车联网涵盖智能座舱和自动驾驶两大方向&#xff0c;构建在网联基础上&#xff0c;犀思云多年深度赋能汽车行业&#xff0c;本文将从车…

Qt通用属性工具:随心定义,随时可见(三)

传送门: 《Qt通用属性工具:随心定义,随时可见(一)》 《Qt通用属性工具:随心定义,随时可见(二)》 《Qt通用属性工具:随心定义,随时可见(三)》 一、效果展示 本文将展示的是一个源于Qt但是却有些年头的Qt属性浏览工具。支持交互式编辑和查阅对象属性。 这可不就是妥…

LeetCode、162. 寻找峰值【中等,最大值、二分】

文章目录 前言LeetCode、162. 寻找峰值【中等&#xff0c;最大值、二分】题目及类型思路及代码思路1&#xff1a;二分思路2&#xff1a;寻找最大值 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿…

Filter过滤器、使用场景、使用办法、创建和配置等

这里写目录标题 过滤器应用场景自动登录统一设置编码格式访问权限控制敏感字符过滤 Filter使用Filter的创建和配置 过滤器 过滤器实际上就是对 web资源进行拦截&#xff0c;做一些处理后再交给下一个过滤器或 servlet处理通常都是用来拦截request进行处理的&#xff0c;也可以…