请阅读【嵌入式开发学习必备专栏 之 ARM Cortex-Mx专栏】
rt-thread 在PendSV_Handler
退出的时候发生了HardFault_Handler
是什么原因?且 LR 的值为0xfffffffd
在 ARM Cortex-M 架构中,堆栈指针 (SP) 必须始终保持 8 字节对齐。这是因为从 ARMv7-M 开始,堆栈帧可能包含额外的浮点寄存器,而要求 8 字节对齐以实现更有效的访问和与浮点寄存器大小相一致。
在进入异常处理时,处理器会自动将 xPSR
、返回地址、LR
、R12
、R3
、R2
、R1
和 R0
压入堆栈;如果使用浮点单元且由异常激活,则还会压入 S0-S15
和 FPSCR
寄存器。
当从异常返回时,处理器会根据 LR 中的
EXC_RETURN
值来检查堆栈指针,以确保正确地恢复寄存器状态。
发生 HardFault
的原因可能很多,但当你看到 LR
(链接寄存器)的值为 0xFFFFFFFD
时,这表明异常返回时处理器试图从进程堆栈指针(PSP)恢复上下文。这个特定的 EXC_RETURN
值意味着在从异常(这种情况下是 PendSV)返回时,发生了与堆栈或上下文恢复有关的问题。
以下是一些可能导致你在 PendSV_Handler
退出时遭遇 HardFault
的原因:
PendSV_Handler
时,必须保存当前任务的上下文,包括所有必要的寄存器。如果保存过程中出错,或者未能保存足够的寄存器状态,那么恢复这些寄存器时会遇到问题。xPSR
)的值不正确,那么在尝试返回到这些地址时会触发 HardFault
。LR
的值是正确的 EXC_RETURN
,但如果在异常处理的汇编代码中有错误,可能会导致错误的堆栈操作或错误的异常返回。为了调试此 HardFault
,可以采取以下步骤:
HardFault_Handler
中,检查 PSP 是否指向有效的内存区域。PendSV_Handler
中的代码,观察 PSP
、PC
和 xPSR
的值以及它们的变化。HardFault_Handler
:实现一个 HardFault_Handler
来捕获硬件错误,从中可以读取更多的系统状态和错误信息,例如配置故障状态寄存器 CFSR
、HFSR
、MMFAR
和 BFAR
。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
ARM Cortex-M33 处理器是 ARMv8-M 架构的一部分,可选地包含一个符合 IEEE 754 标准的单精度浮点单元 (FPU),支持所有单精度浮点数据类型的运算。包含 FPU 的 Cortex-M33 可以提高浮点计算的性能,适用于需要执行大量浮点计算的应用程序。
Cortex-M33 的 FPU 支持以下特性:
如果选择在 Cortex-M33 上使用 FPU 功能,需要使用 -mfloat-abi=hard
或 -mfloat-abi=softfp
编译器选项来启用硬件浮点支持。这些选项会使编译器产生使用 FPU 的代码,并链接到相应的浮点库。
Q:cortex-m33默认安全状态下如何启动rt-thread os,需要配置哪些内容? 可以一直在安全状态下运行os吗?
A: 要在 Cortex-M33 默认的安全状态下启动 RT-Thread OS,需要执行一系列的初始化步骤来配置处理器,启动操作系统,并确保操作系统及其任务在安全状态下正确运行。
下面是一般需要执行的步骤:
rt_system_scheduler_init
初始化调度器,rt_system_timer_init
初始化系统定时器等。rt_thread_create
,来创建并初始化操作系统任务。rt_system_scheduler_start
来启动 RT-Thread 的调度器。实际上,如果你不需要 TrustZone 提供的安全状态和非安全状态之间的隔离,或者不打算在非安全状态下运行任何代码,那么你可以简单地将整个系统配置为安全状态,并在该状态下运行操作系统。这种情况下,你不需要配置任何有关 TrustZone 的特定内容,系统将作为一个普通的单状态(只有安全状态)系统运行。
如果你使用了 TrustZone 并且需要在系统的非安全状态下运行某些代码,那么你需要在系统启动时配置 TrustZone 的相关设置,并实现从安全状态到非安全状态的切换逻辑。
总之,RT-Thread OS 作为一个灵活的实时操作系统,能够在 Cortex-M33 处理器的安全状态下运行,无论是独立于 TrustZone 特性,还是与 TrustZone 安全特性一起使用。具体配置和启动步骤应参考 RT-Thread OS 的文档和 Cortex-M33 的硬件手册。