在验证一个RAM中执行函数时,遇到了MCU进入Hardfault错误的问题。
代码载入内存地址0x20003000之后,使用函数指针的方式跳转:
typedef int (*func_call)(int, char **);
void call_ram_func(void)
{
uint32_t *fun_base;
func_call func;
int argc = 2;
char *argv[] = {""};
fun_base = (uint32_t*)0x20003080;
func = (func_call)(fun_base);
func(argc,argv);
}
上述代码在汇编级单步调试的时候,运行正常,一旦全速运行后,程序只要执行到func(argc,argv)就会进入Hardfault。最后在一步一步分析汇编的时候,发现跳转的地址0x20003080有端倪,联想到Thumb指令集与ARM指令集的区别时才恍然大悟,指令LSB即最低有效位为0时是ARM指令,为1时是Thumb代码,这里0x20003080显然被识别为ARM指令了,而整个程序使用Thumb指令集编译的,执行这条指令之前,MCU也一直处于Thumb状态,突然执行一条ARM指令所以出现了错误。明白了问题,解决办法很简单,代码按照以下方式修正:
typedef int (*func_call)(int, char **);
void call_ram_func(void)
{
uint32_t *fun_base;
func_call func;
int argc = 2;
char *argv[] = {""};
fun_base = (uint32_t*)(0x20003080 + 0x1);
func = (func_call)(fun_base);
func(argc,argv);
}
将调用地址最低位置为1,跳转的地址就变成了Thumb指令了,再次运行一切恢复正常。
至于汇编级调试时正常,全速跑时却出现Hardfault异常的问题,有前辈解释是由于单步调试时调试器会对指令进行修正,所以错误的指令会被修正,全速运行时,没有调试器的参与,MCU就异常了。
具体可参见https://bbs.21ic.com/icview-134389-999-1.html的讨论。