(四)Betaflight启动流程详解

文章详细解释了AT32F437DEV嵌入式系统启动时,如何通过查看map文件和链接脚本来定位程序入口,以及汇编.S启动文件中的入口标号和C语言main函数的调用过程。还介绍了C语言函数如systemInit()和init()的初始化流程。
摘要由CSDN通过智能技术生成

4.1 查看程序入口

查看./obj/main/betaflight_AT32F437DEV.map文件,发现在Flash的起始地址即0x0800 0000处链接的是startup_at32f435_437.o文件,startup_at32f435_437.o文件由startup_at32f435_437.S汇编文件编译而来。则程序启动后会先执行startup_at32f435_437.S汇编文件。 (具体芯片启动规则还不太清楚,知道的大佬不吝赐教)。

 .isr_vector 0x0000000008000000  0x20c obj/main/AT32F437DEV/startup_at32f435_437.o

                0x0000000008000000                g_pfnVectors

                0x000000000800020c                . = ALIGN (0x4)

                [!provide]                        PROVIDE (isr_vector_table_end = .

4.2 汇编 .S启动文件

打开 obj/main/AT32F437DEV/目录下的startup_at32f435_437.S文件。

4.2.1 汇编程序入口

汇编程序的默认入口标号是_start , 不过startup_at32f435_437.S中没有该标号,而是使用了自定义的入口标号Reset_Handler,该入口标号的定义方法是在链接脚本中使用ENTRY进行指明。

打开./src/link/at32_flash_f43xM.ld链接脚本文件,发现在该脚本50行引用了另一个链接脚本文件:

INCLUDE "at32_flash_f4_split.ld"

打开与at32_flash_f43xM.ld同目录的at32_flash_f4_split.ld文件,在12行找到如下代码:

/* Entry Point */

ENTRY(Reset_Handler)

这里用ENTRY指明了汇编文件的入口标号Reset_Handler

4.2.2 调用C语言main函数

在startup_at32f435_437.S文件第60行找到Reset_Handler,其下依次使用bl指令(执行后会返回到原处)调用了一些C言初始化函数、用b指令(执行后不会返回)调用许多汇编文件下的子标号(类似于C语言的函数调用)。

Reset_Handler:

/* custom init */

  ldr   sp, =_estack      /* set stack pointer 设置栈指针*/



  bl persistentObjectInit                       /*保护数据初始化*/

  bl checkForBootLoaderRequest    /*进行一些关于BootLoader支持的操作*/



/* Copy the data segment initializers from flash to SRAM */

  movs  r1, #0

  b  LoopCopyDataInit



CopyDataInit:

  ldr  r3, =_sidata

  ldr  r3, [r3, r1]

  str  r3, [r0, r1]

  adds  r1, r1, #4



LoopCopyDataInit:

  ldr  r0, =_sdata

  ldr  r3, =_edata

  adds  r2, r0, r1

  cmp  r2, r3

  bcc  CopyDataInit

  ldr  r2, =_sbss

  b  LoopFillZerobss

/* Zero fill the bss segment. */

FillZerobss:

  movs  r3, #0

  str  r3, [r2], #4



LoopFillZerobss:

  ldr  r3, = _ebss

  cmp  r2, r3

  bcc  FillZerobss





  ldr  r2, =_sfastram_bss

  b  LoopFillZerofastram_bss

/* Zero fill the fastram_bss segment. */

FillZerofastram_bss:

  movs  r3, #0

  str  r3, [r2], #4



LoopFillZerofastram_bss:

  ldr  r3, = _efastram_bss

  cmp  r2, r3

  bcc  FillZerofastram_bss





/* Call the clock system intitialization function.*/

  bl  SystemInit

/* Call static constructors */

  bl __libc_init_array

/* Call the application's entry point.*/

  bl  main        /*调用所有main函数?*/

  bx  lr

对汇编子标号的调用流程如下:

Reset_Handler (60)

-》LoopCopyDataInit (77)

-》LoopFillZerobss (84)

-》LoopFillZerofastram_bss (103)

最终在LoopFillZerofastram_bss下调用C语言的main函数

  bl  main        /*调用所有main函数?*/

不过这里还有些问题,全文搜索int main(void)函数,发现会出现许多结果,大部分都为各种驱动与设备.c文件的,看内容类似初始化之类的操作。只有src/main/目录下main.c文件中的main函数最像c语言程序入口。

所以这里的bl  main指令是只调用了main.c里的main函数(并未找到extern之类的声明),还是所有的main函数都调用了一遍,就不得而知了。先闻道的前辈不吝赐教O(∩_∩)O谢谢!

同时为了解决上术问题,可以在vscode文件夹下建立一个.vscode/settings.json的设置文件,在文件中输入:

{

    //搜索注释

    "search.exclude": {

       "**.o": true,

       "src/main/target/[B-Z]*":true,

       "src/main/target/A[A-S]*":true,

       "src/main/target/AT32F403ADEV*":true,

    },



    //文件目录注释

    "files.exclude": {

        "**.o": true,

        "src/main/target/[B-Z]*":true,

        "src/main/target/A[A-S]*":true,

        "src/main/target/AT32F403ADEV*":true,

    }

}

语法规则为:

"search.exclude": {} 表示搜索结果中排除

"files.exclude": {} 表示左侧工程目录中排除

"arch/arm/boot/dts/imx6ul-*":true, “true”表示排除, “false”表示不排除

**表示前缀匹配, *表示后缀匹配

[A-S] 表示对A~S所有字母进行匹配

4.3 C语言函数初始化

main() -》init() -》systemInit()  函数

4.3.1 systemInit()  函数

搜索发现systemInit()  函数在src/main/drivers/system.h 中初声明,确在src/main/drivers/system_at32f43x.c 、 src/main/target/SITL/target.c 与 obj/main/AT32F437DEV/drivers/system_at32f43x.i 三个文件中都有定义。

C语言中同名函数重复定义编译器会报错,这里编译成功说明一定有两会被舍弃。

首先obj/main/AT32F437DEV/drivers/system_at32f43x.i 位于obj输出文件夹下,是编译过程中产生的,可以先排除。

其次,打开make/targets.mk 文件发现 35~65行:

ifeq ($(TARGET),$(filter $(TARGET),$(F3_TARGETS)))

……



else ifeq ($(TARGET),$(filter $(TARGET), $(SITL_TARGETS)))

TARGET_MCU := SITL

SIMULATOR_BUILD = yes



……

else ifeq ($(TARGET),$(filter $(TARGET), $(AT32F43x_TARGETS)))

TARGET_MCU := AT32F43x



else

……

endif

在这个Makefile文件中,由于TARGET_MCU变量最终被赋值AT32F43x而不是SITL(一种芯片类型),所以在编译时src/main/target/SITL/下的文件并未被包含进来,故systemInit()  函数使用src/main/drivers/system_at32f43x.c中的定义。

验证的话,可以分别将两个.c文件中systemInit() 函数的定义注释掉,重新编译看哪个会出现报错。

4.3.2 其他模块命令等初始化

BF1在init()函数中对LED、陀螺仪等各种模块与命令进行初始化,去掉不用的宏为:

void init(void)

{

#ifdef SERIAL_PORT_COUNT

    printfSerialInit();

#endif



 ……



    swdPinsInit();



    unusedPinsInit();



    tasksInit();



    systemState |= SYSTEM_STATE_READY;

}

这里注意在init()函数的最后,对各任务进行了初始化,即tasksInit();函数。

4.3.3 tasksInit() 函数

其中主要进行了三部分操作,使用schedulerInit() 函数进行调度器初始化,使用setTaskEnabled() 函数对各任务进行使能,使用rescheduleTask() 函数对各任务的运行周期重新设置等。

C语言部分的初始化流程大致如下:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值