OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 97|回复: 0

从用户代码跳转到系统bootloader

[复制链接]

24

主题

24

帖子

0

精华

初级会员

Rank: 2

积分
99
金钱
99
注册时间
2024-12-9
在线时间
6 小时
发表于 2025-12-25 11:28:42 | 显示全部楼层 |阅读模式
从用户代码跳转到系统bootloader

前言
在AT32F4xx的memory map里面有一块启动程序代码区,里面存放的是系统的Bootloader。但如果要去执行系统Bootloader,必须要通过BOOT Pin去配置,通常是将BOOT0 拉高,BOOT1 拉低的方式。在实际使用中可能没有将BOOT Pin接出来,此时就不能够通过切换BOOTPin的方式去进入系统Bootloader。这里就提供一种直接从用户代码直接跳转到系统Bootloader的方法.

注:本应用笔记对应的代码是基于雅特力提供V2.x.x 板级支持包(BSP)而开发,对于其他版本BSP,需要注意使用上的区别。
支持型号列表:AT32全系列


1                 软件实现1.1           跳转到Bootloader的前提条件
从用户代码跳转到启动程序代码区去执行Bootloader之前必须执行以下操作:
1)     关闭所有外设时钟
2)     关闭PLL的使用
3)     禁用所有的中断
4)     清除所有挂起的中断标志位
这个过程我们有两种方式去实现:
1)     方式1:用代码清除以上4点之后直接执行跳转(这里需要根据客户代码开启的外设不同清除对应的Clock,PLL,Interrupt)
2)     方式2:用Reset的方式自动清除,Reset之后在SystemInit里面用户代码初始化之前跳转,用以保证以上4点能够满足
1.2           实现方式1
使用AT-START开发板设计一个用户程序APPJumpToBootloaderMethod1,程序主要完成一个LED操作,另外在检测一个用户按键,当按键按下之后就直接跳转到系统Bootloader(跳转之前需清除中断等信息),如果觉得在跳转之前要清除所有的Clock,中断等信息比较麻烦,可以参考方式2的实现,使用Reset自动清除。
1.2.1       方式1代码实现
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())
   
              {
   
                     /*清除Clock, PLL,    Interrupt*/
   
                     app_clear_sys_status    ();
   
                     app_jump_to_bootloader    ();
   
              }
   
              if(LedTimer    == LedTog)
   
              {
   
                     at32_led_toggle(LED4);
   
                     LedTimer    = 0;
   
              }
   
              LedTimer    ++;
   
       }
   
}


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();
   
}



app_clear_sys_status函数负责清除Clock,PLL,关闭Interrupt,和清除中断挂起标志


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 升级流程进行程序升级

备注:本文档仅作分享用,仅供有需求的小伙伴参考,如需详细操作步骤或资料,请访问雅特力官网获取:https://www.arterytek.com/cn/support/index.jsp?index=1

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-1-2 15:04

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表