void app_clear_sys_status()
{
/*Close Peripherals Clock*/
CRM->apb2rst = 0xFFFF;
CRM->apb2rst = 0;
CRM->apb1rst = 0xFFFF;
CRM->apb1rst = 0;
CRM->apb1en = 0;
CRM->apb2en = 0;
/*Close PLL*/
/* Reset SW, AHBDIV, APB1DIV, APB2DIV, ADCDIV and CLKOUT_SEL bits */
CRM->cfg_bit.sclksel = 0;
CRM->cfg_bit.ahbdiv = 0;
CRM->cfg_bit.apb1div = 0;
CRM->cfg_bit.apb2div = 0;
CRM->cfg_bit.adcdiv_l = 0;
CRM->cfg_bit.adcdiv_h = 0;
CRM->cfg_bit.clkout_sel = 0;
CRM->ctrl_bit.hexten = 0;
CRM->ctrl_bit.cfden = 0;
CRM->ctrl_bit.pllen = 0;
CRM->cfg_bit.pllrcs = 0;
CRM->cfg_bit.pllhextdiv = 0;
CRM->cfg_bit.pllmult_l = 0;
CRM->cfg_bit.pllmult_h = 0;
CRM->cfg_bit.usbdiv_l = 0;
CRM->cfg_bit.usbdiv_h = 0;
CRM->cfg_bit.pllrange = 0;
/* Disable all interrupts and clear pending bits */
CRM->clkint_bit.lickstblfc = 0;
CRM->clkint_bit.lextstblfc = 0;
CRM->clkint_bit.hickstblfc = 0;
CRM->clkint_bit.hextstblfc = 0;
CRM->clkint_bit.pllstblfc = 0;
CRM->clkint_bit.cfdfc = 0;
/*Colse Systick*/
SysTick->CTRL = 0;
/*Disable ALL interrupt && Pending Interrupt Flag*/
/*这里需要根据用户开启的外设进行清除中断和挂起的中断标志*/
/*
user add code...
*/
}
1.3 实现方法2
实现方法2,即使用reset的方式,在SystemInit初始化用户代码之前跳转。
我们使用AT-START开发板设计了一个用户程序的APPJumpToBootloaderMethod2,程序主要完成了一个LED的操作,另外通过检测一个用户按键,但按下按键的时候,表示要从用户程序进入系统Bootloader,此时会在后备寄存器BPR_DATA1中写入0x5AA5。然后产生软件复位,软件复位后在SystemInit开始的地方去判断BPR_DATA1是否为0x5AA5,并将BPR_DATA1清0, 如果是就会进入跳转到Bootloader的程序。这里在进入SystemInit开始的地方就进行跳转,是为了防止用户Code初始化之后和系统Bootloader的配置不匹配。
1.3.1 方式2代码实现
main函数主要是一个闪灯和检测按键,通过按键按下表示需要进入系统Bootloader。
int main(void) { uint32_t LedTimer = 0, LedTog = 0; system_clock_config(); at32_board_init(); LedTog = system_core_clock/80; while(1) { if(USER_BUTTON == at32_button_press()) { /*保存BPR一个状态标志,表示APP需要跳转到Bootloader */ BPR_Write_Flag(); } if ( LedTimer == LedTog) { at32_led_toggle(LED4);; LedTimer = 0; } LedTimer ++; } } |
bpr_write_flag函数主要是写一个跳转标志到BPR_DATA1中,并进行软件复位
void bpr_write_flag (void) { /* enable pwc and bpr clock */ crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);
/* enable write access to bpr domain */ pwc_battery_powered_domain_access(TRUE);
/* clear tamper pin event pending flag */ bpr_flag_clear(BPR_TAMPER_EVENT_FLAG);
bpr_data_write(BPR_DATA1, BKP_JUMP_FLAG);
pwc_battery_powered_domain_access(FALSE);
/*System Reset*/ NVIC_SystemReset(); } |
bpr_check_flag函数主要是在reset之后判断是否要跳转到系统bootloader,返回1 表示要跳转到bootloader,0表示不跳转
uint8_t bpr_check_flag (void) { uint8_t ret_val = 0; /* enable pwc and bpr clock */ crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);
/* enable write access to bpr domain */ pwc_battery_powered_domain_access(TRUE);
/* clear tamper pin event pending flag */ bpr_flag_clear(BPR_TAMPER_EVENT_FLAG);
if(bpr_data_read(BPR_DATA1) == BPR_JUMP_FLAG) { bpr_data_write(BPR_DATA1, 0x00); //write 00 to bkp ret_val = 1; }
pwc_battery_powered_domain_access(FALSE); crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, FALSE); crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, FALSE); return ret_val; } |
app_jump_to_bootloader函数负责跳转到Bootloader
void app_jump_to_bootloader (void) { uint32_t dwStkPtr, dwJumpAddr; dwStkPtr = *(uint32_t *)BOOTLOADER_ADDRESS; dwJumpAddr = *(uint32_t *)(BOOTLOADER_ADDRESS + sizeof(uint32_t));
/*跳转之前,需要保证所有外设Clock 关闭,PLL 关闭,关闭所有中断,清除所有的中断挂起标志*/ SET_MSP(dwStkPtr); pfTarget = (void (*)(void))dwJumpAddr; pfTarget();
} |
SystemInit中,在用户代码初始化之前,判断是否需要跳转到系统Bootloader。
void SystemInit (void) { #if defined (__FPU_USED) && (__FPU_USED == 1U) SCB->CPACR |= ((3U << 10U * 2U) | /* set cp10 full access */ (3U << 11U * 2U) ); /* set cp11 full access */ #endif
/*check if need to go into bootloader*/ if(bpr_check_flag () == 1) { app_jump_to_bootloader (); }
/* reset the crm clock configuration to the default reset state(for debug purpose) */ /* set hicken bit */ CRM->ctrl_bit.hicken = TRUE;… } |
2 使用用户代码跳转Bootloader实验
实验使用AT-STAT-F403AV1.0开发板,使用DFU的方式进行升级(串口升级流程相同)
1. 下载APPJumpToBootloaderMethod1或者APPJumpToBootloaderMethod2程序到AT-START-F403A V1.0开发板
2. 可以看到LED3闪烁
3. 按下PB2USER 按键,此时LED3熄灭,表示已经进入系统Bootloader
4. 插拔AT-STAT-F403AV1.0 上的USB
5. 打开ArteryISP Programmer,可以看到一个USB DFU的设备已经连接上
6. 之后可以按照正常的ISP 升级流程进行程序升级