STM32F1与STM32CubeIDE编程实例-Azure-RTOS ThreadX移植 ThreadX移植 文章目录
1、ThreadX介绍 ThreadX拥有广泛安全认证,并且符合汽车行业软件可靠性协会 MISRA C 标准,是应用最为广泛的嵌入式操作系统之一。ThreadX 实时操作系统已成为全球最受欢迎的实时操作系统之一,已部署在超过 62 亿台设备中,包括消费电子、医疗设备、数据网络应用和 SoC。
ThreadX 提供基于优先级、抢占式调度、快速中断响应、内存管理、线程间通信、互斥、事件通知和线程同步等特性。 ThreadX 的主要区别技术特征包括抢占阈值、优先级继承、高效的定时器管理、快速软件定时器、微微内核设计、事件链和内存占用小。在ARM 架构处理器中需要最小内存尺寸约为 2 KB。
ThreadX 通过非对称多处理 (AMP) 或对称多处理 (SMP) 支持多核处理器环境。带有内存管理单元 (MMU) 或内存保护单元 (MPU) 内存保护的应用程序线程隔离可用于 ThreadX 模块。
本文将详细介绍如何将ThreadX移植到STM32F1中。
2、STM32CubeIDE配置 开发环境搭建、系统时钟配置、调试配置及串口配置,请参考:
3、ThreadX源码配置 第一步:下载ThreadX源码:https://github.com/azure-rtos/threadx,本次使用版本为:`Azure RTOS ThreadX 6.1.11`
第二步:在STM32CubeIDE中创建threadx目录;在工程目录threadx中创建port\cortex_m3\gnu目录和port\cortex_m3\gnu\example_build目录。
第三步:将ThreadX源码目录中的common目录复制到工程目录threadx下。
第四步:将ThreadX源码目录中的port\cortex_m3\gnu\中的inc和src文夹复制到工程目录port\cortex_m3\gnu下。
第五步:将将ThreadX源码目录中的port\cortex_m3\gnu\example_build目录中的tx_initialize_low_level.S文件复制到工程port\cortex_m3\gnu\example_build中。
最终源码结构如下:
4、ThreadX源码移植配置 第一步:修改STM32F1的启动文件startup_stm32f103vetx.s。将ThreadX的全局向量表添加到startup_stm32f103vetx.s文件:
第二步:修改STM32F1的链接文件:STM32F103VETX_FLASH.ld,定义ThreadX的内存:__RAM_segment_used_end_,这个参数在tx_initialize_low_level.S中定义,该文件中ThreadX底层初始化汇编文件。修改如下:
第三步:修改ThreadX时钟(包含时钟频率和节拍),注意这个必须与STM32CubeIDE中配置CPU主频时钟一致。这里将CPU的主频时钟配置为72MHz。因此,修改如下:
最后,需要将ThreadX源码的头文件包含到工程中:
5、移植测试 本次实例将创建两个threadx线程,一个线程用于每1秒向串口输出计数结果;另一个用于每500毫秒闪烁一次LED,并向串口输出计数。
5.1 创建LED闪烁任务 1)基本定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /\* \* led\_blink\_task.h \* \* Created on: May 3, 2022 \* Author: jenson \*/ #ifndef \_\_LED\_BLINK\_TASK\_H\_\_ #define \_\_LED\_BLINK\_TASK\_H\_\_ void create\_led\_task(void); #endif /\* \_\_LED\_BLINK\_TASK\_H\_\_ \*/
2)线程实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 /\* \* led\_blink\_task.c \* \* Created on: May 3, 2022 \* Author: jenson \*/ #include "tx\_api.h" #include "tx\_thread.h" #include <stdio.h> #include "led\_blink\_task.h" #include "gpio.h" TX_THREAD led_thread_handle;// 线程句柄 #define LED\_THREAD\_STACK\_SIZE 512 //线程堆栈大小 uint8\_t led_thread_stack[LED_THREAD_STACK_SIZE]; // 线程句柄 void led\_task\_entry(void \*params) { int counter = 0; printf("[task]led\_task\_entry started\r\n"); for (;;) { printf("[task]led\_blink\_task:counter = %d\r\n", counter); HAL\_GPIO\_TogglePin(LED1_GPIO_Port, LED1_Pin); counter++; tx\_thread\_sleep(500); } } void create\_led\_task(void){ tx\_thread\_create(/\*创建线程\*/ &led_thread_handle, /\*线程句柄\*/ "led\_blink", /\*线程名称\*/ led_task_entry, /\*线程执行函数\*/ NULL, /\*线程函数\*/ led_thread_stack, /\*线程堆栈入口\*/ LED_THREAD_STACK_SIZE, /\*线程堆栈大小\*/ 3, /\*线程优先级\*/ 3, /\*线程抢占阈值\*/ TX_NO_TIME_SLICE, /\*线程时间切片类型,不开启\*/ TX_AUTO_START /\*线程启动类型:自动启动\*/ ); printf("createdd led task\r\n"); }
注意:在ThreadX中,线程堆栈有多种方式,比如,静态、内存池分配、ThreadX默认堆栈内存+偏移等等。
5.2 串口计数线程 1)基本定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /\* \* hello\_task.h \* \* Created on: May 3, 2022 \* Author: jenson \*/ #ifndef \_\_HELLO\_TASK\_H\_\_ #define \_\_HELLO\_TASK\_H\_\_ void create\_hello\_task(void); #endif /\* \_\_HELLO\_TASK\_H\_\_ \*/
2)线程实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 /\* \* hello\_task.c \* \* Created on: May 3, 2022 \* Author: jenson \*/ #include "hello\_task.h" #include "tx\_api.h" #include "tx\_thread.h" #include <stdio.h> TX_THREAD hello_thread_handle; // 线程句柄 #define HELLO\_THREAD\_STACK\_SIZE 512 // 线程堆栈大小 uint8\_t hello_thread_stack[HELLO_THREAD_STACK_SIZE]; // 线程堆栈 void hello\_task\_entry(void \*params) { int counter = 0; printf("[task]hello\_task started\r\n"); for (;;) { printf("[task]hello\_task:counter = %d\r\n", counter); counter++; tx\_thread\_sleep(1000); } } void create\_hello\_task(void){ tx\_thread\_create(/\*创建线程\*/ &hello_thread_handle, /\*线程句柄\*/ "hello\_task", /\*线程名称\*/ hello_task_entry, /\*线程执行函数\*/ NULL, /\*线程函数\*/ hello_thread_stack, /\*线程堆栈入口\*/ HELLO_THREAD_STACK_SIZE, /\*线程堆栈大小\*/ 3, /\*优先级\*/ 3, /\*抢占阈值\*/ TX_NO_TIME_SLICE, /\*线程时间切片类型,不开启\*/ TX_AUTO_START /\*线程启动类型:自动启动\*/ ); printf("created hello task\r\n"); }
5.3 ThreadX内核启动 1)基本定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /\* \* app.h \* \* Created on: May 3, 2022 \* Author: jenson \*/ #ifndef \_\_APP\_H\_\_ #define \_\_APP\_H\_\_ void app\_start(void); #endif /\* \_\_APP\_H\_\_ \*/
2)启动ThreadX内核
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 /\* \* app.c \* \* Created on: May 3, 2022 \* Author: jenson \*/ #include <stdio.h> #include "main.h" #include "app.h" #include "tasks/hello\_task.h" #include "tasks/led\_blink\_task.h" #include "tx\_api.h" #include "tx\_thread.h" void tx\_application\_define(void \*first_unused_memory) { create\_hello\_task(); create\_led\_task(); } void app\_start(void) { tx\_kernel\_enter(); }
在 tx_application_define 完成后,控制权被转移到线程调度程序并从那里转移到每个单独的线程。
3)主程序
在main.c文件中添加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 /\* Private includes ----------------------------------------------------------\*/ /\* USER CODE BEGIN Includes \*/ #include "app.h" #include <stdio.h> /\* USER CODE END Includes \*/ int main(void) { /\* USER CODE BEGIN 1 \*/ /\* USER CODE END 1 \*/ /\* MCU Configuration--------------------------------------------------------\*/ /\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/ HAL\_Init(); /\* USER CODE BEGIN Init \*/ /\* USER CODE END Init \*/ /\* Configure the system clock \*/ SystemClock\_Config(); /\* USER CODE BEGIN SysInit \*/ /\* USER CODE END SysInit \*/ /\* Initialize all configured peripherals \*/ MX\_GPIO\_Init(); MX\_USART1\_UART\_Init(); /\* USER CODE BEGIN 2 \*/ printf("\*\*\*\*STM32CubeIDE:ThreadX Demo\*\*\*\*\r\n"); // 启动ThreadX内核 app\_start(); /\* USER CODE END 2 \*/ /\* Infinite loop \*/ /\* USER CODE BEGIN WHILE \*/ while (1) { /\* USER CODE END WHILE \*/ /\* USER CODE BEGIN 3 \*/ } /\* USER CODE END 3 \*/ }
运行结果:
至此,ThreadX的移植基本完成,让我们开启ThreadX的学习之旅吧!!
文章来源: https://iotsmart.blog.csdn.net/article/details/125071735
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!