【STM32H750】玩转ART-Pi(八)——添加动态模块

发布于 2020-11-30 11:08:38

目录

【STM32H750】玩转ART-Pi(一)——使用STM32CUBMX生成TouchGFX工程
【STM32H750】玩转ART-Pi(二)——制作MDK的外部QSPI-FLASH烧录算法
【STM32H750】玩转ART-Pi(三)——如何在ART-PI上创建TouchGFX工程
【STM32H750】玩转ART-Pi(四)——添加文件系统
【STM32H750】玩转ART-Pi(五)——添加网络功能
【STM32H750】玩转ART-Pi(六)——添加FTP服务器
【STM32H750】玩转ART-Pi(七)——TouchGFX从文件系统中读取图片
【STM32H750】玩转ART-Pi(八)——添加动态模块

实验平台:

硬件: RT-Thread官方ART-PI H750开发版
软件: RT-Thread Studio 1.1.5

代码下载:

演示代码下载地址:https://download.csdn.net/download/sinat_31039061/13196914

联系作者:

加我微信,备注“加群”,加入技术交流群
在这里插入图片描述

动态模块简介

在传统桌面操作系统中,用户空间和内核空间是分开的,应用程序运行在用户空间,内核以及内核模块则运行于内核空间,其中内核模块可以动态加载与删除以扩展内核功能。dlmodule 则是 RT-Thread 下,在内核空间对外提供的动态模块加载机制的软件组件。在 RT-Thread v3.1.0 以前的版本中,这也称之为应用模块(Application Module),在 RT-Thread v3.1.0 及之后,则回归传统,以动态模块命名。

dlmodule 组件更多的是一个 ELF 格式加载器,把单独编译的一个 elf 文件的代码段,数据段加载到内存中,并对其中的符号进行解析,绑定到内核导出的 API 地址上。动态模块 elf 文件主要放置于 RT-Thread 下的文件系统上。
动态模块为 RT-Thread 提供了动态加载程序模块的机制,因为也独立于内核编译,所以使用方式比较灵活。从实现上讲,这是一种将内核和动态模块分开的机制,通过这种机制,内核和动态模块可以分开编译,并在运行时通过内核中的模块加载器将编译好的动态模块加载到内核中运行。

在 RT-Thread 的动态模块中,目前支持两种格式:

  • .mo 则是编译出来时以 .mo 做为后缀名的可执行动态模块;它可以被加载,并且系统中会自动创建一个主线程执行这个动态模块中的 main 函数;同时这个 main(int argc, char**argv) 函数也可以接受命令行上的参数。
  • .so 则是编译出来时以 .so 做为后缀名的动态库;它可以被加载,并驻留在内存中,并提供一些函数集由其他程序(内核里的代码或动态模块)来使用。

当前 RT-Thread 支持动态模块的架构主要包括 ARM 类架构和 x86 架构,未来会扩展到 MIPS,以及 RISC-V 等架构上。RT-Thread 内核固件部分可使用多种编译器工具链,如 GCC, ARMCC、IAR 等工具链;但动态模块部分编译当前只支持 GNU GCC 工具链编译。因此编译 RT-Thread 模块需下载 GCC 工具,例如 CodeSourcery 的 arm-none-eabi 工具链。一般的,最好内核和动态模块使用一样的工具链进行编译(这样不会在 libc 上产生不一致的行为)。另外,动态模块一般只能加载到 RAM 中使用,并进行符号解析绑定到内核导出的 API 地址上,而不能基于 Flash 直接以 XIP 方式运行(因为 Flash 上也不能够再行修改其中的代码段)。

官方动态模块文档介绍:https://www.rt-thread.org/document/site/programming-manual/dlmodule/dlmodule/

添加动态模块

  1. 新建工程

在这里插入图片描述

  1. 打开动态模块

在这里插入图片描述

  1. 在rtconfig.py 中设置动态模块编译时需要用到的配置参数
M_CFLAGS = CFLAGS + ' -mlong-calls -fPIC '
M_CXXFLAGS = CXXFLAGS + ' -mlong-calls -fPIC'
M_LFLAGS = DEVICE + CXXFLAGS + ' -Wl,--gc-sections,-z,max-page-size=0x4' +\
                                ' -shared -fPIC -nostartfiles -nostdlib -static-libgcc'
M_POST_ACTION = STRIP + ' -R .hash $TARGET\n' + SIZE + ' $TARGET \n'
M_BIN_PATH = r'E:\qemu-dev310\fatdisk\root'

相关的解释如下:

  • M_CFLAGS - 动态模块编译时用到的 C 代码编译参数,一般此处以 PIC 方式进行编译(即代码地址支持浮动方式执行);
  • M_CXXFLAGS - 动态模块编译时用到的 C++ 代码编译参数,参数和上面的 M_CFLAGS 类似;
  • M_LFLAGS - 动态模块进行链接时的参数。同样是 PIC 方式,并且是按照共享库方式链接(部分链接);
  • M_POST_ACTIOn - 动态模块编译完成后要进行的动作,这里会对 elf 文件进行 strip 下,以减少 elf 文件的大小;
  • M_BIN_PATH - 当动态模块编译成功时,对应的动态模块文件是否需要复制到统一的地方;

在这里插入图片描述

  1. 添加符号表

内核固件也会通过 RTM(function) 的方式导出一些函数 API 给动态模块使用,这些导出符号可以在 msh 下通过命令:
list_symbols
列出固件中所有导出的符号信息。dlmodule 加载器也是把动态模块中需要解析的符号按照这里导出的符号表来进行解析,完成最终的绑定动作。
这段符号表会放在一个专门的,名字是 RTMSymTab 的 section 中,所以对应的固件链接脚本也需要保留这块区域,而不会被链接器优化移除掉。可以在链接脚本中添加对应的信息:

/* section information for modules */
. = ALIGN(4);
__rtmsymtab_start = .;
KEEP(*(RTMSymTab))
__rtmsymtab_end = .;

然后在工程目录下执行一下命令:scons --target=ua -s,来生成编译动态模块时需要包括的内核头文件搜索路径及全局宏定义。
在这里插入图片描述

  1. 编译下载

打开map文件,可以看到导出的符号表
在这里插入图片描述
在 msh 下通过list_symbols命令,可以查看导出的API列表:
在这里插入图片描述

编译动态模块

在 github 上有一份独立仓库: rtthread-apps ,这份仓库中放置了一些和动态模块,动态库相关的示例。
其目录结构如下:
在这里插入图片描述
可以把这份 git clone 到本地,然后在命令行下以 scons 工具进行编译,如果是 Windows 平台,推荐使用 RT-Thread/ENV 工具。

进入控制台命令行后,进入到这个 rtthread-apps repo 所在的目录(同样的,请保证这个目录所在全路径不包含空格,中文字符等字符),并设置好两个变量:

  • RTT_ROOT - 指向到 RT-Thread 代码的根目录;
  • BSP_ROOT - 指向到 BSP 的工程目录;

Windows 下可以使用 (例如本工程):
在这里插入图片描述

添加文件系统

参考【STM32H750】玩转ART-Pi(四)——添加文件系统

运行hello.mo

把编译出来的hello.mo文件拷贝到文件系统中,然后运行它:
在这里插入图片描述
关注公众号,后续有精彩内容会第一时间发送给您!
在这里插入图片描述

1 条评论

发布
问题