rt-thread 使用心得

最近做了一个项目,接触到了 rt-thread 这款国产实时操作系统,进行了简单的配置之后就能够在板子上面调试,确实很方便!

下面是我在配置的过程中遇到的一些问题,以及对这些问题的思考。

rt-thread 驱动与组件初始化

rt-thread 系统驱动与组件的初始化与常见的嵌入式实时操作系统有较大区别。rt-thread 通过将初始化函数地址以不同的初始化级别排序后存储到初始化段中,在段的前后设置锚点,通过遍历获取锚点间存储的函数指针,依次执行来完成初始化工作。

rt-thread 中的初始化工作可以分为组件板级初始化与组件系统级初始化两种,这两种类别的初始化函数指针依次存放。根据 rt-thread 中 component.c 源代码可以发现这些初始化函数的执行有如下顺序 :

a. rti_start --> 0
b. BOARD_EXPORT --> 1
c. rti_board_end --> 1.end
d. DEVICE_EXPORT --> 2
e. COMPONENT_EXPORT --> 3
f. FS_EXPORT --> 4
g. ENV_EXPORT --> 5
h. APP_EXPORT --> 6
i. rti_end --> 6.end

下面是我的项目的 map 文件中与初始化函数段相关的数据:

                0x60033030                __rt_init_start = .*(SORT(.rti_fn*)).rti_fn.0      0x60033030        0x4 build/kernel/src/components.o0x60033030                __rt_init_rti_start.rti_fn.0.end  0x60033034        0x4 build/kernel/src/components.o0x60033034                __rt_init_rti_board_start.rti_fn.1      0x60033038        0x4 build/drivers/drv_uart.o0x60033038                __rt_init_imxrt_hw_uart_init.rti_fn.1      0x6003303c        0x4 build/drivers/drv_pin.o0x6003303c                __rt_init_rt_hw_pin_init.rti_fn.1      0x60033040        0x4 build/drivers/drv_spi_bus.o0x60033040                __rt_init_rt_hw_spi_bus_init.rti_fn.1.end  0x60033044        0x4 build/kernel/src/components.o0x60033044                __rt_init_rti_board_end.rti_fn.2      0x60033048        0x4 build/kernel/components/dfs/src/dfs.o0x60033048                __rt_init_dfs_init.rti_fn.2      0x6003304c        0x4 build/kernel/components/net/lwip-2.0.2/src/arch/sys_arch.o0x6003304c                __rt_init_lwip_system_init.rti_fn.2      0x60033050        0x4 build/kernel/components/drivers/sdio/mmcsd_core.o0x60033050                __rt_init_rt_mmcsd_core_init.rti_fn.3      0x60033054        0x4 build/drivers/drv_rtc.o0x60033054                __rt_init_rt_hw_hp_rtc_init.rti_fn.3      0x60033058        0x4 build/drivers/drv_i2c.o0x60033058                __rt_init_rt_hw_i2c_init.rti_fn.3      0x6003305c        0x4 build/drivers/drv_lcd.o0x6003305c                __rt_init_rt_hw_lcd_init.rti_fn.3      0x60033060        0x4 build/drivers/drv_sdio.o0x60033060                __rt_init_imxrt_mci_init.rti_fn.3      0x60033064        0x4 build/drivers/drv_eth.o0x60033064                __rt_init_rt_hw_imxrt_eth_init.rti_fn.4      0x60033068        0x4 build/kernel/components/dfs/filesystems/elmfat/dfs_elm.o0x60033068                __rt_init_elm_init.rti_fn.4      0x6003306c        0x4 build/kernel/components/libc/compilers/newlib/libc.o0x6003306c                __rt_init_libc_system_init.rti_fn.4      0x60033070        0x4 build/kernel/components/drivers/i2c/i2c_core.o0x60033070                __rt_init_rt_i2c_core_init.rti_fn.6      0x60033074        0x4 build/kernel/components/finsh/shell.o0x60033074                __rt_init_finsh_system_init.rti_fn.6.end  0x60033078        0x4 build/kernel/src/components.o0x60033078                __rt_init_rti_end0x6003307c                __rt_init_end = .

__rti_init_start 是初始化函数段的开始,__rt_init_end 是该段的结束,且段中函数指针变量以相同的前缀名进行排序。为什么会有这样的布局呢?这与链接脚本有关。以 gcc 链接脚本为例,你可以在链接脚本中发现这样几行:

   /* section information for initial. */. = ALIGN(4);__rt_init_start = .;KEEP(*(SORT(.rti_fn*)))__rt_init_end = .;. = ALIGN(4);

第一行是注释,第二行表示当前行开始以四字节对齐,四字节就是 32 位 cpu 中一个指针的长度。然后在 __rti_init_start 中保存段的起始地址,同理在 __rt_init_end 中保存段的结束地址。KEEP(*(SORT(.rti_fn*))) 有两个作用:

  1. 强制链接器保留以名称中包含 .rti_fn* 的段。

  2. 以 .rti_fn* 为关键词对不同 .o 中的段定义进行排序,这一点至关重要。

我在构建第一个可以调试的工程时就发现在我的链接脚本中缺少了 KEEP(*(SORT(.rti_fn*))) 这句,造成无法正常完成初始化工作,系统一运行便进入断言。如果你在使用 rt-thread 时遇到断言问题,那么你首先在生成的 map 文件中以关键字 __rti_fn 搜索,不仅要确认这样的段确实存在,而且一定排好了序存放。如果搜索不到,或者搜索到的结果乱序排放,那么你可以检查链接脚本,这常常就是问题所在。

为什么一定要排序呢?我也曾经心存疑惑,当我阅读了初始化部分的源代码,我发现了问题的答案。

两个主要的初始化函数的主要内容如下:

 void rt_components_board_init(void){.................................for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++){(*fn_ptr)();}.................................}void rt_components_init(void){.............................................const init_fn_t *fn_ptr;for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++){(*fn_ptr)();}.....................................}

rt_components_board_init 是组件的板级初始化函数,该函数以 __rt_init_rti_board_start 为起始地址,__rt_init_rti_board_end 为终止地址,程序依次遍历这两个锚点间存放的初始化函数地址并执行。如果没有进行排序,那么需要执行的函数的地址可能不在这两个锚点之间,无法获取到相应的函数地址也就无法完成初始化工作,这就是要排序的原因。

rt_components_init 是组件的系统级初始化函数,原理与上述函数相同,这里就不赘述了。

入口函数设定

我使用 gnu 工具来编译 rt-thread 工程。进一步阅读源码,我发现系统中并没有使用常规的 main 函数为入口,它使用 entry 函数作为系统执行入口,在 arm-none-eabi-gcc 中设置 -eentry 来以 entry 代替 main,这算是一个技巧吧!

rt-thread 使用心得相关推荐

  1. 关于RT thread系统节拍时钟的配置

    关于RT thread系统节拍时钟的配置                  -----本文基于rt-thread-3.1.3版本编写 首先,使用RTthread OS时,要配置(或者明白)它的系统节拍 ...

  2. rt thread studio使用QBOOT和片外flash实现OTA升级

    我们这里要使用单片机外部flash作为OTA的下载分区,外部flash硬件连接关系 PB3-->SPI3_CLK PB4-->SPI3_MISO PB5-->SPI3_MOSI PE ...

  3. rt thread 使用FAL遇到fal_init() undefined reference

    rt thread FAL 0.5版,之前有没有不知道,遇到一个坑. 在main.cpp里面已经 #include <fal.h> fal_init() 编译报错,说 fal_init() ...

  4. RT Thread Free Modbus移植问题整理

    RT Thread Free Modbus移植问题整理 问题描述: 在读写寄存器中,写数据正常,只能读1个寄存器的值,多个值会异常. 在移植过程中发现串口(或RS485)数据接收长度异常. 一.环境描 ...

  5. Yeelink平台使用——远程控制 RT Thread + LwIP+ STM32

    1.前言     [2014年4月重写该博文]     经过若干时间的努力终于搞定了STM32+LwIP和yeelink平台的数据互通,在学习的过程中大部分时间花在以太网协议栈学习上,但是在RT Th ...

  6. RT Thread根据开发板制作BSP方法

    之前一直不懂怎么使用RT Thread的软件包,感谢网上的大神,看了你们的博客后大概了解一些,在此做下记录.用RT Thread软件包需要RT Thread的系统,但是RT Thread和RT Thr ...

  7. RT Thread之 Uart2 操作

    官网连接:https://docs.rt-thread.org/#/rt-thread-version/rt-thread-standard/programming-manual/device/uar ...

  8. 基于rt thread smart构建EtherCAT主站

    我把源码开源到到了gitee,https://gitee.com/rathon/rt-thread-smart-soem 有兴趣的去可以下载下来跑一下 软件工程推荐用vscode 打开.rt thre ...

  9. RT Thread利用STM32CUBEMX和RT Thread studio来创建模板工程

    (1)RT Thread利用STM32CUBEMX来创建模板工程 1.参考文档: 基于 CubeMX 移植 RT-Thread Nano:RT-Thread 文档中心 注意:串口2必须使能异步模式(启 ...

  10. rt thread系统下添加wiznet软件包后,不插网线CPU利用率100%问题

    rt thread系统下添加wiznet软件包后如果不插网线的话其他任务运行很卡,使用ps命令发现优先级低的任务很多都超时了 rt thread线程错误码 添加了一个可以查看CPU利用率的软件包CPU ...

最新文章

  1. FTP匿名访问修复方法
  2. C#程序 权限不够的解决方案
  3. Python中该使用%还是format来格式化字符串?
  4. Tomcat9 (catalina.bat)控制台日志乱码
  5. map类的erase方法的在Linux与Windows中的差异
  6. 文档下载:《Oracle 20c和19c的新特性解密》
  7. 昇腾AI计算,无惧618冲动消费
  8. 22男人应该明白的道理
  9. TypeError: 'RGB' has type str, but expected one of: bytes(法1)
  10. 2.安装 Android SDK
  11. 商城网站前台html模板,网上购物商城前台模板HTML源码
  12. 射频电路设计中的热量分析
  13. 3D打印是什么?如何工作的?
  14. 计算机办公软件海报,word知识面制作一个图文并茂的宣传海报
  15. 计算机科学中的数学第一章答案,翻译《计算机科学与数学》第一章第四节:我们的公理...
  16. 图形验证码 java
  17. android 高光动画,分享AirDroid高光时刻:它是如何使我高效工作和生活的?
  18. unplugin插件
  19. uni-app z-index无效的解决办法(遮罩层)
  20. 两个月运维工程师的工作总结及心得

热门文章

  1. Python|模拟文件系统
  2. P1_M3_L3 Safety Frameworks for Self Driving(自动驾驶安全框架)
  3. 财务管理 viewthread.php,厦大2017mpacc:一些个人经验和感想
  4. NB模组选型及整体方案注意事项
  5. storm多个bolt之间多对一或一对多下发
  6. 社团划分——Fast Unfolding算法
  7. HD2014 青年歌手大奖赛_评委会打分
  8. html前台数据自动更新,网页数据如何实现实时刷新?
  9. 利用Python定时让微信发送信息
  10. 一号店项目 完整版 代码自取