BootLoader代码解析

本文详细解析了BootLoader的代码,包括从Flash复制到SRAM,零填充.BSS段,设置向量表,检查更新,配置硬件,并跳转到应用程序的过程。还讨论了BootLoader如何判断和处理强制更新的情况,以及BootLoader执行流程的关键步骤。

 

ProcessorInit
    ;
    ; Copy the code image from flash to SRAM.
    ;
    movs    r0, #0x0000
    movs    r1, #0x0000
    movt    r1, #0x2000--->movt把0x2000放到r1的高16bit


    import  ||Image$$SRAM$$ZI$$Base||--->.BSS段的开始地址
    ldr     r2, =||Image$$SRAM$$ZI$$Base||
copy_loop
        ldr     r3, [r0], #4
        str     r3, [r1], #4
        cmp     r1, r2
        blt     copy_loop

    ;
    ; Zero fill the .bss section.
    ;
    movs    r0, #0x0000
    import  ||Image$$SRAM$$ZI$$Limit||
    ldr     r2, =||Image$$SRAM$$ZI$$Limit||
zero_loop
        str     r0, [r1], #4
        cmp     r1, r2
        blt     zero_loop

    ;
    ; Set the vector table pointer to the beginning of SRAM.
    ;
    movw    r0, #(NVIC_VTABLE & 0xffff)
    movt    r0, #(NVIC_VTABLE >> 16)
    movs    r1, #0x0000
    movt    r1, #0x2000
    str     r1, [r0]

    ;
    ; Set the return address to the code just copied into SRAM.
    ;

    //此刻lr寄存器中已经存放了返回地址

   // 此操作为lr=lr+SRAM address,所以程序直接返回到SRAM中继续运行
    orr     lr, lr, #0x20000000

    ;
    ; Return to the caller.
    ;
    bx      lr

;******************************************************************************
;
; The reset handler, which gets called when the processor starts.
;
;******************************************************************************
    export  Reset_Handler

程序是从这里开始的
Reset_Handler
    ;
    ; Initialize the processor.
    ;

    //bl指令会把下条指令的地址存放到lr寄存器中
    bl      ProcessorInit

    //程序运行到这里已经被拷贝到SRAM中了

    ;
    ; Call the user-supplied low level hardware initialization function
    ; if provided.
    ;
    if      :def:_BL_HW_INIT_FN_HOOK
    import  $_BL_HW_INIT_FN_HOOK
    bl      $_BL_HW_INIT_FN_HOOK
    endif

    ;
    ; See if an update should be performed.
    ;
    import  CheckForceUpdate
    bl      CheckForceUpdate

    //r0保存CheckForceUpdate函数的返回值

    //如果为0表示启动APP程序
    cbz     r0, CallApplication

 

 

 

CallApplication
    ;
    ; Copy the application's vector table to the target address if necessary.
    ; Note that incorrect boot loader configuration could cause this to
    ; corrupt the code!  Setting VTABLE_START_ADDRESS to 0x20000000 (the start
    ; of SRAM) is safe since this will use the same memory that the boot loader
    ; already uses for its vector table.  Great care will have to be taken if
    ; other addresses are to be used.
    ;

    //把APP的VTABLE拷贝到指定addr

    //一般来说_APP_START_ADDRESS == _VTABLE_START_ADDRESS==0x1000=4K

    //一般来说程序的开始是VTABLE表,所以程序开始地址肯定是VTABLE地址

 

    //处理不相等的情况

    //把APP开始处得VTABLE拷贝到指定地址
    if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)
    movw    r0, #(_VTABLE_START_ADDRESS & 0xffff)
    if (_VTABLE_START_ADDRESS > 0xffff)
    movt    r0, #(_VTABLE_START_ADDRESS >> 16)
    endif
    movw    r1, #(_APP_START_ADDRESS & 0xffff)
    if (_APP_START_ADDRESS > 0xffff)
    movt    r1, #(_APP_START_ADDRESS >> 16)
    endif

    ;
    ; Calculate the end address of the vector table assuming that it has the
    ; maximum possible number of vectors.  We don't know how many the app has
    ; populated so this is the safest approach though it may copy some non
    ; vector data if the app table is smaller than the maximum.
    ;
    movw    r2, #(70 * 4)
    adds    r2, r2, r0
VectorCopyLoop
        ldr     r3, [r1], #4
        str     r3, [r0], #4
        cmp     r0, r2
        blt     VectorCopyLoop
    endif

//如果_APP_START_ADDRESS == _VTABLE_START_ADDRESS可以省略拷贝

    ;
    ; Set the vector table address to the beginning of the application.
    ;

//在APP程序开始之前一定要配置好VTABLE寄存器
    movw    r0, #(_VTABLE_START_ADDRESS & 0xffff)
    if (_VTABLE_START_ADDRESS > 0xffff)
    movt    r0, #(_VTABLE_START_ADDRESS >> 16)
    endif
    movw    r1, #(NVIC_VTABLE & 0xffff)
    movt    r1, #(NVIC_VTABLE >> 16)
    str     r0, [r1]

    ;
    ; Load the stack pointer from the application's vector table.
    ;

    //程序开始处是VTABLE

    //VTABLE第一个entry是STACK地址
    movw    r0, #(_APP_START_ADDRESS & 0xffff)
    if (_APP_START_ADDRESS > 0xffff)
    movt    r0, #(_APP_START_ADDRESS >> 16)
    endif
    ldr     sp, [r0]

    ;
    ; Load the initial PC from the application's vector table and branch to
    ; the application's entry point.
    ;

     //跳转到APP程序中

    //APP和BOOT程序各自有一个VTABLE表

    //读取应用程序中断向量表次4个字节的内容(即reset后的地址)
    ldr     r0, [r0, #4]
    bx      r0

 

 

 

************************************************************************

关于配置短接升级:

 

配置升级时IO口的极性

#define FORCED_UPDATE_POLARITY  0

配置IO口初始化时的电极

#define FORCED_UPDATE_WPU

 

所以

1:

如果配置UPDATE 0

则配置IO口默认为上拉

端口短接时升级

 

2:

如果配置UPDATE 1

则配置IO口默认为下拉

端口上拉时升级

 

在CheckForceUpdate函数中

 

检查如果FLASH中指定ADDR没有APP程序,则强制进入UPDATE模式

 

    pulApp = (unsigned long *)APP_START_ADDRESS;
    if((pulApp[0] == 0xffffffff) || ((pulApp[0] & 0xfff00000) != 0x20000000) ||
       (pulApp[1] == 0xffffffff) || ((pulApp[1] & 0xfff00001) != 0x00000001))
    {
        return(1);
    }

 

为什么(pulApp[0] & 0xfff00000) != 0x20000000) 表示不像栈指针?堆栈至少要建立在ram区
为什么(pulApp[1] & 0xfff00001) != 0x00000001)表示不像reset向量?向量表第二项是复位向量,

也就是初始pc值,pc最后一位必须为1 否则会进入arm模式产生fault;

而且Vector一开始肯定在FLASH中,FLASH 256K大小,所以地址最大=0x40000。所以&操作后高位一定为0

整个BOOTLOADER大致流程:

        ;
    bl      ProcessorInit--->把自己copy到内存中开始运行

    

    bl      CheckForceUpdate--->1: FLASH指定地址中是否有APP ,2: IO口是否配置为升级操作
    cbz     r0, CallApplication--->如果返回0则启动APP

   进入UPDATE

EnterBootLoader
    bl      ConfigureDevice --->开始配置升级接口

    b       Updater--->进入升级循环操作

CallApplication

   进入APP

烧写APP后的操作。

     发送COMMAND_RUN命令直接从APP_ADDRESS启动程序

     发送COMMAND_RESET命令直接RESET MCU

应该采用第二种方式,因为直接从APP_ADDRESS启动程序,但是此时VTABLE寄存器还没有配置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值