RT-Thread的各種硬件、線程初始化過程的學習


  RT-Thread的各種硬件、線程初始化過程時,可以通過六個預定義的宏來實現,在實際編程時,直接使用這6個宏即可。

/* board init routines will be called in board_init() function */
#define INIT_BOARD_EXPORT(fn) INIT_EXPORT(fn, "1")
/* pre/device/component/env/app init routines will be called in init_thread */
/* components pre-initialization (pure software initilization) */
#define INIT_PREV_EXPORT(fn) INIT_EXPORT(fn, "2")
/* device initialization */
#define INIT_DEVICE_EXPORT(fn) INIT_EXPORT(fn, "3")
/* components initialization (dfs, lwip, ...) */
#define INIT_COMPONENT_EXPORT(fn) INIT_EXPORT(fn, "4")
/* environment initialization (mount disk, ...) */
#define INIT_ENV_EXPORT(fn) INIT_EXPORT(fn, "5")
/* appliation initialization (rtgui application etc ...) */
#define INIT_APP_EXPORT(fn) INIT_EXPORT(fn, "6")

 

通過源碼的學習,了解一下程序初始化過程。

1)首先在main函數內調用了 rtthread_startup() 函數;

2)在void rtthread_startup(void)內調用了 rt_hw_board_init() 函數;

3)在 rt_hw_board_init() 函數內調用 rt_components_board_init();

void rt_components_board_init(void)
{
  #if RT_DEBUG_INIT
  int result;
  const struct rt_init_desc *desc;
  for (desc = &__rt_init_desc_rti_board_start; desc < &__rt_init_desc_rti_board_end; desc ++)
  {
    rt_kprintf("initialize %s", desc->fn_name);
    result = desc->fn();
    rt_kprintf(":%d done\n", result);
  }
#else
  const init_fn_t *fn_ptr;

  for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++)
  {
    (*fn_ptr)();
  }
#endif
}

 這里需要注意兩個變量__rt_init_rti_board_start和__rt_init_rti_board_end,查找__rt_init_rti_board_start定義,導向到這個語句:INIT_EXPORT(rti_board_start, "0.end");

繼續查找INIT_EXPORT,導向到 RT_USED  const   init_fn_t   __rt_init_##fn   SECTION(".rti_fn."level) = fn,

查找SECTION,到想到(#define SECTION(x)    __attribute__((section(x)))),這里作用是將作用的函數或數據放入指定名為"section_name"輸入段,在鏈接的時候會被自動調用

知道__rt_init_rti_board_end 是通過宏定義INIT_EXPORT來組合前部分 __rt_init_和后部分rti_board_start,並放入到section指定的名稱段內;  __rt_init_rti_board_end類似。

__rt_init_rti_board_end 指向了section的“0.end”名稱段,__rt_init_rti_board_end指向了section的"1.end"名稱段,(*fn_ptr)()函數指針會依次調用這兩段之間的所有函數。

這樣,在rt_components_board_init函數內,就會把通過宏定義#define   INIT_BOARD_EXPORT(fn)    INIT_EXPORT(fn, "1")定義的函數進行調用。

4)在void rtthread_startup(void)內調用了 rt_application_init() 函數;

5)在rt_application_init()函數內創建的線程內,調用了rt_components_init()函數;

void rt_components_init(void)
{
  #if RT_DEBUG_INIT
  int result;
  const struct rt_init_desc *desc;

  rt_kprintf("do components intialization.\n");
  for (desc = &__rt_init_desc_rti_board_end; desc < &__rt_init_desc_rti_end; desc ++)
  {
    rt_kprintf("initialize %s", desc->fn_name);
    result = desc->fn();
    rt_kprintf(":%d done\n", result);
  }
#else
  const init_fn_t *fn_ptr;

  for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++)
  {
    (*fn_ptr)();
  }
#endif
}

 這里需要注意兩個變量__rt_init_rti_board_end和__rt_init_rti_end,

__rt_init_rti_board_end通過上面分析,可以知道它指向的是輸入段section的"1.end"名稱段,

__rt_init_rti_end通過了INIT_EXPORT(rti_end, "6.end"),它指向的是輸入段section的"6.end"名稱段,

(*fn_ptr)()函數指針會依次調用這兩段之間的所有函數。

這樣,在rt_components_init函數內,就會把通過以下5個宏定義

#define INIT_PREV_EXPORT(fn) INIT_EXPORT(fn, "2")

#define INIT_DEVICE_EXPORT(fn) INIT_EXPORT(fn, "3")

#define INIT_COMPONENT_EXPORT(fn) INIT_EXPORT(fn, "4")

#define INIT_ENV_EXPORT(fn) INIT_EXPORT(fn, "5")

#define INIT_APP_EXPORT(fn) INIT_EXPORT(fn, "6")

定義的函數進行調用。

6)所以,在自己代碼中需要進行硬件初始化、線程啟動等函數調用時,在函數定義下面直接使用以上6個宏中的一個,即可實現自動調用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM