Mbed OS启动流程

mbed_boot.c中总体上介绍了启动流程

 * For ARMCC:
 * ==========
 *
 * Reset (TARGET)
 *     -> SystemInit (TARGET)
 *     -> __main (LIBC)
 *         -> __rt_entry (MBED: rtos/mbed_boot.c)
 *             -> __user_setup_stackheap (LIBC)
 *             -> mbed_set_stack_heap (MBED: rtos/mbed_boot.c)
 *             -> mbed_cpy_nvic (MBED: rtos/mbed_boot.c)
 *             -> mbed_sdk_init (TARGET)
 *             -> _platform_post_stackheap_init (RTX)
 *                 -> osKernelInitialize (RTX)
 *             -> mbed_start_main (MBED: rtos/mbed_boot.c)
 *                 -> osThreadNew (RTX)
 *                     -> pre_main(MBED: rtos/mbed_boot.c)
 *                         -> __rt_lib_init (LIBC)
 *                         -> $Sub$$main (MBED: rtos/mbed_boot.c)
 *                             -> mbed_main (MBED: rtos/mbed_boot.c)
 *                             -> main (APP)
 *                 -> osKernelStart (RTX)
 *
 * In addition to the above, libc will use functions defined by RTX: __user_perthread_libspace, _mutex_initialize,
 * _mutex_acquire, _mutex_release, _mutex_free for details consult: ARM C and C++ Libraries and Floating-Point
 * Support User Guide.
 *
MBED项目中用C代码实现放在BIN文件最开始位置的中断向量表等内容的RESET section值得借鉴。
一般来说,启动阶段的代码由汇编实现,包含了终端向量表的数据设置,以及复位后第1个指令到调用LIBC主入口__main,在__main里完成数据的初始,并调用 __rt_entry,在 __rt_entry里再完成堆栈初始化、LIBC库初始后,调用main函数。
一个简单的示例如下:
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
__Vectors       DCD     __initial_sp              ; Top of Stack     BIN文件前4个字节为栈的初始化地址
                DCD     Reset_Handler             ; Reset Handler   BIN文件第2个4字节是复位后的第1条指令的位置
                DCD     NMI_Handler               ; NMI Handler     之后为各个中断对应处理函数的第1条指令位置
                DCD     HardFault_Handler         ; Hard Fault Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     SVC_Handler               ; SVCall Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     PendSV_Handler            ; PendSV Handler
                DCD     SysTick_Handler           ; SysTick Handler
                ; External Interrupts
                DCD     xxxx       
                DCD     xxxx 
                DCD     xxxx 
                DCD     xxxx 
                DCD     xxxx 
                DCD     xxxx 
                DCD     xxxx 
                DCD     xxxx 
                DCD     xxxx 
                DCD     xxxx 
                DCD     xxxx 
                DCD     xxxx 
__Vectors_End
__Vectors_Size  EQU     __Vectors_End - __Vectors                                                                                                                              
                AREA    |.text|, CODE, READONLY
; Reset Handler
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  SystemInit
                IMPORT  __main
                LDR     R0, =SystemInit   调用系统初始化函数,因为还没有初始化C库,不要使用C库里的函数
                BLX     R0
                LDR     R0, =__main     初始化数据去,初始化C库后调用应用main函数
                BX      R0
                ENDP

; Dummy Exception Handlers (infinite loops which can be modified)               
NMI_Handler     PROC
                EXPORT  NMI_Handler               [WEAK]
                B       .
                ENDP               
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler         [WEAK]
                B       .
                ENDP
SVC_Handler     PROC
                EXPORT  SVC_Handler               [WEAK]
                B       .
                ENDP
PendSV_Handler  PROC
                EXPORT  PendSV_Handler            [WEAK]
                B       .
                ENDP
SysTick_Handler PROC
                EXPORT  SysTick_Handler           [WEAK]
                B       .
                ENDP

在mbed os项目里的startup_NUC_472.c里,使用__attribute__ ((section("RESET")))语法,将本文件的数据和代码定义为RESET section。首先定义个const uint32_t __vector_handlers[] 数组,该数组里存放的歌中断函数的地址。相当于前面汇编代码开始处的中断向量表。
   再看看中断向量表中的函数名,使用了弱符号和别名机制,在用户没有定义强符号的同名中断函数时,将使用弱符号对应的函数。举个例
 项目自身宏定义    
#define WEAK            __attribute__ ((weak))
#define ALIAS(f)        __attribute__ ((weak, alias(#f)))
#define WEAK_ALIAS_FUNC(FUN, FUN_ALIAS)     void FUN(void) __attribute__ ((weak, alias(#FUN_ALIAS)));


 WEAK_ALIAS_FUNC(SC4_IRQHandler, Default_Handler)

const uint32_t __vector_handlers[] {
xxx 
(uint32_t) SC4_IRQHandler,          根据前面的别名定义,开发人员没有定义 SC4_IRQHandler,将连接 Default_Handler函数

xxx
}

缺省的死循环函数

void Default_Handler(void)
{
    while (1);
}

复位后第1条指令执行的函数地址

void Reset_Handler(void)

{

  运行环境必要的硬件初始化

Xxxx

  调用LIBC库的主入口

 __main();

}

 

启动C代码里,再次利用了弱符号特性。因为C库里一些函数或变量是定义为弱符号的,便于应用开发中重新按照系统的要去重新实现。其中__rt_entry(void)就可以重新实现。mBed OS里重新实现了__rt_entry(void)如下。

/* Called by the C library */

void __rt_entry (void) {

   __user_setup_stackheap();

   mbed_set_stack_heap();

   /* Copy the vector table to RAM only if uVisor is not in use. */

#if !(defined(FEATURE_UVISOR) &&defined(TARGET_UVISOR_SUPPORTED))

   mbed_cpy_nvic();

#endif

   mbed_sdk_init();

   _platform_post_stackheap_init();

   mbed_start_main();

}

 

 

C语言的弱、强符号特性,平常都很少使用。现在看来,用于实现函数的重载,是非常好的用法。

小贴士:可以定义多个弱符号,链接时会选择代码SIZE长的符号链接。

你可能感兴趣的:(Mbed OS启动流程)