从闪存启动时的 STM32 HardFault
STM32 HardFault when booted from Flash
我有一个简单的 STM32F103 ARM 芯片裸机程序(我使用 GNU 工具链和 openocd 调试器)。
当我从 RAM 运行 它工作正常。当我使用预装的引导加载程序引导芯片并直接跳转到闪存中的 Reset_Handler
位置时,它也可以工作。但是当我尝试从闪存启动时,处理器进入 HardFault 模式。
处理器复位后,pc
寄存器立即指向 Reset_Handler
位置。当我迈出一步时,如果落入Hardfault_Handler
.
为什么会这样?我怀疑这是一个糟糕的内存访问,但一切似乎都是一致的。
汇编代码:
.syntax unified
.cpu cortex-m3
.arch armv7-m
.fpu softvfp
.thumb
.section .text
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.align 4
Reset_Handler:
mov r0, #0
mov r1, #0
mov r2, #0
b Reset_Handler
.section .vector,"a",%progbits
.type Vectors, %object
.size Vectors, .-Vectors
Vectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
.word WWDG_IRQHandler
.word PVD_IRQHandler
.word TAMPER_IRQHandler
.word RTC_IRQHandler
.word FLASH_IRQHandler
.word RCC_IRQHandler
.word EXTI0_IRQHandler
.word EXTI1_IRQHandler
.word EXTI2_IRQHandler
.word EXTI3_IRQHandler
.word EXTI4_IRQHandler
.word DMA1_Channel1_IRQHandler
.word DMA1_Channel2_IRQHandler
.word DMA1_Channel3_IRQHandler
.word DMA1_Channel4_IRQHandler
.word DMA1_Channel5_IRQHandler
.word DMA1_Channel6_IRQHandler
.word DMA1_Channel7_IRQHandler
.word ADC1_2_IRQHandler
.word USB_HP_CAN1_TX_IRQHandler
.word USB_LP_CAN1_RX0_IRQHandler
.word CAN1_RX1_IRQHandler
.word CAN1_SCE_IRQHandler
.word EXTI9_5_IRQHandler
.word TIM1_BRK_IRQHandler
.word TIM1_UP_IRQHandler
.word TIM1_TRG_COM_IRQHandler
.word TIM1_CC_IRQHandler
.word TIM2_IRQHandler
.word TIM3_IRQHandler
.word 0
.word I2C1_EV_IRQHandler
.word I2C1_ER_IRQHandler
.word 0
.word 0
.word SPI1_IRQHandler
.word 0
.word USART1_IRQHandler
.word USART2_IRQHandler
.word 0
.word EXTI15_10_IRQHandler
.word RTC_Alarm_IRQHandler
.word USBWakeUp_IRQHandler
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
b Reset_Handler
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak DebugMon_Handler
.thumb_set DebugMon_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
.weak TAMPER_IRQHandler
.thumb_set TAMPER_IRQHandler,Default_Handler
.weak RTC_IRQHandler
.thumb_set RTC_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_IRQHandler
.thumb_set EXTI0_IRQHandler,Default_Handler
.weak EXTI1_IRQHandler
.thumb_set EXTI1_IRQHandler,Default_Handler
.weak EXTI2_IRQHandler
.thumb_set EXTI2_IRQHandler,Default_Handler
.weak EXTI3_IRQHandler
.thumb_set EXTI3_IRQHandler,Default_Handler
.weak EXTI4_IRQHandler
.thumb_set EXTI4_IRQHandler,Default_Handler
.weak DMA1_Channel1_IRQHandler
.thumb_set DMA1_Channel1_IRQHandler,Default_Handler
.weak DMA1_Channel2_IRQHandler
.thumb_set DMA1_Channel2_IRQHandler,Default_Handler
.weak DMA1_Channel3_IRQHandler
.thumb_set DMA1_Channel3_IRQHandler,Default_Handler
.weak DMA1_Channel4_IRQHandler
.thumb_set DMA1_Channel4_IRQHandler,Default_Handler
.weak DMA1_Channel5_IRQHandler
.thumb_set DMA1_Channel5_IRQHandler,Default_Handler
.weak DMA1_Channel6_IRQHandler
.thumb_set DMA1_Channel6_IRQHandler,Default_Handler
.weak DMA1_Channel7_IRQHandler
.thumb_set DMA1_Channel7_IRQHandler,Default_Handler
.weak ADC1_2_IRQHandler
.thumb_set ADC1_2_IRQHandler,Default_Handler
.weak USB_HP_CAN1_TX_IRQHandler
.thumb_set USB_HP_CAN1_TX_IRQHandler,Default_Handler
.weak USB_LP_CAN1_RX0_IRQHandler
.thumb_set USB_LP_CAN1_RX0_IRQHandler,Default_Handler
.weak CAN1_RX1_IRQHandler
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
.weak CAN1_SCE_IRQHandler
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
.weak EXTI9_5_IRQHandler
.thumb_set EXTI9_5_IRQHandler,Default_Handler
.weak TIM1_BRK_IRQHandler
.thumb_set TIM1_BRK_IRQHandler,Default_Handler
.weak TIM1_UP_IRQHandler
.thumb_set TIM1_UP_IRQHandler,Default_Handler
.weak TIM1_TRG_COM_IRQHandler
.thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM2_IRQHandler
.thumb_set TIM2_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak I2C1_EV_IRQHandler
.thumb_set I2C1_EV_IRQHandler,Default_Handler
.weak I2C1_ER_IRQHandler
.thumb_set I2C1_ER_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler
.weak EXTI15_10_IRQHandler
.thumb_set EXTI15_10_IRQHandler,Default_Handler
.weak RTC_Alarm_IRQHandler
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
.weak USBWakeUp_IRQHandler
.thumb_set USBWakeUp_IRQHandler,Default_Handler
.end
RAM 链接描述文件:
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
MEMORY {
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20k
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64k
}
_estack = 0x20004FFF;
SECTIONS {
.isr_vector : {
. = ALIGN(4);
KEEP(*(.vector))
. = ALIGN(8);
} > RAM
.text : {
. = ALIGN(4);
*(.text)
} > RAM
}
Flash 链接描述文件:
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
MEMORY {
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20k
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64k
}
_estack = 0x20004FFF;
SECTIONS {
.isr_vector : {
. = ALIGN(4);
KEEP(*(.vector))
. = ALIGN(8);
} > FLASH
.text : {
. = ALIGN(4);
*(.text)
} > FLASH
}
.text
部分的反汇编:
08000110 <ADC1_2_IRQHandler>:
8000110: e7fe b.n 8000110 <ADC1_2_IRQHandler>
8000112: bf00 nop
8000114: f3af 8000 nop.w
8000118: f3af 8000 nop.w
800011c: f3af 8000 nop.w
08000120 <Reset_Handler>:
8000120: f04f 0000 mov.w r0, #0
8000124: f04f 0100 mov.w r1, #0
8000128: f04f 0200 mov.w r2, #0
800012c: e7f8 b.n 8000120 <Reset_Handler>
800012e: bf00 nop
.isr_vector
部分的反汇编(部分):
08000000 <Vectors>:
8000000: 20004fff strdcs r4, [r0], -pc ; <UNPREDICTABLE>
8000004: 08000120 stmdaeq r0, {r5, r8}
8000008: 08000111 stmdaeq r0, {r0, r4, r8}
800000c: 08000111 stmdaeq r0, {r0, r4, r8}
8000010: 08000111 stmdaeq r0, {r0, r4, r8}
...
8000108: 08000111 stmdaeq r0, {r0, r4, r8}
800010c: 00000000 andeq r0, r0, r0
您的错误在链接描述文件中:
_estack = 0x20004FFF;
由于该值在向量 table 中使用不变,因此 SP 将被初始化为一个奇数值。但是 ARM 规范实际上指定 SP 可以被 8 整除(对齐到 8 字节)。
奇数在第一次使用栈时触发错误
修复很简单:
_estack = 0x20005000;
编辑:
向量中有更多错误table:
8000004: 08000120 stmdaeq r0, {r5, r8}
8000008: 08000111 stmdaeq r0, {r0, r4, r8}
8000004
处的"reset handler"应该是08000121
,但实际上是08000120
。这是无效的 - 最后一位 必须 设置为 thumb 指令集。
一旦将此值加载到 PC 中,这将在执行第一条指令之前触发复位故障。
原因是缺少声明:
.type Reset_Handler, %function
在我使用的汇编程序启动文件中还有一些声明:
.text
.thumb
.thumb_func
.align 1
.globl Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* code here ..*/
我有一个简单的 STM32F103 ARM 芯片裸机程序(我使用 GNU 工具链和 openocd 调试器)。
当我从 RAM 运行 它工作正常。当我使用预装的引导加载程序引导芯片并直接跳转到闪存中的 Reset_Handler
位置时,它也可以工作。但是当我尝试从闪存启动时,处理器进入 HardFault 模式。
处理器复位后,pc
寄存器立即指向 Reset_Handler
位置。当我迈出一步时,如果落入Hardfault_Handler
.
为什么会这样?我怀疑这是一个糟糕的内存访问,但一切似乎都是一致的。
汇编代码:
.syntax unified
.cpu cortex-m3
.arch armv7-m
.fpu softvfp
.thumb
.section .text
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.align 4
Reset_Handler:
mov r0, #0
mov r1, #0
mov r2, #0
b Reset_Handler
.section .vector,"a",%progbits
.type Vectors, %object
.size Vectors, .-Vectors
Vectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
.word WWDG_IRQHandler
.word PVD_IRQHandler
.word TAMPER_IRQHandler
.word RTC_IRQHandler
.word FLASH_IRQHandler
.word RCC_IRQHandler
.word EXTI0_IRQHandler
.word EXTI1_IRQHandler
.word EXTI2_IRQHandler
.word EXTI3_IRQHandler
.word EXTI4_IRQHandler
.word DMA1_Channel1_IRQHandler
.word DMA1_Channel2_IRQHandler
.word DMA1_Channel3_IRQHandler
.word DMA1_Channel4_IRQHandler
.word DMA1_Channel5_IRQHandler
.word DMA1_Channel6_IRQHandler
.word DMA1_Channel7_IRQHandler
.word ADC1_2_IRQHandler
.word USB_HP_CAN1_TX_IRQHandler
.word USB_LP_CAN1_RX0_IRQHandler
.word CAN1_RX1_IRQHandler
.word CAN1_SCE_IRQHandler
.word EXTI9_5_IRQHandler
.word TIM1_BRK_IRQHandler
.word TIM1_UP_IRQHandler
.word TIM1_TRG_COM_IRQHandler
.word TIM1_CC_IRQHandler
.word TIM2_IRQHandler
.word TIM3_IRQHandler
.word 0
.word I2C1_EV_IRQHandler
.word I2C1_ER_IRQHandler
.word 0
.word 0
.word SPI1_IRQHandler
.word 0
.word USART1_IRQHandler
.word USART2_IRQHandler
.word 0
.word EXTI15_10_IRQHandler
.word RTC_Alarm_IRQHandler
.word USBWakeUp_IRQHandler
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
b Reset_Handler
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak DebugMon_Handler
.thumb_set DebugMon_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
.weak TAMPER_IRQHandler
.thumb_set TAMPER_IRQHandler,Default_Handler
.weak RTC_IRQHandler
.thumb_set RTC_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_IRQHandler
.thumb_set EXTI0_IRQHandler,Default_Handler
.weak EXTI1_IRQHandler
.thumb_set EXTI1_IRQHandler,Default_Handler
.weak EXTI2_IRQHandler
.thumb_set EXTI2_IRQHandler,Default_Handler
.weak EXTI3_IRQHandler
.thumb_set EXTI3_IRQHandler,Default_Handler
.weak EXTI4_IRQHandler
.thumb_set EXTI4_IRQHandler,Default_Handler
.weak DMA1_Channel1_IRQHandler
.thumb_set DMA1_Channel1_IRQHandler,Default_Handler
.weak DMA1_Channel2_IRQHandler
.thumb_set DMA1_Channel2_IRQHandler,Default_Handler
.weak DMA1_Channel3_IRQHandler
.thumb_set DMA1_Channel3_IRQHandler,Default_Handler
.weak DMA1_Channel4_IRQHandler
.thumb_set DMA1_Channel4_IRQHandler,Default_Handler
.weak DMA1_Channel5_IRQHandler
.thumb_set DMA1_Channel5_IRQHandler,Default_Handler
.weak DMA1_Channel6_IRQHandler
.thumb_set DMA1_Channel6_IRQHandler,Default_Handler
.weak DMA1_Channel7_IRQHandler
.thumb_set DMA1_Channel7_IRQHandler,Default_Handler
.weak ADC1_2_IRQHandler
.thumb_set ADC1_2_IRQHandler,Default_Handler
.weak USB_HP_CAN1_TX_IRQHandler
.thumb_set USB_HP_CAN1_TX_IRQHandler,Default_Handler
.weak USB_LP_CAN1_RX0_IRQHandler
.thumb_set USB_LP_CAN1_RX0_IRQHandler,Default_Handler
.weak CAN1_RX1_IRQHandler
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
.weak CAN1_SCE_IRQHandler
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
.weak EXTI9_5_IRQHandler
.thumb_set EXTI9_5_IRQHandler,Default_Handler
.weak TIM1_BRK_IRQHandler
.thumb_set TIM1_BRK_IRQHandler,Default_Handler
.weak TIM1_UP_IRQHandler
.thumb_set TIM1_UP_IRQHandler,Default_Handler
.weak TIM1_TRG_COM_IRQHandler
.thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM2_IRQHandler
.thumb_set TIM2_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak I2C1_EV_IRQHandler
.thumb_set I2C1_EV_IRQHandler,Default_Handler
.weak I2C1_ER_IRQHandler
.thumb_set I2C1_ER_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler
.weak EXTI15_10_IRQHandler
.thumb_set EXTI15_10_IRQHandler,Default_Handler
.weak RTC_Alarm_IRQHandler
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
.weak USBWakeUp_IRQHandler
.thumb_set USBWakeUp_IRQHandler,Default_Handler
.end
RAM 链接描述文件:
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
MEMORY {
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20k
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64k
}
_estack = 0x20004FFF;
SECTIONS {
.isr_vector : {
. = ALIGN(4);
KEEP(*(.vector))
. = ALIGN(8);
} > RAM
.text : {
. = ALIGN(4);
*(.text)
} > RAM
}
Flash 链接描述文件:
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
MEMORY {
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20k
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64k
}
_estack = 0x20004FFF;
SECTIONS {
.isr_vector : {
. = ALIGN(4);
KEEP(*(.vector))
. = ALIGN(8);
} > FLASH
.text : {
. = ALIGN(4);
*(.text)
} > FLASH
}
.text
部分的反汇编:
08000110 <ADC1_2_IRQHandler>:
8000110: e7fe b.n 8000110 <ADC1_2_IRQHandler>
8000112: bf00 nop
8000114: f3af 8000 nop.w
8000118: f3af 8000 nop.w
800011c: f3af 8000 nop.w
08000120 <Reset_Handler>:
8000120: f04f 0000 mov.w r0, #0
8000124: f04f 0100 mov.w r1, #0
8000128: f04f 0200 mov.w r2, #0
800012c: e7f8 b.n 8000120 <Reset_Handler>
800012e: bf00 nop
.isr_vector
部分的反汇编(部分):
08000000 <Vectors>:
8000000: 20004fff strdcs r4, [r0], -pc ; <UNPREDICTABLE>
8000004: 08000120 stmdaeq r0, {r5, r8}
8000008: 08000111 stmdaeq r0, {r0, r4, r8}
800000c: 08000111 stmdaeq r0, {r0, r4, r8}
8000010: 08000111 stmdaeq r0, {r0, r4, r8}
...
8000108: 08000111 stmdaeq r0, {r0, r4, r8}
800010c: 00000000 andeq r0, r0, r0
您的错误在链接描述文件中:
_estack = 0x20004FFF;
由于该值在向量 table 中使用不变,因此 SP 将被初始化为一个奇数值。但是 ARM 规范实际上指定 SP 可以被 8 整除(对齐到 8 字节)。
奇数在第一次使用栈时触发错误
修复很简单:
_estack = 0x20005000;
编辑:
向量中有更多错误table:
8000004: 08000120 stmdaeq r0, {r5, r8}
8000008: 08000111 stmdaeq r0, {r0, r4, r8}
8000004
处的"reset handler"应该是08000121
,但实际上是08000120
。这是无效的 - 最后一位 必须 设置为 thumb 指令集。
一旦将此值加载到 PC 中,这将在执行第一条指令之前触发复位故障。
原因是缺少声明:
.type Reset_Handler, %function
在我使用的汇编程序启动文件中还有一些声明:
.text
.thumb
.thumb_func
.align 1
.globl Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* code here ..*/