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

2024 年 7 月 15 日 星期一(已编辑)
/
159

最全认证 RTOS——azure_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_CLOCKSYSTICK_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也需要创建,在纯内核中有说明

应该如何开启

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

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

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...