下面是Bootloader代码,按下按键(引脚电平为低)进入bootloader命令界面;按键不按下,跳转到APP。
int main(void)
{
// col = R;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
printmsg("iap version 0.1\r\n");
// red and green led off
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_SET);
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==GPIO_PIN_RESET){
// jump to bootloader / red led on
printmsg("jump to bootloader!\r\n");
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_RESET);
jump_to_bootloader();
}
else{
// jump to application / green led on
printmsg("jump to application!\r\n");
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_RESET);
jump_to_application();
}
}
下面是跳转到APP的代码:
/**
* @brief 跳转到用户application,执行用户程序。
*
*/
void jump_to_application(void)
{
int i = 0;
void (*application_reset_handler)(void);
uint32_t msp_value = *(volatile uint32_t*)APP_FLASH_BASE_ADDRESS;
printmsg("MSP value : %#x\r\n",msp_value);
uint32_t reset_handller_address = *(volatile uint32_t *)(APP_FLASH_BASE_ADDRESS+4);
application_reset_handler = (void *)reset_handller_address;
__set_MSP(msp_value);
printmsg("application reset handler address : %#x\r\n",application_reset_handler);
application_reset_handler();
}
APP 代码为:
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init(); MX_USART1_UART_Init();
while (1)
{
printmsg("hello world!\r\n");
uint32_t current_tick = HAL_GetTick();
while(HAL_GetTick()<=current_tick+1000);
}
}
经排查,发现是jump_to_bootloader()中调用了HAL_FLASHX_Erase()函数导致无法跳转,HAL_FLASHX_Erase()中__HAL_LOCK(&pFlash)中使用到了枚举类型进行比较,这个比较导致APP无法正常运行。
注释掉jump_to_bootloader(),APP可以循环打印“hello world!”。
为了模拟现象,在Bootloader程序中创建enum对象,并对其赋值:
typedef enum {
R=0,
G,
B
} COLOR;
typedef struct
{
/* data */
COLOR c;
} _COLOR;
COLOR col;
_COLOR _col;
int main(void)
{
col = R; // ******** 这里赋值
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
printmsg("iap version 0.1\r\n");
// red and green led off
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_SET);
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==GPIO_PIN_RESET){
// jump to bootloader / red led on
printmsg("jump to bootloader!\r\n");
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_RESET);
//jump_to_bootloader();
}
else{
// jump to application / green led on
printmsg("jump to application!\r\n");
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_RESET);
jump_to_application();
}
}
这样就跳转到APP后就只打印一次“hello world!”,然后卡在while中,调试发现HAL_GetTick()一直等于0。
[md]你改的偏移是灰色的,因为他上一级`/* #define USER_VECT_TAB_ADDRESS */`这个宏定义你要打开,就在你截图上面没截到的地方就是 把注释去掉试试
[md]
添加宏定义后OK了,感谢大佬帮助。
在从IAP区跳转到APP前,保证将刚才使能的中断都禁用掉,比方你开启过的UART中断、定时器中断啊什么的,
都逐个将其中断使能位清零,当然直接对外设做复位也可以殊途同归。
另外,基于ST库组织的代码的话,那个systick定时器默认使能并启用了相关中断,记得跳转前将其中断使能
禁用或令其停止计数操作。下面三个操作任一个都可以达到目的。
SysTick->CTRL &=~SysTick_CTRL_TICKINT_Msk;
SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk
SysTick->LOAD = 0 ;
具体到这里 ,跳转过去后 是否发生了因中断优先级问题导致互斥现象。
不知你的Printmsg具体实现,你先屏蔽它看看。 当然前面提到的跳转前
的准备工作要先做足。
需要把你APP初始化是怎么做的放出来
上面就是APP的全部内容,但是我修改了flash的偏移地址,原本是0x00000000,修改为:0x00010000
APP的target配置: