风过空庭,字句正徐来。
关于关于本站关于我给我点钱
更多时间线友链文件服务wiki
联系写留言发邮件GitHub
© 2024-2026 yono. | RSS 订阅 | 站点地图 | | Stay hungry. Stay foolish.
Powered by Mix Space&
白い
.
| 粤 ICP 备2024284785号-1 |
正在被0人看爆
纸白微明,未成篇章。

最全认证 RTOS——azure_threadX 移植教程

(已编辑)
/
813
AI·GEN

关键洞察

这篇文章上次修改于,可能部分内容已经不适用,如有疑问可询问作者。

最全认证 RTOS——azure_threadX 移植教程

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Note

    有一定cmake基础的读者建议直接查看 再谈 threadX 移植 - 土星环的基地

    ThreadX 内核内容介绍

    threadx 已捐赠给 eclipse 基金会,目前的开源代码在这里。

    我使用的通常是 st 公司的 fork,实际上的支持并没有好多少,该有的坑也还是有

    ThreadX 内核包含三个内容:ThreadX 操作系统内核,Modules 模组、trace 调试监测。在 ThreadX 源码中,这些内容很多是混杂在一起的。所以简单写一个文档记录一下。即是移植教程,也记录库结构。

    image-20250120113105909

    image-20250120113105909
    本文档所有的图片,都在图片相关描述文字的上方。这是 threadX 源码的所有内容

    其中显示出了系统内核的三个版本

    • common 普通内核
    • common_module 具有模组加载功能的内核,硬件驱动与软件逻辑可完全分离
    • common_smp 具有多核 MCU 支持的内核

    内核移植目标是使用这些组件

    • ThreadX 操作系统内核
    • Modules 模组
    • Trace 调试监控

    纯内核移植

    纯内核是我说的——相对于modules版内核和smp版内核,实际上与 freertos、bios 这类普通 RTOS 功能无异,只是移植 threadX 系其他组件更方便,命名也更一致,例如 NetX、usbX、FileX 都可以非常简单加入系统。

    哪些是纯内核源码?

    image-20250120113135771

    image-20250120113135771

    在 threadX 操作系统源码中,有如图框出的两个文件夹,这两个文件夹实际上就是我们移植操作系统内核需要的所有源码了

    image-20250120113144296

    image-20250120113144296

    首先关注到 common 文件夹,这些实际上都是需要的源码,也就是我们的工程需要的文件,但仍然有一些值得注意的地方。

    image-20250120113152696

    image-20250120113152696

    在 stc 文件夹下,有一些 tx_trace_xx 命名的源码文件,这些是 trace 调试监测使用的源码

    image-20250120113211734

    image-20250120113211734

    以这个开启监控的函数为例,如果没有使用 TX_ENABLE_EVENT_TRACE 宏定义进行开启监控功能,那么这个函数是不会做任何事情的

    image-20250120113221624

    image-20250120113221624

    在 inc 文件夹下,也有一个 tx_trace.h 的文件。

    image-20250120113231145

    image-20250120113231145

    没有开启 TX_ENABLE_EVENT_TRACE 宏定义,也是几乎不做任何事情。

    image-20250120113327255

    image-20250120113327255

    回到源码文件夹,再关注到 ports 文件夹

    image-20250120113335373

    image-20250120113335373

    找到自己对应的内核

    image-20250120113343609

    image-20250120113343609

    找到自己对应的编译器,源码和头文件都是工程所需,另外要注意的是排除可能存在的这个文件 tx_misra.S,可能已经有 tx_misra.c 定义了

    image-20250120113358035

    image-20250120113358035

    简单介绍一下ports/内核名/编译器名/inc中的tx_port.h文件,这里是调整 threadX 的唯一接口,类似TX_ENABLE_EVENT_TRACE这样控制操作系统的功能开启与否的宏定义,可以写在编译器整体 define 处。

    但是关注到第79行,他给了一个另外的.h 接口供我们定义。我们可以将TX_INCLUDE_USER_DEFINE_FILE宏定义写在编译器整体 define 中然后通过自定义一个tx_user.h文件来控制操作系统宏定义。

    这个tx_user.h文件有一个示例,在操作系统源码common\inc下有名为tx_user_sample.h或类似的文件作为示例,但是tx_user.h这个文件名需要自己创建或改名他的示例文件。

    image-20250120113414656

    image-20250120113414656

    在 common\src 下有这样一个 tx_thread_initialize.c,其中有一个变量可以在运行时查看配置状况。这个变量同时在 tx_thread.h 中被 extern 声明,所以使用 threadX 操作系统时可以随地查看这个变量且不可重复声明。

    应该如何开启?

    image-20250120113428701

    image-20250120113428701

    虽然我们使用 ac6编译器,仍然可以先关注一下 gnu 文件夹,因为其中有一个简单的创建任务的示例

    image-20250120113436203

    image-20250120113436203

    在这里!

    image-20250120113446122

    image-20250120113446122

    简单分析示例

    1. 这部分是头文件,仅仅包含了 tx_api.h
    2. 这部分是 main 入口
    3. 这部分是一个固定需要自己定义的函数,这个函数名在_tx_initialize_kernel_enter()开启 thread 内核时会进行调用,实际上就是内核开启后给我们用户程序的接口,。
    image-20250120113503114

    image-20250120113503114

    简单分析一下这个用户接口函数的话,其实就是将 threadX 的几个主要 api 演示了一遍,申请内存空间,使用这片内存空间创建任务,创建消息队列,创建消息量等等常见常用的 API,具体如何使用可以自行看源码。

    结合整个示例,我们知道使用 threadX 内核的最基本操作:

    1. 包含tx_api.h
    2. 定义void tx_application_define(void *first_unused_memory)这个函数,并在这个函数调用后再创建任务(此时 threadX 内核已经开启)
    3. 主程序中使用tx_kernel_enter();函数开启 threadX 内核

    关注到与示例同文件夹下的这个文件

    image-20250120113526759

    image-20250120113526759

    其中定义了一些中断函数,用于接管芯片的中断处理,使 threadX 操作系统运行起来,注意修改SYSTEM_CLOCK和SYSTICK_CYCLES,在如图示例中,600000代表芯片主频时钟是6M,100代表操作系统的时钟基准是10ms,也就是tx_thread_sleep(1);实际上是释放内核10ms

    其实这个.S 文件仍然有需要修改的地方,似乎是某些中断没有定义,最好是使用 stm32cubeMX 自动生成一个,然后粘到自己工程里,如果操作系统没有正常运行,最大的可能是这个 tx_initialize_low_level.s 有问题

    image-20250120113610189

    image-20250120113610189

    编译器整体 Define 添加这样一条TX_INCLUDE_USER_DEFINE_FILE

    带模组管理器的内核移植

    首先确认一个概念,模组管理器和模组是什么?

    模组管理器具有 threadX 内核,具有驱动硬件的能力,可以从某些存储介质内加载模组的可执行二进制内容(例如从片内 flash 的0x8100000这个地址开始加载模组;模组不具有驱动硬件的能力,没有 threadX 内核,无法单独工作,但是作为一个单独的工程存在,可以独立编译发布。

    也就是模组管理器和模组是两个工程,同时他们需要移植的源码是不同的。

    至于有什么必要做这样的事情,不在这里讨论。

    哪些是带模组管理器的源码?

    image-20250120113627567

    image-20250120113627567

    可以先不管那么多,将这三个文件夹都粘进自己的工程再说在 threadX 操作系统源码中,有如图框出的三个文件夹,这三个文件夹内有移植带模组管理器的内核的所有源码

    由于默认已经看过纯内核移植的内容了,认为对基础内核以及 trace 调试追踪有一定了解。所以这些内容不再赘述,仅讨论与纯内核不同的点。

    关注到common_modules文件夹

    image-20250120113919648

    image-20250120113919648

    作为模组管理器的内核,需要的是框起来的两个源码文件夹,而 module_lib 是给模组移植的源码。

    可以先不管那么多,将这两个文件夹的所有内容都包含进自己的工程再说,后续再做调整

    image-20250120114052337

    image-20250120114052337

    关注到ports_modules文件夹

    image-20250120114059902

    image-20250120114059902

    找到自己对应的架构

    image-20250120114113463

    image-20250120114113463

    找到自己对应的编译器

    image-20250120114125196

    image-20250120114125196

    需要的是框起来的两个源码文件夹,而 module_lib 是给模组移植的源码。

    不管那么多,将这两个文件夹的所有内容都包含进自己的工程再说,后续再做调整

    image-20250120114148306

    image-20250120114148306

    然后从例程找到或者使用 stm32cubeMX 自动生成一个tx_initialize_low_level.S,由于 stm32cubeMX 不支持生成 modules 工程,事实上也不适合,能顺利使用 modules 需要大量自己的适配和操作。
    在如图这个工程中,推荐从例程中寻找。

    在纯内核移植中已经介绍过tx_initialize_low_level.S了,不再赘述。

    image-20250120114214674

    image-20250120114214674

    回到这个文件夹下,找到名为txm_module_user_sample.h的文件,复制一份改名为txm_module_user.h,当编译器整体 define 设置有TXM_MODULE_INCLUDE_USER_DEFINE_FILE时,在模组管理器工程和模组工程中都会调用名为txm_module_user.h的头文件(必须是相同的),以控制操作系统功能

    image-20250120114227489

    image-20250120114227489

    txm_module_user.h中大致是这样的内容

    记得tx_user.h也需要创建,在纯内核中有说明

    应该如何开启

    实际上与纯内核的开启方法一样。但注意这种内核使用时,标准的做法是将业务逻辑都做成模组进行加载,但是模组工程的建立以及二者的适配也挺麻烦的,目前还没完全搞清楚,所以也没有做成文档。

    但就把它当作普通内核使用也是没有问题的。