首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

RT-Thread 啟動流程深度解析:startup.c 核心代碼逐行講解

     編輯:關於C語言

RT-Thread 啟動入口:rtthread_startup()

RT-Thread(簡稱 RTT)的啟動流程集中在 startup.c,核心函數 rtthread_startup() 按依賴順序初始化所有子系統:

void rtthread_startup(void) {
    rt_hw_board_init();        // 1. 板級硬件初始化
    rt_show_version();         // 2. 打印版本信息
    rt_system_tick_init();     // 3. 系統節拍(時鐘中斷)初始化
    rt_system_object_init();   // 4. 內核對象容器初始化
    rt_system_timer_init();    // 5. 定時器系統初始化
    rt_system_scheduler_init(); // 6. 調度器初始化
    rt_device_init_all();      // 7. 設備驅動模型初始化
    rt_application_init();     // 8. 應用層線程/組件初始化
    rt_thread_idle_init();     // 9. 空閒線程創建
    rt_system_scheduler_start(); // 10. 啟動調度器(不返回)
}

兩大關鍵自定義點

1. rt_hw_board_init() — 板級支持包 (BSP) 核心

由芯片廠商/板卡製造商實現,典型工作:

  • 時鐘樹配置(PLL、總線分頻)
  • UART 控制台初始化(早期 printk 依賴)
  • 外設時鐘使能(GPIO、SPI、I2C 等)
  • **堆內存初始化**(見下文)

2. rt_application_init() — 應用層入口

用戶代碼入口,通常創建主線程、初始化文件系統、網絡協議棧、GUI 等。

堆內存初始化:跨編譯器的鏈接符號藝術

RTT 使用 rt_system_heap_init(start, end) 劃定堆範圍。不同工具鏈獲取「已用 RAM 末端」方式不同:

#ifdef RT_USING_HEAP
#if STM32_EXT_SRAM
    rt_system_heap_init((void*)STM32_EXT_SRAM_BEGIN, (void*)STM32_EXT_SRAM_END);
#else
    #ifdef __CC_ARM      // ARMCC (MDK)
        rt_system_heap_init((void*)&Image$$RW_IRAM1$$ZI$$Limit, (void*)STM32_SRAM_END);
    #elif __ICCARM__     // IAR
        rt_system_heap_init(__segment_end("HEAP"), (void*)STM32_SRAM_END);
    #else                // GCC
        rt_system_heap_init((void*)&__bss_end, (void*)STM32_SRAM_END);
    #endif
#endif
#endif

符號解析

工具鏈符號含義
ARMCCImage$$RW_IRAM1$$ZI$$LimitRW/IRAM1 區域 ZI 段末端,即 .bss 結束地址
IAR__segment_end("HEAP")鏈接腳本定義的 HEAP 段末端
GCC__bss_end鏈接腳本提供的 .bss 段結束符號

這些符號由鏈接器自動生成,代表「靜態數據區結束」,其後的 RAM 即可安全用作動態堆。

為什麼區分靜態/動態線程?

  • 靜態線程:棧在編譯期分配於 .bss/.data,無需堆,啟動極快。
  • 動態線程:棧/控制塊運行時從堆分配(rt_thread_create),靈活但需堆初始化完成。

rt_thread_idle_init() 創建的空閒線程通常是靜態的,保證調度器啟動前就有可運行線程。

調度器啟動後不返回

rt_system_scheduler_start() 會切換到最高優先級就緒線程,進入線程上下文**永不返回**。這也是為什麼 main() 在 RTT 中通常不存在或為空。

學習建議

  1. 從 BSP 的 rt_hw_board_init() 入手,理解硬件初始化順序。
  2. 閱讀 rt_application_init() 所在文件,掌握專案具體啟動邏輯。
  3. 對照鏈接腳本(.ld/.sct/.icf)理解堆/棧/段佈局。
  4. 啟用 RT_DEBUG 並觀察串口輸出,驗證啟動流程。

掌握 startup.c 即掌握了 RTT 從上電到多線程運行的完整生命週期,是移植、調試、優化的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved