当前位置: 首页 > news >正文

Rt-Thread 启动流程与组件初始化

目录

1、启动流程

2、程序入口

2.1、入口函数

2.2、用户main函数

3、rtthread_startup()函数

3.1、rt_hw_board_init()函数

4、组件初始化

4.1、INIT_EXPORT宏

4.1.1、未定义RT_USING_COMPONENTS_INIT

4.1.2、定义RT_USING_COMPONENTS_INIT,未定义RT_DEBUG_INIT

4.1.2、定义RT_USING_COMPONENTS_INIT,且定义RT_DEBUG_INIT

4.2、INIT_EXPORT实例

4.2.1、定义RT_USING_COMPONENTS_INIT,未定义RT_DEBUG_INIT

4.2.2、定义RT_USING_COMPONENTS_INIT,且定义RT_DEBUG_INIT

4.3、INIT_XXX_EXPORT宏

4.4、rt_components_board_init()函数

4.5、rt_components_init()函数


1、启动流程

RT-Thread 支持多种平台和多种编译器,而 rtthread_startup() 函数是 RT-Thread 规定的统一启动入口。

2、程序入口

在进入 main() 之前需要进行RT-Thread 系统功能初始化,需要修改入口函数。

2.1、入口函数

#if defined(__CC_ARM) || defined(__CLANG_ARM)
extern int $Super$$main(void);
/* re-define main function */
int $Sub$$main(void)
{
    rtthread_startup();
    return 0;
}
#elif defined(__ICCARM__)
extern int main(void);
/* __low_level_init will auto called by IAR cstartup */
extern void __iar_data_init3(void);
int __low_level_init(void)
{
    // call IAR table copy function.
    __iar_data_init3();
    rtthread_startup();
    return 0;
}
#elif defined(__GNUC__)
/* Add -eentry to arm-none-eabi-gcc argument */
int entry(void)
{
    rtthread_startup();
    return 0;
}
#endif
编译工具入口函数
MDK

$Sub$$main()

注:使用了 MDK 的扩展功能 $Sub$$ 和$Super$$。可以给 main 添加 $Sub$$ 的前缀符号作为一个新功能函数 $Sub$$main,这个 $Sub$$main 可以先调用一些要补充在 main 之前的功能函数

IAR__low_level_init()
GCCentry()

2.2、用户main函数

void main_thread_entry(void *parameter)
{
    extern int main(void);
    extern int $Super$$main(void);

#ifdef RT_USING_COMPONENTS_INIT
    /* RT-Thread components initialization */
    rt_components_init();
#endif
    /* invoke system main function */
#if defined(__CC_ARM) || defined(__CLANG_ARM)
    $Super$$main(); /* for ARMCC. */
#elif defined(__ICCARM__) || defined(__GNUC__)
    main();
#endif
}
编译工具入口函数
MDK

$Super$$main()

IARmain()
GCC

3、rtthread_startup()函数

这部分代码,大致可以分为四个部分:

1)初始化与系统相关的硬件;
2)初始化系统内核对象,例如定时器、调度器、信号;
3)创建 main 线程,在 main 线程中对各类模块依次进行初始化;
4)初始化定时器线程、空闲线程,并启动调度器。

详细功能如下:

1)关中断

2)板级初始化,在该函数中初始化堆

3)打 印 RT-Thread 版 本 信 息

4)系统定时器系统初始化

5)系统调度器初始化

6)*系统信号量初始化

7)创建应用初始化线程

8)系统定时器线程初始化

9)空闲线程初始化

10)调度器开始调度

int rtthread_startup(void)
{
    rt_hw_interrupt_disable(); //关中断

    rt_hw_board_init(); //板级初始化,在该函数中初始化堆

    rt_show_version(); //显示版本

    rt_system_timer_init(); //系统定时器系统初始化

    rt_system_scheduler_init(); //系统调度器初始化

#ifdef RT_USING_SIGNALS
    rt_system_signal_init(); //如果定义了宏RT_USING_SIGNALS,初始化系统信号量
#endif

    rt_application_init(); //创建应用初始化线程

    rt_system_timer_thread_init(); //系统定时器线程初始化

    rt_thread_idle_init(); //空闲线程初始化

    rt_system_scheduler_start(); //调度器开始调度

    return 0;
}

3.1、rt_hw_board_init()函数

此函数为板级初始化函数(不同板子的初始化函数不同)

1)系统时钟设置

2)为系统提供心跳

3)*调用rt_components_board_init()函数,进行串口初始化(将系统输入输出终端绑定到这个串口,后续系统运行信息就会从串口打印出来)

4)*调用rt_system_heap_init()函数,进行堆初始化

4、组件初始化

 

4.1、INIT_EXPORT宏

#ifdef RT_USING_COMPONENTS_INIT
typedef int (*init_fn_t)(void);
#ifdef _MSC_VER /* we do not support MS VC++ compiler */
    #define INIT_EXPORT(fn, level)
#else
    #if RT_DEBUG_INIT
        struct rt_init_desc
        {
            const char* fn_name;
            const init_fn_t fn;
        };
        #define INIT_EXPORT(fn, level)                                                       \
            const char __rti_##fn##_name[] = #fn;                                            \
            RT_USED const struct rt_init_desc __rt_init_desc_##fn SECTION(".rti_fn." level) = \
            { __rti_##fn##_name, fn};
    #else
        #define INIT_EXPORT(fn, level)                                                       \
            RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn
    #endif
#endif
#else
#define INIT_EXPORT(fn, level)
#endif

4.1.1、未定义RT_USING_COMPONENTS_INIT

#define INIT_EXPORT(fn, level)

4.1.2、定义RT_USING_COMPONENTS_INIT,未定义RT_DEBUG_INIT

 #define INIT_EXPORT(fn, level)                                                       \
    RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn

定义了一个指向fn()函数的函数指针__rt_init_##fn,并将此函数指针定位到".rti_fn."level段。

4.1.2、定义RT_USING_COMPONENTS_INIT,且定义RT_DEBUG_INIT

struct rt_init_desc
{
    const char* fn_name;
    const init_fn_t fn;
};
#define INIT_EXPORT(fn, level)   \
    const char __rti_##fn##_name[] = #fn;                                            \
    RT_USED const struct rt_init_desc __rt_init_desc_##fn SECTION(".rti_fn." level) = \
            { __rti_##fn##_name, fn};

定义了一个字符数组和一个结构体。

1)__rti_##fn##_name[]字符数组用于保存fn()函数的名称。

2)__rt_init_desc_##fn结构体此结构体有2个成员。并将__rt_init_desc_##fn结构体定位到".rti_fn."level段。

        fn_name成员为函数名称,指向__rti_##fn##_name[]字符数组

        fn成员为函数指针。指向fn()函数的函数指针,函数指针名为__rt_init_##fn。

4.2、INIT_EXPORT实例

static int rti_start(void)
{
    return 0;
}
INIT_EXPORT(rti_start, "0");

static int rti_start(void)
{
    return 0;
}
INIT_EXPORT(rti_start, "0");

static int rti_board_start(void)
{
    return 0;
}
INIT_EXPORT(rti_board_start, "0.end");

static int rti_board_end(void)
{
    return 0;
}
INIT_EXPORT(rti_board_end, "1.end");

static int rti_end(void)
{
    return 0;
}
INIT_EXPORT(rti_end, "6.end");

4.2.1、定义RT_USING_COMPONENTS_INIT,未定义RT_DEBUG_INIT

RT_USED const init_fn_t __rt_init_rti_start SECTION(".rti_fn.0") = rti_start
RT_USED const init_fn_t __rt_init_rti_board_start SECTION(".rti_fn.0.end") = rti_board_start
RT_USED const init_fn_t __rt_init_rti_board_end SECTION(".rti_fn.1.end") = rti_board_end
RT_USED const init_fn_t __rt_init_rti_end SECTION(".rti_fn.6.end") = rti_end
函数指针函数
__rt_init_rti_start .rti_fn.0rti_start()
__rt_init_rti_board_start.rti_fn.0.endrti_board_start()
__rt_init_rti_board_end.rti_fn.1.endrti_board_end()
__rt_init_rti_end.rti_fn.6.endrti_end()

4.2.2、定义RT_USING_COMPONENTS_INIT,且定义RT_DEBUG_INIT

const char __rti_rti_start_name[] = "rti_start";                                            
RT_USED const struct rt_init_desc __rt_init_desc_rti_start SECTION(".rti_fn.0") = \
 { __rti_rti_start_name, rti_start};

const char __rti_rti_board_start_name[] = "rti_board_start";                                            
RT_USED const struct rt_init_desc __rt_init_desc_rti_board_start SECTION(".rti_fn.0.end") = \
 { __rti_rti_board_start_name, rti_board_start};

const char __rti_rti_board_end_name[] = "rti_board_end";                                            
RT_USED const struct rt_init_desc __rt_init_desc_rti_board_end SECTION(".rti_fn.1.end") = \
 { __rti_rti_board_end_name, rti_board_end};

const char __rti_rti_board_rti_end_name[] = "rti_end";                                            
RT_USED const struct rt_init_desc __rt_init_desc_rti_end SECTION(".rti_fn.6.end") = \
 { __rti_rti_end_name, rti_end};
数组字符串
__rti_rti_start_name[]"rti_start"
__rti_rti_board_start_name[]"rti_board_start"
__rti_rti_board_end_name[]"rti_board_end"
__rti_rti_board_rti_end_name[]"rti_end"
结构体成员函数
__rt_init_rti_start .rti_fn.0fn_name__rti_rti_start_name[]
fnrti_start()
__rt_init_rti_board_start.rti_fn.0.endfn_name__rti_rti_board_start_name[]
fnrti_board_start()
__rt_init_rti_board_end.rti_fn.1.endfn_name__rti_rti_board_end_name[]
fnrti_board_end()
__rt_init_rti_end.rti_fn.6.endfn_name__rti_rti_board_rti_end_name[]
fnrti_end()

4.3、INIT_XXX_EXPORT宏

/* 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")
INIT_BOARD_EXPORT.rti_fn.1
INIT_PREV_EXPORT.rti_fn.2
INIT_DEVICE_EXPORT.rti_fn.3
INIT_COMPONENT_EXPORT.rti_fn.4
INIT_ENV_EXPORT.rti_fn.5
INIT_APP_EXPORT.rti_fn.6

4.4、rt_components_board_init()函数

此函数用于板级组件初始化(调用.rti_fn.0.end段到.rti_fn.1.end段的函数)。一般为BOARD_EXPORT()宏定义的函数指针指向的函数(一般为串口初始化函数)。

__rt_init_rti_board_start位于.rti_fn.0.end段,__rt_init_rti_board_end位于.rti_fn.1.end段。

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
    volatile 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
}

4.5、rt_components_init()函数

此函数用于组件初始化(调用.rti_fn.1.end段到.rti_fn.6.end段的函数)。一般为DEVICE_EXPORT()、COMPONENT_EXPORT(),FS_EXPORT(),ENV_EXPORT(),APP_EXPORT()宏定义的函数指针指向的函数。

__rt_init_rti_board_end位于.rti_fn.1.end段,__rt_init_rti_end位于.rti_fn.6.end段。

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

    rt_kprintf("do components initialization.\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
    volatile 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
}

相关文章:

  • CentOS-7-x86_64 iso镜像的安装(Linux操作系统)
  • Parcel配置public静态文件目录
  • 设计模式——策略模式
  • “一万字”动静图生动结合详解:快速排序
  • Linux命令详解(14)useradd命令
  • 面试题之Java的异常
  • k8s helm Seata1.5.1
  • 物业公司如何解决降本增收?快鲸智慧社区系统来帮你
  • MobTech 短信验证Android端 API
  • kafka学习总结
  • 政策汇总 | 川渝发布若干政策支持双城经济圈健康发展、岷山行动计划第三批项目申报解答......近期16个政策汇总
  • Vue3.0中使用路由进行跳转和传参以及取值
  • 迷茫了3年:做完这个测试项目,我终于决定辞职
  • 时间相关模块
  • LINU下登录脚本的执行顺序
  • css系列之关于字体的事
  • Javascripit类型转换比较那点事儿,双等号(==)
  • magento2项目上线注意事项
  • python docx文档转html页面
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • SpiderData 2019年2月16日 DApp数据排行榜
  • tweak 支持第三方库
  • Vue ES6 Jade Scss Webpack Gulp
  • 回顾 Swift 多平台移植进度 #2
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 正则与JS中的正则
  • "无招胜有招"nbsp;史上最全的互…
  • (2)STL算法之元素计数
  • (C语言)共用体union的用法举例
  • (poj1.3.2)1791(构造法模拟)
  • (备忘)Java Map 遍历
  • (附源码)计算机毕业设计SSM基于健身房管理系统
  • (力扣)循环队列的实现与详解(C语言)
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • (转)c++ std::pair 与 std::make
  • (转)socket Aio demo
  • (转)为C# Windows服务添加安装程序
  • .Net Core和.Net Standard直观理解
  • .NET与 java通用的3DES加密解密方法
  • .Net语言中的StringBuilder:入门到精通
  • /etc/fstab 只读无法修改的解决办法
  • /etc/fstab和/etc/mtab的区别
  • @RequestParam @RequestBody @PathVariable 等参数绑定注解详解
  • [120_移动开发Android]008_android开发之Pull操作xml文件
  • [Avalon] Avalon中的Conditional Formatting.
  • [C++]AVL树怎么转
  • [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated c
  • [iOS]GCD(一)
  • [MFC] MFC 获取指定窗口截图(大小可调)
  • [OIDC in Action] 3. 基于OIDC(OpenID Connect)的SSO(添加Github OAuth 2.0的支持)
  • [Poj 1015] Jury Compromise 解题报告 (完全背包)
  • [Pyhton]weakref 弱引用
  • [QT] TCP协议演示