GD32E10x bootloader踩坑记
typedef xt_void (*FUNC)(xt_void);
FUNC jumpAddr = NULL;
int main(void)
{
if (((*(volatile xt_u32 *)FLASH_APP_START_ADDR) & 0x2FFF0000) == 0x20000000) {
__disable_irq();
__set_MSP(*(volatile xt_u32 *)FLASH_APP_START_ADDR);
jumpAddr = (FUNC)(*(volatile xt_u32 *)(FLASH_APP_START_ADDR + 4));
jumpAddr();
} else {
printf("invalid stack addr:%#X\n", *(volatile xt_u32 *)FLASH_APP_START_ADDR);
return XERROR;
}
}
在system_gd32e10x.c库文件中定义使用的晶振是哪个
/* select a system clock by uncommenting the following line */
/* use IRC8M */
//#define __SYSTEM_CLOCK_IRC8M (uint32_t)(__IRC8M)
//#define __SYSTEM_CLOCK_48M_PLL_IRC8M (uint32_t)(48000000)
//#define __SYSTEM_CLOCK_72M_PLL_IRC8M (uint32_t)(72000000)
//#define __SYSTEM_CLOCK_108M_PLL_IRC8M (uint32_t)(108000000)
#define __SYSTEM_CLOCK_120M_PLL_IRC8M (uint32_t)(120000000)
/* use HXTAL(CK_HXTAL = 8M) */
//#define __SYSTEM_CLOCK_HXTAL (uint32_t)(__HXTAL)
//#define __SYSTEM_CLOCK_48M_PLL_HXTAL (uint32_t)(48000000)
//#define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000)
//#define __SYSTEM_CLOCK_108M_PLL_HXTAL (uint32_t)(108000000)
//#define __SYSTEM_CLOCK_120M_PLL_HXTAL (uint32_t)(120000000)
简直让人难过,应用程序使用的是__SYSTEM_CLOCK_120M_PLL_HXTAL
bootloader采用的是__SYSTEM_CLOCK_120M_PLL_IRC8M
所以无法跳转过去,上帝,忙了我一整天。
总结以下几个注意事项:
(1)bootloader和应用程序使用的外部晶振需要一样。
(2)需要正确设置flash下载地址,因为跳转之前需要设置栈指针,可执行文件bin中的前四字节表示栈顶指针
后四字节表示程序入口地址。跳转就是把程序入口地址给到PC指针,程序入口地址是复位中断后执行的
第一条指令,在ARM中通常是指SystemInit函数。所以从bootloader跳转到应用程序后,系统是会重新初始化的
相当于系统复位了一下。
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
(3)如果有采用分散加载,在分散加配制文件.scf中可以指定应用程序的起始地址,这个与在keil中进行设置效果是一样的。采用了分散加载后,程序是按.scf文件来指定flash启始地址,还是按keil中配制没试过。
(4)中断向量要设置正确,一般程序下载的flash地址,就是放置中断向量的地址。
(5)记得在设置栈之前把所有中断禁止__disable_irq();
(6)GD32芯片,中断向量设置时,它的flash地址必须满足0x200对齐,没仔细研究可能所有芯片都有这个限制。
(7)在设置新的栈指针后,局部变量的内容会被修改,如果需要保存一些内容,改用全局变量或者static修饰。