修复STM32 Keil程序使用Ozone调试启动崩溃或时钟异常问题
ozone在配置工程向导时会有如下选项,其中PC指针选项会影响Ozone调试,可能出现崩溃(带FPU的芯片会出现)或时钟异常等情况

1. ELF Entry Point(错误方法)
默认选择ELF Entry Point将PC指针跳转到ELF进入点,但ELF进入点并不是复位向量位置不会经过SystemInit导致浮点指令崩溃
工程脚本节选如下:
void _SetupTarget(void) {
unsigned int SP;
unsigned int PC;
unsigned int VectorTableAddr;
VectorTableAddr = Elf.GetBaseAddr();
//
// Set up initial stack pointer
//
SP = Target.ReadU32(VectorTableAddr);
if (SP != 0xFFFFFFFF) {
Target.SetReg("SP", SP);
}
//
// Set up entry point PC
//
PC = Elf.GetEntryPointPC();
if (PC != 0xFFFFFFFF) {
Target.SetReg("PC", PC);
} else {
Util.Error("Project script error: failed to set up entry point PC", 1);
}
}
启动过程日志如下:
Elf.GetBaseAddr(); // returns 0x8000000
Target.ReadU32 (0x08000000); // returns 0x4, data is 0x24000678
Target.SetReg ("SP", 0x24000678);
Elf.GetEntryPointPC(); // returns 0x8000298
Target.SetReg ("PC", 0x8000298);
崩溃信息:

2. Read From Base Address Vector Table(正确方法)
该选项使用中断向量表中的复位向量配置PC指针,可以直接定位到复位向量上运行,和正常启动方式一致
如果启动后有时钟不正常问题,则可能是下载程序后没有正常复位导致RCC配置失败,在工程脚本中AfterTargetDownload函数第一行加入Exec.Reset();使其下载后能执行复位动作。修改完成需重新加载工程。
工程脚本节选如下:
void AfterTargetDownload (void) {
Util.Log("After Download Reset");
// Exec.Reset(); // 可选
_SetupTarget();
}
void _SetupTarget(void) {
unsigned int SP;
unsigned int PC;
unsigned int VectorTableAddr;
VectorTableAddr = Elf.GetBaseAddr();
//
// Set up initial stack pointer
//
SP = Target.ReadU32(VectorTableAddr);
if (SP != 0xFFFFFFFF) {
Target.SetReg("SP", SP);
}
//
// Set up entry point PC
//
PC = Target.ReadU32(VectorTableAddr + 4);
if (PC != 0xFFFFFFFF) {
Target.SetReg("PC", PC);
} else {
Util.Error("Project script error: failed to set up entry point PC", 1);
}
}
启动日志如下:
Elf.GetBaseAddr(); // returns 0x8000000
Target.ReadU32 (0x08000000); // returns 0x4, data is 0x24000678
Target.SetReg ("SP", 0x24000678);
Target.ReadU32 (0x08000004); // returns 0x4, data is 0x8000339
Target.SetReg ("PC", 0x8000339);
可见复位向量为0x8000339指向Reset_Handler,而第一种方法获取的地址为0x8000298指向__main是错误的
查看启动脚本可确认Reset_Handler中__main位于SystemInit之后调用,故第一种方法遗漏FPU初始化
; Reset handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT SystemInit IMPORT __main LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP
关于GCC
gcc编译器的ELF入口位置就是Reset_Handler(参考链接脚本),所以不存在Keil程序的跳过SystemInit问题,但依然可能存在时钟异常问题
作者:qq_25014669