修复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

物联沃分享整理
物联沃-IOTWORD物联网 » 修复STM32 Keil程序使用Ozone调试启动崩溃或时钟异常问题

发表回复