从MCU上电启动流程出发编写bootloader(上)

在这里插入图片描述
配置开发板的BOOT,从EFLASH(即片内Flash存储器)启动。
在这里插入图片描述
在KEIL中也需要进行相应的设置,将接下来要编写的bootloader烧写至EFLASH(bootloader段需要设置从0x8000000开始,空间根据bootloader大小分配)。
在这里插入图片描述
我们将bootloader程序反汇编可以查看EFLASH分配占用情况。
在这里插入图片描述
结合startup_ac78xx.s启动文件来分析MCU上电的启动流程。

__Vectors       DCD     __initial_sp               ; Top of Stack 0
                DCD     Reset_Handler              ; Reset Handler 04

MCU上电后首先建立从0x8000000开始建立中断向量表,随后因为复位进入Reset_Handler函数(中断向量0x08000135),下面是Reset_Handler函数的执行的具体操作。

Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit

                ; enable lockup reset
                LDR R1, =0x4000000C
                LDR R0, =0x0301FF00
                STR R0, [R1]

                ; enable xosc monitor
                LDR R1, =0x40000000
                LDR R0, [R1]
                ORR R0, R0,#0x00010000
                STR R0, [R1]

                ; enable xosc ready flag
                LDR R1, =0x400088b0
                LDR R0, [R1]
                BIC  R0, R0,#0x10000000
                STR R0, [R1]

                LDR     R0, =SystemInit
                BLX     R0
                LDR     R0, =__main
                BX      R0
                ENDP

在这里插入图片描述
关注到在进入_main函数前,SystemInit的函数首先被执行。SystemInit函数定义在system_ac78xx.c文件中。

void SystemInit (void)
{
    SetEflashClock();
    //SPM_EnableLVD(0);  //disable LVD if need
}

SetEflashClock函数从函数名理解,应该是设置内部Flash时钟的,为我们后续烧写EFLASH做初始化工作。我们暂且不去深究SetEflashClock函数的具体操作。在SystemInit函数执行完返回到下一条指令,这时才会进入_main函数。
在map文件中可以查看Reset_Handler、_main、SystemInit函数入口地址,以及_initial_sp的数据内容。
_main的入口地址应该是0x0800011c
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
有趣的是_main_stk和_main有着同样的入口地址,我们来看下有关它们的反汇编代码。
这段代码执行的操作是将0x20002518赋值给sp指针。

  __main
    _main_stk
        0x0800011c:    f8dfd010    ....    LDR      sp,__lit__00000000 ; [0x8000130] = 0x20002518
    .ARM.Collect$$$$00000004
    _main_scatterload
        0x08000120:    f000fa9c    ....    BL       __scatterload ; 0x800065c
    .ARM.Collect$$$$00000008
    .ARM.Collect$$$$0000000A
    .ARM.Collect$$$$0000000B
    __main_after_scatterload
    _main_clock
    _main_cpp_init
    _main_init
        0x08000124:    4800        .H      LDR      r0,[pc,#0] ; [0x8000128] = 0x800302d
        0x08000126:    4700        .G      BX       r0
    $d
        0x08000128:    0800302d    -0..    DCD    134230061
    $t
    .ARM.Collect$$$$0000000E
    __rt_lib_shutdown_fini
        0x0800012c:    f3af8000    ....    NOP.W    
    $d
    .ARM.Collect$$$$00002712
    __lit__00000000
    .ARM.Collect$$$$0000000F
    .ARM.Collect$$$$00000011
    __rt_final_cpp
    __rt_final_exit
        0x08000130:    20002518    .%.     DCD    536880408

重点关注以下三条指令。
在这里插入图片描述
由于ARM采用三级流水线架构(取指——译指——执行),当CPU执行到0x08000124处时,此时PC指针已经指向0x08000128处,接下来执行跳转指令,程序从0x0800302d处开始执行。我们可以从反汇编文件中查看对应的函数为用户定义的main函数。

在这里插入图片描述
因此,MCU上电后并非从用户定义的main函数开始执行!!!
而是按如下步骤进行:
(1)从0x8000000(启动位置)开始定义中断向量表。
(2)通过中断向量表执行Reset_Handler中断服务函数。
(3)执行SystemInit函数。(进行系统初始化工作)
(4)返回执行_main函数。(设置SP指针,跳转到用户定义main函数)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无名小屁喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值