stm32开发之threadx+modulex组合开发使用记录

前言

  1. 参考博客 论坛
  2. 官方资料: 微软
  3. 开发板核心芯片使用的是stm32f407zgtx,烧录工具使用的是jlink
  4. 模块的构建使用的是脚本进行构建
  5. 网上针对modulex的资料较少,这里做个记录

项目结构

在这里插入图片描述

逻辑框架

在这里插入图片描述

主程序代码

在这里插入图片描述

主函数

/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-4-4     shchl   first version*/
#include "includes.h"/*** @brief app 入口函数* @return*/
int main() {/*系统初始化*/System_Init();/*挂起hal tick*/HAL_SuspendTick();/*进入threadx 内核*/tx_kernel_enter();while (1) {printf("app run\r\n");HAL_Delay(1000);}return 0;
}

app_threadx

/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-4-4     shchl   first version*** tx_kernel_enter() 执行逻辑(关键)*   TX_PORT_SPECIFIC_PRE_INITIALIZATION----可扩展*    _tx_initialize_low_level() --- 设备层(寄存器)初始化*    _tx_initialize_high_level() --- tx os 内部相关初始化*   TX_INITIALIZE_KERNEL_ENTER_EXTENSION----可扩展*     tx_application_define(_tx_initialize_unused_memory);*   TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION ---可扩展**/#include "includes.h"#define APP_MAIN_STACK_SIZE 2048
#define APP_MEM_ALLOC_STATIC_ENABLE (0) /*静态内存分配使能*//*
*******************************************************************************************************
*                               外部引入变量
*******************************************************************************************************
*/
extern void app_component_init(void);/*
*******************************************************************************************************
*                               变量
*******************************************************************************************************
*//*
*********************************************************************************************************
*                                       静态全局变量
*********************************************************************************************************
*/
static TX_THREAD app_start_thread; /*应用启动线程*/
/*
*********************************************************************************************************
*                                      函数声明
*********************************************************************************************************
*/
static void app_start_entry(ULONG input);
/*
*********************************************************************************************************
*                                      内部函数
*********************************************************************************************************
*/static void app_start_entry(ULONG input) {/*恢复 HAL 时基*/HAL_ResumeTick();/*外设初始化*/bsp_Init();/*应用组件初始化*/app_component_init();while (1) {/* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */bsp_ProPer1ms();tx_thread_sleep(1);}
}/*** @brief  应用组件定义初始化* @param  first_unused_memory : 指向第一个未使用的内存的指针* @retval None*/
VOID tx_application_define(VOID *first_unused_memory) {UINT stat;
#if APP_MEM_ALLOC_STATIC_ENABLE
#define TX_STATIC_MEM_SIZE (60*1024) /*静态内存字节数*//*内存池初始化*/static uint8_t mem_pool_area[TX_STATIC_MEM_SIZE];tx_mem_pool_static_init(mem_pool_area, TX_STATIC_MEM_SIZE);
#elseif (first_unused_memory) {tx_mem_pool_init(first_unused_memory);} else {// todo 未使用动态内存,后面禁止使用 app_malloc 函数}
#endifstat = tx_thread_create(&app_start_thread, "app start thread",app_start_entry, 0,app_malloc(APP_MAIN_STACK_SIZE), APP_MAIN_STACK_SIZE,2, 2,TX_NO_TIME_SLICE, TX_AUTO_START);if (stat != TX_SUCCESS) {/*错误处理: 线程创建失败*/Error_Handler();}}

日志

/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-4-4     shchl   first version*/
#include "includes.h"/*
*******************************************************************************************************
*                               外部引入变量
*******************************************************************************************************
*/
extern TX_MUTEX AppPrintfSemp;    /* 用于printf互斥 */
/*
*******************************************************************************************************
*                               变量
*******************************************************************************************************
*//*
*********************************************************************************************************
*                                       静态全局变量
*********************************************************************************************************
*/
static char buf_str[TX_LOG_BUF_SZ] = {0}; /* 特别注意,如果printf的变量较多,注意此局部变量的大小是否够用 */
/*
*********************************************************************************************************
*                                      函数声明
*********************************************************************************************************
*//*
*********************************************************************************************************
*                                      外部函数
*********************************************************************************************************
*/
void tx_log(const char *fmt, ...) {va_list v_args;va_start(v_args, fmt);int len = vsnprintf((char *) &buf_str[0],(size_t) sizeof(buf_str),(char const *) fmt,v_args);va_end(v_args);/* 互斥操作 */tx_mutex_get(&AppPrintfSemp, TX_WAIT_FOREVER);if (len > TX_LOG_BUF_SZ - 1) {len = TX_LOG_BUF_SZ - 1;}buf_str[len] = '\0';printf("%s", buf_str);tx_mutex_put(&AppPrintfSemp);}void tx_log_no_mutex(const char *fmt, ...) {va_list v_args;va_start(v_args, fmt);(void) vsnprintf((char *) &buf_str[0],(size_t) sizeof(buf_str),(char const *) fmt,v_args);va_end(v_args);/* 互斥操作 */printf("%s", buf_str);
}

内存管理

/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-4-9     shchl   first version*/
#include "includes.h"#define RAM_START              (0x20000000)   /*ram起始地址*/
#define RAM_SIZE               (128 * 1024)   /*总大小*/
#define RAM_END                (RAM_START + RAM_SIZE) /*结束地址*/#define STAND_C_LIB      0  /*使用c标准库提供的内存分配函数进行管理*/
#define TX_BYTE_POOL_MEM 1  /*使用threadx提供的字节池对象进行内存分配管理*/
#define MEM_MANAGER_MODE TX_BYTE_POOL_MEM
/*
*********************************************************************************************************
*                                       静态全局变量
*********************************************************************************************************
*/
static TX_BYTE_POOL g_byte_pool; /*全局字节池*/
static ULONG mem_size;  /*内存总大小(字节)*//*
*********************************************************************************************************
*                                      外部函数
*********************************************************************************************************
*/
/*** @brief 内存池初始化* @param start_addr 其实地址*/
void tx_mem_pool_init(void *start_addr) {
#if MEM_MANAGER_MODE == TX_BYTE_POOL_MEM// 地址对齐-保证4字节 内部已处理这里就不需要进行字节对齐处理了ULONG begin_align =(ULONG) start_addr;mem_size = (RAM_END - begin_align); /*动态内存总大小(字节)*//*通过threadx 提供的字节池对象进行管理动态内存空间*/if (tx_byte_pool_create(&g_byte_pool, "heap",start_addr, mem_size) != TX_SUCCESS) {/*错误处理*/Error_Handler();}#elif MEM_MANAGER_MODE == TX_BYTE_POOL_MEM
#endif
}void tx_mem_pool_static_init(void *start_addr, uint16_t byte_cnt){mem_size = byte_cnt; /*动态内存总大小(字节)*//*通过threadx 提供的字节池对象进行管理动态内存空间*/if (tx_byte_pool_create(&g_byte_pool, "heap",start_addr, mem_size) != TX_SUCCESS) {/*错误处理*/Error_Handler();}}/*** @brief 内存分配* @param size 分配大小(字节)* @return 指向分配内存的首地址*/
void *app_malloc(ULONG size) {
#if MEM_MANAGER_MODE == TX_BYTE_POOL_MEMstatic void *mem_ptr = NULL; /*这里要用全局静态变量,不能放在栈上面*/tx_byte_allocate(&g_byte_pool, (void **) &mem_ptr,size, TX_NO_WAIT);return mem_ptr;
#elsereturn malloc(size);
#endif}/*** @brief 释放内存* @param mem_ptr*/
void app_free(void *mem_ptr) {
#if MEM_MANAGER_MODE == TX_BYTE_POOL_MEMtx_byte_release(mem_ptr);
#elsefree(mem_ptr);
#endif}/*** @brief 重新分配内存空间* @param ptr 原始内存指向的指针* @param size 重新分配的大小* @return 新分配内存空间的首地址*  @note 需要用返回回去的指针覆盖原始指针,防止重新分配的内存首地址发生改变*/
void *app_realloc(void *ptr, ULONG size) {
#if MEM_MANAGER_MODE == TX_BYTE_POOL_MEMvoid *nw_ptr = app_malloc(size);memcpy(nw_ptr, ptr, size);app_free(ptr);return nw_ptr;#elsereturn realloc(ptr,size);
#endif}

模块管理

#include "includes.h"
#include "txm_module.h"#define APP_MODULE_MANAGER_STACK_SIZE                          4096U /*模块管理栈字节大小*/
#define APP_MODULE_MANAGER_THREAD_PRIORITY                     4     /*模块管理线程优先级*/
#define APP_MODULE_MANAGER_THREAD_PREEMPTION_THRESHOLD         APP_MODULE_MANAGER_THREAD_PRIORITY /*模块管理抢占阈值优先级*/#define MODULE_DATA_SIZE           (20*1024)  /* 供动态APP使用 */
#define OBJECT_MEM_SIZE            (32*1024)    /* 供动态APP的动态内存管理申请使用 */
enum {READY_FLAG, /*未启动*/STARTED_FLAG, /*已启动*/
};
/*** @brief 模块信息结构体*/
struct module_info_struct {uint8_t start_flag; /*启动标志位*/char *module_name; /*模块名*/uint32_t load_addr; /*加载地址地址*/TXM_MODULE_INSTANCE instance;  /* 模块实例 */
};
/*
*******************************************************************************************************
*                               外部引入变量
*******************************************************************************************************
*//*
*******************************************************************************************************
*                               变量
*******************************************************************************************************
*/
struct module_info_struct module_tbl[] = {{READY_FLAG, "app module 01", 0x08020000U},{READY_FLAG, "app module 02", 0x08040000U}
};
#define MODULE_TBL_SIZE (sizeof(module_tbl)/sizeof(module_tbl[0]))TX_QUEUE ResidentQueue;       /* 消息队列,用于主程序和动态APP通信 */
uint32_t MessageQueuesBuf[100];/*
*********************************************************************************************************
*                                       静态全局变量
*********************************************************************************************************
*/
static TX_THREAD module_manager_thread; /*模块管理线程*/
static ULONG memory_faults = 0;
static UCHAR *module_data_area;
static UCHAR *object_memory;/*
*********************************************************************************************************
*                                      函数声明
*********************************************************************************************************
*/
static void app_txm_module_info_out(TXM_MODULE_INSTANCE *instance, ULONG prop);static VOID module_fault_handler(TX_THREAD *thread, TXM_MODULE_INSTANCE *module);static void app_module_load(uint8_t idx);static void app_module_unload(uint8_t idx);static VOID module_manager_entry(ULONG thread_input);
/*
*********************************************************************************************************
*                                      外部函数
*********************************************************************************************************
*//*
*********************************************************************************************************
*	函 数 名: module_application_define
*	功能说明: 创建 模块管理任务线程
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
int module_application_define(void) {/*模块 分配内存空间*/object_memory = app_malloc(OBJECT_MEM_SIZE);module_data_area = app_malloc(MODULE_DATA_SIZE);/* 创建动态APP管理器任务  */if (tx_thread_create(&module_manager_thread, "Module Manager Thread",module_manager_entry, 0,app_malloc(APP_MODULE_MANAGER_STACK_SIZE), APP_MODULE_MANAGER_STACK_SIZE,APP_MODULE_MANAGER_THREAD_PRIORITY, APP_MODULE_MANAGER_THREAD_PREEMPTION_THRESHOLD,TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS) {Error_Handler();}/* 创建常驻消息队列 */if (tx_queue_create(&ResidentQueue, "Resident Queue",TX_1_ULONG, MessageQueuesBuf,16 * sizeof(ULONG)) != TX_SUCCESS) {Error_Handler();}return TX_SUCCESS;
}TX_THREAD_EXPORT_LV1(module_application_define); /*首先创建模块应用*//*
*********************************************************************************************************
*	函 数 名: module_manager_entry
*	功能说明: 动态加载管理任务。
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/static VOID module_manager_entry(ULONG thread_input) {TX_PARAMETER_NOT_USED(thread_input);UINT status;uint8_t cmd;/* 初始化动态加载管理器,主要是给动态APP的数据空间使用  */status = txm_module_manager_initialize((VOID *) module_data_area, MODULE_DATA_SIZE);if (status != TX_SUCCESS) {Error_Handler();}/* 供动态APP使用的对象内存池,主要各种控制块申请 */status = txm_module_manager_object_pool_create(object_memory, OBJECT_MEM_SIZE);if (status != TX_SUCCESS) {Error_Handler();}/* 注册faults管理 */status = txm_module_manager_memory_fault_notify(module_fault_handler);if (status != TX_SUCCESS) {Error_Handler();}while (1) {if (comGetChar(COM1, &cmd))    /* 从串口读入一个字符(非阻塞方式) */{switch (cmd) {/* 加载APP1 */case '1':app_module_load(0);break;/* 卸载APP1 */case '2':app_module_unload(0);break;/* 加载APP2 */case '3':app_module_load(1);break;/* 卸载APP2 */case '4':app_module_unload(1);break;/* 打印任务执行情况 */case '5':app_task_info_out();break;default:break;}}tx_thread_sleep(1);}
}/*
*********************************************************************************************************
*	函 数 名: module_fault_handler
*	功能说明: 监测faults
*	形    参: ---
*	返 回 值: 无
*********************************************************************************************************
*/
static VOID module_fault_handler(TX_THREAD *thread, TXM_MODULE_INSTANCE *module) {tx_log("module_fault_handler: thread[%s],module[%s]\r\n", thread->tx_thread_name, module->txm_module_instance_name);/* 统计错误消息  */memory_faults++;
}/*** @brief 加载模块* @param idx 模块下标*/
static void app_module_load(uint8_t idx) {UINT status;ULONG module_properties;struct module_info_struct *module_inf;if (idx >= MODULE_TBL_SIZE) {tx_log("load idx(%d) out of bound\r\n", idx);return;}/*模块信息*/module_inf = &module_tbl[idx];if (module_inf->start_flag == STARTED_FLAG) {tx_log("module(%s) already started \r\n", module_inf->module_name);return;}/* 加载动态APP */status = txm_module_manager_in_place_load(&module_inf->instance,module_inf->module_name,(VOID *) module_inf->load_addr);if (status) {tx_log("txm_module_manager_in_place_load error:[%d]\r\n", status);return;}/* 获取动态APP属性 */status = txm_module_manager_properties_get(&module_inf->instance, &module_properties);if (status) {tx_log("txm_module_manager_properties_get error:[%d]\r\n", status);return;}/*模块信息打印*/app_txm_module_info_out(&module_inf->instance, module_properties);/* 启动动态APP */status = txm_module_manager_start(&module_inf->instance);tx_thread_sleep(1000);if (status != TX_SUCCESS) {tx_log("txm_module_manager_start error:[%d]\r\n", status);return;}/*更新信息*/module_inf->start_flag = STARTED_FLAG;tx_log("Module execution is started\n");}/*** @brief 卸载模块* @param idx 模块下标*/
static void app_module_unload(uint8_t idx) {UINT status;struct module_info_struct *module_inf;if (idx >= MODULE_TBL_SIZE) {tx_log("load idx(%d) out of bound\r\n", idx);return;}/*模块信息*/module_inf = &module_tbl[idx];if (module_inf->start_flag == STARTED_FLAG) { /*已经启动,才会卸载*//* 停止动态APP */status = txm_module_manager_stop(&module_inf->instance);if (status != TX_SUCCESS) {tx_log("==========================MODULE(%s) STOP ERR(%d)========================\r\n",module_inf->module_name, status);return;}/* 卸载动态APP */status = txm_module_manager_unload(&module_inf->instance);if (status != TX_SUCCESS) {tx_log("==========================MODULE(%s) UNLOAD ERR(%d)========================\r\n",module_inf->module_name, status);return;}tx_log("==========================MODULE(%s) UNLOAD OK========================\r\n", module_inf->module_name);} else {tx_log("==========================MODULE(%s) NOT STARTED========================\r\n", module_inf->module_name);}}static void app_txm_module_info_out(TXM_MODULE_INSTANCE *instance, ULONG prop) {tx_log("===============================app_txm_module_info_out================================\r\n");tx_log("------------------module build info------------------\r\n");tx_log("\t--Compiled for %s compiler\r\n",((prop >> 25) == 1) ? "CubeIDE (GNU)" : ((prop >> 24) == 1) ? "ARM KEIL" : "IAR EW");tx_log("\t--Shared/external memory access is %s\r\n", ((prop & 0x04) == 0) ? "Disabled" : "Enabled");tx_log("\t--MPU protection is %s\r\n", ((prop & 0x02) == 0) ? "Disabled" : "Enabled");tx_log("\t--%s mode execution is enabled for the module\r\n\r\n", ((prop & 0x01) == 0) ? "Privileged" : "User");tx_log("------------------module application info------------------\r\n");tx_log("\t--application id %#x;instance id:%#x;name:%s\r\n",instance->txm_module_instance_application_module_id,instance->txm_module_instance_id,instance->txm_module_instance_name);tx_log("\t--code section【start addr: %#x||end addr:%#x||size(bytes):%d】\r\n",instance->txm_module_instance_code_start,instance->txm_module_instance_code_end,instance->txm_module_instance_code_size);tx_log("\t--data section【start addr: %#x||end addr:%#x||size(bytes):%d】\r\n",instance->txm_module_instance_data_start,instance->txm_module_instance_data_end,instance->txm_module_instance_data_size);tx_log("\t--shared_memory 【addr:%#x||size(bytes): %d】\r\n",instance->txm_module_instance_shared_memory_address,instance->txm_module_instance_shared_memory_length);}

主程序和模块的通信

/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-4-13     shchl   first version*/
#include "includes.h"
#include "txm_module.h"#define App_Printf_ID1       (TXM_APPLICATION_REQUEST_ID_BASE)
#define App_Printf_ID2       (TXM_APPLICATION_REQUEST_ID_BASE + 1)UINT module_manager_application_request(ULONG request_id,ALIGN_TYPE param_1,ALIGN_TYPE param_2,ALIGN_TYPE param_3) {switch (request_id) {/* 执行函数printf */case App_Printf_ID1:printf("执行APP1的打印函数:%lu\r\n", param_1);return TX_SUCCESS;/* 执行函数printf */case App_Printf_ID2:printf("执行APP2的打印函数:%lu\r\n", param_1);return TX_SUCCESS;default:{printf("module_manager_application_request:%lu not available\r\n",request_id);return TX_NOT_AVAILABLE;}}}

cpu 任务状态线程(未使用到threadx的内部工具代码)

/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-4-4     shchl   first version*/
#include "includes.h"
/*
*******************************************************************************************************
*                               任务相关宏定义
*******************************************************************************************************
*/
#define APP_TASK_CPU_STAT_PRIO 30
#define APP_TASK_CPU_STAT_STK_SIZE 1024
/*
*******************************************************************************************************
*                               外部引入变量
*******************************************************************************************************
*/
#if defined(TX_EXECUTION_PROFILE_ENABLE)
extern EXECUTION_TIME _tx_execution_idle_time_total;
extern EXECUTION_TIME _tx_execution_thread_time_total;
extern EXECUTION_TIME _tx_execution_isr_time_total;
#endif/*
*******************************************************************************************************
*                               变量
*******************************************************************************************************
*/
__IO double OSCPUUsage;    /* CPU百分比 */
/*
*********************************************************************************************************
*                                       静态全局变量
*********************************************************************************************************
*/
static TX_THREAD cpu_stat_task_thread;
/*
*********************************************************************************************************
*                                      函数声明
*********************************************************************************************************
*/
static VOID task_cpu_stat_entry(ULONG input);
/*
*********************************************************************************************************
*                                      外部函数
*********************************************************************************************************
*/
/*** @brief cpu 状态任务* @param first_thread 第一个启动的任务线程首地址*/
int tx_task_cpu_stat_create() {tx_thread_create(&cpu_stat_task_thread,              /* 任务控制块地址 */"app_cpu_stat",               /* 任务名 */task_cpu_stat_entry,                  /* 启动任务函数地址 */0,                             /* 传递给任务的参数 */app_malloc(APP_TASK_CPU_STAT_STK_SIZE),            /* 堆栈基地址 */APP_TASK_CPU_STAT_STK_SIZE,    /* 堆栈空间大小 */APP_TASK_CPU_STAT_PRIO,        /* 任务优先级*/APP_TASK_CPU_STAT_PRIO,        /* 任务抢占阀值 */TX_NO_TIME_SLICE,               /* 不开启时间片 */TX_AUTO_START);                 /* 创建后立即启动 */return TX_SUCCESS;
}TX_THREAD_EXPORT(tx_task_cpu_stat_create);/*
*********************************************************************************************************
*	函 数 名: app_task_info_out
*	功能说明: 将ThreadX任务信息通过串口打印出来
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/void app_task_info_out(void) {TX_THREAD *p_tcb = _tx_thread_identify(); /* 定义一个任务控制块指针,并指向当前线程 *//* 打印标题 */tx_log("调用线程======[%s]\r\n", p_tcb->tx_thread_name);
#if defined(TX_EXECUTION_PROFILE_ENABLE)tx_log("CPU利用率 = %5.2f%%\r\n", OSCPUUsage);tx_log("任务执行时间 = %.9fs\r\n", (double) _tx_execution_thread_time_total / SystemCoreClock);tx_log("空闲执行时间 = %.9fs\r\n", (double) _tx_execution_idle_time_total / SystemCoreClock);tx_log("中断执行时间 = %.9fs\r\n", (double) _tx_execution_isr_time_total / SystemCoreClock);tx_log("系统总执行时间 = %.9fs\r\n", (double) (_tx_execution_thread_time_total + \_tx_execution_idle_time_total + \_tx_execution_isr_time_total) / SystemCoreClock);
#endiftx_log("===============================================================\r\n");tx_log(" 任务优先级 任务栈大小 当前使用栈  最大栈使用 状态   任务名\r\n");tx_log("   Prio     StackSize   CurStack    MaxStack   Taskname\r\n");/* 遍历任务控制列表TCB list),打印所有的任务的优先级和名称 */while (p_tcb != (TX_THREAD *) 0) {tx_log("   %2d        %5d      %5d       %5d    %5d      %s\r\n",p_tcb->tx_thread_priority,p_tcb->tx_thread_stack_size,(int) p_tcb->tx_thread_stack_end - (int) p_tcb->tx_thread_stack_ptr,(int) p_tcb->tx_thread_stack_end - (int) p_tcb->tx_thread_stack_highest_ptr,p_tcb->tx_thread_state,p_tcb->tx_thread_name);p_tcb = p_tcb->tx_thread_created_next;if (p_tcb == _tx_thread_identify()) break;}
}/*
*********************************************************************************************************
*                                      内部函数
*********************************************************************************************************
*/
static VOID task_cpu_stat_entry(ULONG input) {
#if defined(TX_EXECUTION_PROFILE_ENABLE)EXECUTION_TIME TolTime, IdleTime, deltaTolTime, deltaIdleTime;uint32_t uiCount = 0;(void) input;/* 计算CPU利用率 */IdleTime = _tx_execution_idle_time_total;TolTime = _tx_execution_thread_time_total + _tx_execution_isr_time_total + _tx_execution_idle_time_total;while (1) {/* CPU利用率统计 */uiCount++;if (uiCount == 20) {uiCount = 0;deltaIdleTime = _tx_execution_idle_time_total - IdleTime;deltaTolTime =_tx_execution_thread_time_total + _tx_execution_isr_time_total + _tx_execution_idle_time_total -TolTime;OSCPUUsage = (double) deltaIdleTime / deltaTolTime;OSCPUUsage = 100 - OSCPUUsage * 100;IdleTime = _tx_execution_idle_time_total;TolTime = _tx_execution_thread_time_total + _tx_execution_isr_time_total + _tx_execution_idle_time_total;}tx_thread_sleep(10);}
#elsewhile (1) {bsp_Idle();tx_thread_sleep(10);}#endif
}

模块脚本生成代码(根据实际情况进行调整)

生成txm静态库文件的脚本(注意代码中的路径)

/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-4-14     shchl          thread txm lib 脚本构建*/
#include "main.h"
#include <dirent.h>
#include <sys/stat.h>
/*** @brief txm 源文件构建命令*/
const char *tx_txm_lib_source_build_cmd ="arm-none-eabi-gcc -c -g ""-mcpu=cortex-m4 ""-mfloat-abi=hard ""-mfpu=vfpv4 ""-mthumb ""-fpic -fno-plt ""-mno-pic-data-is-text-relative ""-msingle-pic-base ";
const char *tx_txm_lib_script = "tx_txm_static_lib_build.bat";/*根据实际情况修改*/
static char *txm_inc_list ="\t-IE:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\common\\inc""\t-IE:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\common_modules\\inc""\t-IE:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\ports_module\\cortex_m4\\gnu\\inc ";
static char *txm_lib_src_dir = "E:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\common_modules\\module_lib\\src";
static char *txm_lib_port_file = "E:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\ports_module\\cortex_m4\\gnu\\module_lib\\src\\txm_module_thread_shell_entry.c";void build_txm_lib() {FILE *pSaveFile = fopen(tx_txm_lib_script, "w");if (pSaveFile) {DIR *pDir = opendir(txm_lib_src_dir);/*删除之前的静态库文件*/fputs("del txm.a\n",pSaveFile);if (pDir) {struct dirent *pDirent = readdir(pDir);while (pDirent) {/*判断是否是.c文件*/if (strstr(pDirent->d_name, ".c")) {fprintf(pSaveFile, "%s %s %s\\%s\n",tx_txm_lib_source_build_cmd,txm_inc_list,txm_lib_src_dir,pDirent->d_name);} else if (strstr(pDirent->d_name, ".") && pDirent->d_namlen == 1) {// 当前目录} else if (strstr(pDirent->d_name, "..") && pDirent->d_namlen == 2) {// 上一级目录} else {// 其他判断}pDirent = readdir(pDir);}/*单独添加接口编译源文件*/fprintf(pSaveFile, "%s %s %s\n",tx_txm_lib_source_build_cmd,txm_inc_list,txm_lib_port_file);/*构建静态库*/fputs("arm-none-eabi-ar -r  txm.a *.o\n",pSaveFile);/*删除.o文件*/fputs("del *.o\n",pSaveFile);}fclose(pSaveFile);}}

生成模块构建bin文件的脚本(注意对应的threadx的实际位置)

/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-4-14     shchl          生成模块应用脚本代码*/
#include "main.h"const char *tx_module_build_script = "tx_module_build.bat";/*指令格式*/
const char *common_del_cmd = "del *.o *.axf *.map"; /*通用删除指令*/
/*** @brief  编译指令 c文件编译成 目标文件*/
const char *module_compilar_to_obj_cmd ="arm-none-eabi-gcc -c -g ^\n""\t\t-mcpu=cortex-m4 ^\n""\t\t-mfloat-abi=hard ^\n""\t\t-mfpu=vfpv4 -fpie -fno-plt ^\n""\t\t-mno-pic-data-is-text-relative ^\n""\t\t-msingle-pic-base ";/*** @brief 链接文件+目标文件*/
const char *module_compilar_to_axf_cmd ="arm-none-eabi-ld -A cortex-m4 ^\n""\t\t-T %s %s ^\n""\t\t-e _txm_module_thread_shell_entry txm.a ^\n""\t\t-o   app_module.axf ^\n""\t\t-M > app_module.map ";
const char *module_compilar_to_bin_cmd ="\narm-none-eabi-objcopy  -O binary  app_module.axf  \"app_module.bin\" ""\narm-none-eabi-objcopy  -O ihex  app_module.axf  \"app_module.hex\" ";/*模块使用的头文件目录*/
const char *module_inc_dir ="^\n\t\t-IE:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\common\\inc ""^\n\t\t-IE:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\common_modules\\inc ""^\n\t\t-IE:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\ports_module\\cortex_m4\\gnu\\inc ";void build_app_module_bat() {char *link_file = " ..\\app_module.ld ";char *asm_file_list = "^\n\t\t..\\app_module_preamble.S ""^\n\t\t..\\app_module_setup.s ";char *source_c_file_list ="^\n\t\t..\\app_module.c """;char *obj_file_list = "\tapp_module_preamble.o ""\tapp_module_setup.o ""\tapp_module.o ";const char *cmd_asm_fmt = "%s %s\n"; /*汇编指令格式*/const char *cmd_source_fmt = "%s %s %s\n"; /*汇编指令格式*/FILE *pFile = fopen(tx_module_build_script, "w");fprintf(pFile, "del  *.bin  *.hex\n");/*清除*//*汇编文件构建目标文件*/fprintf(pFile, cmd_asm_fmt, module_compilar_to_obj_cmd, asm_file_list);/*源文件构建目标文件*/fprintf(pFile, cmd_source_fmt, module_compilar_to_obj_cmd, module_inc_dir, source_c_file_list);/*目标文件构建axf 文件*/fprintf(pFile, module_compilar_to_axf_cmd, link_file, obj_file_list);/*生成bin文件和map文件*/fprintf(pFile, "%s", module_compilar_to_bin_cmd);/*删除 构建中间文件*/fprintf(pFile, "\n%s\n", common_del_cmd);/*清除*/fclose(pFile);
}

主函数

/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-4-14     shchl   first version*/
#include "main.h"int main(void) {build_txm_lib();build_app_module_bat();return 0;
}

模块1

在这里插入图片描述
上述名称,可自行定义。

入口函数

#define TXM_MODULE#include "txm_module.h"/*
*********************************************************************************************************
*                                    宏定义
*********************************************************************************************************
*/
#define DEFAULT_STACK_SIZE        1024#define App_Printf_ID1       (TXM_APPLICATION_REQUEST_ID_BASE)
#define App_Printf_ID2       (TXM_APPLICATION_REQUEST_ID_BASE + 1)#define MODULE_THREAD_PRIO                         3
#define MODULE_THREAD_PREEMPTION_THRESHOLD         MODULE_THREAD_PRIOULONG      AppModuleStk[DEFAULT_STACK_SIZE/4];/* 相关控制块 */
TX_THREAD               *thread_0;
TX_QUEUE                *resident_queue;/* 函数 */
void thread_0_entry(ULONG thread_input);
void Error_Handler1(void);/*
*********************************************************************************************************
*	函 数 名: default_module_start
*	功能说明: 动态APP入口
*	形    参: ---
*	返 回 值: 无
*********************************************************************************************************
*/
void  demo_module_start(ULONG id)
{CHAR    *pointer;/* 从主程序申请相关控制块,不在APP里面申请,防止APP出问题了影响主程序 */txm_module_object_allocate((void*)&thread_0, sizeof(TX_THREAD));/* 创建任务 */tx_thread_create(thread_0,"module thread 1",thread_0_entry,0,&AppModuleStk[0],DEFAULT_STACK_SIZE,MODULE_THREAD_PRIO,MODULE_THREAD_PREEMPTION_THRESHOLD,TX_NO_TIME_SLICE,TX_AUTO_START);}/*
*********************************************************************************************************
*	函 数 名: thread_0_entry
*	功能说明: 动态APP里面的任务
*	形    参: ---
*	返 回 值: 无
*********************************************************************************************************
*/
void thread_0_entry(ULONG thread_input)
{/* 防止警告 */UINT num = 0;while(1){/* 调用主程序里面的串口打印 */num++;txm_module_application_request(App_Printf_ID1, num, 0, 0);tx_thread_sleep(1000);}
}/*
*********************************************************************************************************
*	函 数 名: thread_0_entry
*	功能说明: 执行出错
*	形    参: ---
*	返 回 值: 无
*********************************************************************************************************
*/
void Error_Handler1(void)
{tx_thread_sleep(TX_WAIT_FOREVER);
}

链接文件(参考官网对应的设备内核)

这里设置的启动地址为0x08020000为的第一个模块的地址

MEMORY
{FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024KRAM   (wx) : ORIGIN = 0x20000000, LENGTH = 128K
}SECTIONS
{__FLASH_segment_start__ = 0x08020000;__FLASH_segment_end__   = 0x08030000;__RAM_segment_start__   = 0x20000000;__RAM_segment_end__     = 0x20020000;__HEAPSIZE__ = 128;__preamble_load_start__ = __FLASH_segment_start__;.preamble __FLASH_segment_start__ : AT(__FLASH_segment_start__){__preamble_start__ = .;*(.preamble .preamble.*)}__preamble_end__ = __preamble_start__ + SIZEOF(.preamble);__dynsym_load_start__ =  ALIGN(__preamble_end__ , 4);.dynsym ALIGN(__dynsym_load_start__ , 4) : AT(ALIGN(__dynsym_load_start__ , 4)){. = ALIGN(4);KEEP (*(.dynsym))KEEP (*(.dynsym*)). = ALIGN(4);}__dynsym_end__ = __dynsym_load_start__ + SIZEOF(.dynsym);__dynstr_load_start__ =  ALIGN(__dynsym_end__ , 4);.dynstr ALIGN(__dynstr_load_start__ , 4) : AT(ALIGN(__dynstr_load_start__, 4)){. = ALIGN(4);KEEP (*(.dynstr))KEEP (*(.dynstr*)). = ALIGN(4);}__dynstr_end__ = __dynstr_load_start__ + SIZEOF(.dynstr);__reldyn_load_start__ =  ALIGN(__dynstr_end__ , 4);.rel.dyn ALIGN(__reldyn_load_start__ , 4) : AT(ALIGN(__reldyn_load_start__ , 4)){. = ALIGN(4);KEEP (*(.rel.dyn))KEEP (*(.rel.dyn*)). = ALIGN(4);}__reldyn_end__ = __reldyn_load_start__ + SIZEOF(.rel.dyn);__relplt_load_start__ =  ALIGN(__reldyn_end__ , 4);.rel.plt ALIGN(__relplt_load_start__ , 4) : AT(ALIGN(__relplt_load_start__ , 4)){. = ALIGN(4);KEEP (*(.rel.plt))KEEP (*(.rel.plt*)). = ALIGN(4);}__relplt_end__ = __relplt_load_start__ + SIZEOF(.rel.plt);__plt_load_start__ =  ALIGN(__relplt_end__ , 4);.plt ALIGN(__plt_load_start__ , 4) : AT(ALIGN(__plt_load_start__ , 4)){. = ALIGN(4);KEEP (*(.plt))KEEP (*(.plt*)). = ALIGN(4);}__plt_end__ = __plt_load_start__ + SIZEOF(.plt);__interp_load_start__ =  ALIGN(__plt_end__ , 4);.interp ALIGN(__interp_load_start__ , 4) : AT(ALIGN(__interp_load_start__ , 4)){. = ALIGN(4);KEEP (*(.interp))KEEP (*(.interp*)). = ALIGN(4);}__interp_end__ = __interp_load_start__ + SIZEOF(.interp);__hash_load_start__ =  ALIGN(__interp_end__ , 4);.hash ALIGN(__hash_load_start__ , 4) : AT(ALIGN(__hash_load_start__, 4)){. = ALIGN(4);KEEP (*(.hash))KEEP (*(.hash*)). = ALIGN(4);}__hash_end__ = __hash_load_start__ + SIZEOF(.hash);__text_load_start__ =  ALIGN(__hash_end__ , 4);.text ALIGN(__text_load_start__ , 4) : AT(ALIGN(__text_load_start__, 4)){__text_start__ = .;*(.text .text.* .glue_7t .glue_7 .gnu.linkonce.t.* .gcc_except_table  )}__text_end__ = __text_start__ + SIZEOF(.text);__dtors_load_start__ = ALIGN(__text_end__ , 4);.dtors ALIGN(__text_end__ , 4) : AT(ALIGN(__text_end__ , 4)){__dtors_start__ = .;KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors))}__dtors_end__ = __dtors_start__ + SIZEOF(.dtors);__ctors_load_start__ = ALIGN(__dtors_end__ , 4);.ctors ALIGN(__dtors_end__ , 4) : AT(ALIGN(__dtors_end__ , 4)){__ctors_start__ = .;KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors))}__ctors_end__ = __ctors_start__ + SIZEOF(.ctors);__got_load_start__ = ALIGN(__ctors_end__ , 4);.got ALIGN(__ctors_end__ , 4) : AT(ALIGN(__ctors_end__ , 4)){. = ALIGN(4);_sgot = .;KEEP (*(.got))KEEP (*(.got*)). = ALIGN(4);_egot = .;}__got_end__ =  __got_load_start__ + SIZEOF(.got);__rodata_load_start__ = ALIGN(__got_end__ , 4);.rodata ALIGN(__got_end__ , 4) : AT(ALIGN(__got_end__ , 4)){__rodata_start__ = .;*(.rodata .rodata.* .gnu.linkonce.r.*)}__rodata_end__ = __rodata_start__ + SIZEOF(.rodata);__code_size__ =  __rodata_end__ - __FLASH_segment_start__;__fast_load_start__ = ALIGN(__rodata_end__ , 4);__fast_load_end__ = __fast_load_start__ + SIZEOF(.fast);__new_got_start__ = ALIGN(__RAM_segment_start__ , 4);__new_got_end__ =  __new_got_start__ + SIZEOF(.got);.fast ALIGN(__new_got_end__ , 4) : AT(ALIGN(__rodata_end__ , 4)){__fast_start__ = .;*(.fast .fast.*)}__fast_end__ = __fast_start__ + SIZEOF(.fast);.fast_run ALIGN(__fast_end__ , 4) (NOLOAD) :{__fast_run_start__ = .;. = MAX(__fast_run_start__ + SIZEOF(.fast), .);}__fast_run_end__ = __fast_run_start__ + SIZEOF(.fast_run);__data_load_start__ = ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4);.data ALIGN(__fast_run_end__ , 4) : AT(ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4)){__data_start__ = .;*(.data .data.* .gnu.linkonce.d.*)}__data_end__ = __data_start__ + SIZEOF(.data);__data_load_end__ = __data_load_start__ + SIZEOF(.data);__FLASH_segment_used_end__ = ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4) + SIZEOF(.data);.data_run ALIGN(__fast_run_end__ , 4) (NOLOAD) :{__data_run_start__ = .;. = MAX(__data_run_start__ + SIZEOF(.data), .);}__data_run_end__ = __data_run_start__ + SIZEOF(.data_run);__bss_load_start__ = ALIGN(__data_run_end__ , 4);.bss ALIGN(__data_run_end__ , 4) (NOLOAD) : AT(ALIGN(__data_run_end__ , 4)){__bss_start__ = .;*(.bss .bss.* .gnu.linkonce.b.*) *(COMMON)}__bss_end__ = __bss_start__ + SIZEOF(.bss);__non_init_load_start__ = ALIGN(__bss_end__ , 4);.non_init ALIGN(__bss_end__ , 4) (NOLOAD) : AT(ALIGN(__bss_end__ , 4)){__non_init_start__ = .;*(.non_init .non_init.*)}__non_init_end__ = __non_init_start__ + SIZEOF(.non_init);__heap_load_start__ = ALIGN(__non_init_end__ , 4);.heap ALIGN(__non_init_end__ , 4) (NOLOAD) : AT(ALIGN(__non_init_end__ , 4)){__heap_start__ = .;*(.heap). = ALIGN(MAX(__heap_start__ + __HEAPSIZE__ , .), 4);}__heap_end__ = __heap_start__ + SIZEOF(.heap);__data_size__ =  __heap_end__ - __RAM_segment_start__;
}

模块要求汇编文件(具体含义参考官方文档,这里主要注意入口函数名要对应模块文件中的入口函数)

    .text.align 4.syntax unified/* Define public symbols.  */.global __txm_module_preamble/* Define application-specific start/stop entry points for the module.  */.global demo_module_start/* Define common external refrences.  */.global _txm_module_thread_shell_entry.global _txm_module_callback_request_thread_entry__txm_module_preamble:.dc.l      0x4D4F4455                                       // Module ID.dc.l      0x6                                              // Module Major Version.dc.l      0x1                                              // Module Minor Version.dc.l      32                                               // Module Preamble Size in 32-bit words.dc.l      0x12345678                                       // Module ID (application defined).dc.l      0x02000004                                       // Module Properties where://   Bits 31-24: Compiler ID//           0 -> IAR//           1 -> ARM//           2 -> GNU//   Bits 23-3: Reserved//   Bit 2:  0 -> Disable shared/external memory access//           1 -> Enable shared/external memory access//   Bit 1:  0 -> No MPU protection//           1 -> MPU protection (must have user mode selected - bit 0 set)//   Bit 0:  0 -> Privileged mode execution//           1 -> User mode execution.dc.l      _txm_module_thread_shell_entry - . - 0           // Module Shell Entry Point.dc.l      demo_module_start - . - 0                        // Module Start Thread Entry Point.dc.l      0                                                // Module Stop Thread Entry Point .dc.l      1                                                // Module Start/Stop Thread Priority.dc.l      1024                                             // Module Start/Stop Thread Stack Size.dc.l      _txm_module_callback_request_thread_entry - . - 0 // Module Callback Thread Entry.dc.l      1                                                // Module Callback Thread Priority.dc.l      1024                                             // Module Callback Thread Stack Size.dc.l      __code_size__                                           // Module Code Size.dc.l      __data_size__                                           // Module Data Size.dc.l      0                                                // Reserved 0.dc.l      0                                                // Reserved 1.dc.l      0                                                // Reserved 2.dc.l      0                                                // Reserved 3.dc.l      0                                                // Reserved 4.dc.l      0                                                // Reserved 5.dc.l      0                                                // Reserved 6.dc.l      0                                                // Reserved 7.dc.l      0                                                // Reserved 8.dc.l      0                                                // Reserved 9.dc.l      0                                                // Reserved 10.dc.l      0                                                // Reserved 11.dc.l      0                                                // Reserved 12.dc.l      0                                                // Reserved 13.dc.l      0                                                // Reserved 14.dc.l      0                                                // Reserved 15

设置汇编文件 (这个直接使用的是threadx源码中提供的,主要做数据的拷贝和填充,共其他地方调用)

.text.align 4.syntax unified.global _gcc_setup.thumb_func
_gcc_setup:STMDB   sp!, {r3, r4, r5, r6, r7, lr}             // Store other preserved registersldr     r3, =__FLASH_segment_start__ldr     r4, =__RAM_segment_start__mov     r5,r0/* Copy GOT table. */ldr     r0, =__got_load_start__sub     r0,r0,r3add     r0,r0,r5ldr     r1, =__new_got_start__sub     r1,r1, r4add     r1,r1,r9ldr     r2, =__new_got_end__sub     r2,r2,r4add     r2,r2,r9new_got_setup:cmp     r1, r2          // See if there are more GOT entriesbeq     got_setup_done  // No, done with GOT setupldr     r6, [r0]        // Pickup current GOT entrycmp     r6, #0          // Is it 0?beq     address_built   // Yes, just skip the adjustmentcmp     r6, r4          // Is it in the code or data area?blt     flash_area      // If less than, it is a code addresssub     r6, r6, r4      // Compute offset of data areaadd     r6, r6, r9      // Build address based on the loaded data addressb       address_built   // Finished building address
flash_area:sub     r6, r6, r3      // Compute offset of code areaadd     r6, r6, r5      // Build address based on the loaded code address
address_built:str     r6, [r1]        // Store in new GOT tableadd     r0, r0, #4      // Move to next entryadd     r1, r1, #4      // b       new_got_setup   // Continue at the top of the loop
got_setup_done:/* Copy initialised sections into RAM if required. */ldr     r0, =__data_load_start__sub     r0,r0,r3add     r0,r0,r5ldr     r1, =__data_start__sub     r1,r1, r4add     r1,r1,r9ldr     r2, =__data_end__sub     r2,r2,r4add     r2,r2,r9bl      crt0_memory_copy/* Zero bss. */ldr     r0, =__bss_start__sub     r0,r0,r4add     r0,r0,r9ldr     r1, =__bss_end__sub     r1,r1,r4add     r1,r1,r9mov     r2, #0bl      crt0_memory_set/* Setup heap - not recommended for Threadx but here for compatibility reasons */ldr     r0, =__heap_start__sub     r0,r0,r4add     r0,r0,r9ldr     r1, =__heap_end__sub     r1,r1,r4add     r1,r1,r9sub     r1,r1,r0mov     r2, #0str     r2, [r0]add     r0, r0, #4str     r1, [r0]LDMIA   sp!, {r3, r4, r5, r6, r7, lr}       // Store other preserved registersbx      lr                                  // Return to caller.align 4/* Startup helper functions. */.thumb_func
crt0_memory_copy:cmp     r0, r1beq     memory_copy_donecmp     r2, r1beq     memory_copy_donesub     r2, r2, r1
memory_copy_loop:ldrb    r3, [r0]add     r0, r0, #1strb    r3, [r1]add     r1, r1, #1sub     r2, r2, #1cmp     r2, #0bne     memory_copy_loop
memory_copy_done:bx      lr.thumb_func
crt0_memory_set:cmp     r0, r1beq     memory_set_donestrb    r2, [r0]add     r0, r0, #1b       crt0_memory_set
memory_set_done:bx      lr/* Setup attibutes of heap section so it doesn't take up room in the elf file */.section .heap, "wa", %nobits

模块2

  1. 与模块1不同的是模块函数 和链接文件中的启动地址不同,其他均一样

入口函数

#define TXM_MODULE#include "txm_module.h"/*
*********************************************************************************************************
*                                    宏定义
*********************************************************************************************************
*/
#define DEFAULT_STACK_SIZE        1024#define App_Printf_ID1       (TXM_APPLICATION_REQUEST_ID_BASE)
#define App_Printf_ID2       (TXM_APPLICATION_REQUEST_ID_BASE + 1)#define MODULE_THREAD_PRIO                         3
#define MODULE_THREAD_PREEMPTION_THRESHOLD         MODULE_THREAD_PRIOULONG      AppModuleStk[DEFAULT_STACK_SIZE/4];/* 相关控制块 */
TX_THREAD               *thread_0;
TX_QUEUE                *resident_queue;/* 函数 */
void thread_0_entry(ULONG thread_input);
void Error_Handler1(void);/*
*********************************************************************************************************
*	函 数 名: default_module_start
*	功能说明: 动态APP入口
*	形    参: ---
*	返 回 值: 无
*********************************************************************************************************
*/
void  demo_module_start(ULONG id)
{CHAR    *pointer;/* 从主程序申请相关控制块,不在APP里面申请,防止APP出问题了影响主程序 */txm_module_object_allocate((void*)&thread_0, sizeof(TX_THREAD));/* 创建任务 */tx_thread_create(thread_0,"module thread 22",thread_0_entry,0,&AppModuleStk[0],DEFAULT_STACK_SIZE,MODULE_THREAD_PRIO,MODULE_THREAD_PREEMPTION_THRESHOLD,TX_NO_TIME_SLICE,TX_AUTO_START);}/*
*********************************************************************************************************
*	函 数 名: thread_0_entry
*	功能说明: 动态APP里面的任务
*	形    参: ---
*	返 回 值: 无
*********************************************************************************************************
*/
void thread_0_entry(ULONG thread_input)
{/* 防止警告 */UINT num = 0;while(1){/* 调用主程序里面的串口打印 */num++;txm_module_application_request(App_Printf_ID2, num, 0, 0);tx_thread_sleep(1000);}
}/*
*********************************************************************************************************
*	函 数 名: thread_0_entry
*	功能说明: 执行出错
*	形    参: ---
*	返 回 值: 无
*********************************************************************************************************
*/
void Error_Handler1(void)
{tx_thread_sleep(TX_WAIT_FOREVER);
}

链接文件

MEMORY
{FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024KRAM   (wx) : ORIGIN = 0x20000000, LENGTH = 128K
}SECTIONS
{__FLASH_segment_start__ = 0x08040000;__FLASH_segment_end__   = 0x08050000;__RAM_segment_start__   = 0x20000000;__RAM_segment_end__     = 0x20020000;__HEAPSIZE__ = 128;__preamble_load_start__ = __FLASH_segment_start__;.preamble __FLASH_segment_start__ : AT(__FLASH_segment_start__){__preamble_start__ = .;*(.preamble .preamble.*)}__preamble_end__ = __preamble_start__ + SIZEOF(.preamble);__dynsym_load_start__ =  ALIGN(__preamble_end__ , 4);.dynsym ALIGN(__dynsym_load_start__ , 4) : AT(ALIGN(__dynsym_load_start__ , 4)){. = ALIGN(4);KEEP (*(.dynsym))KEEP (*(.dynsym*)). = ALIGN(4);}__dynsym_end__ = __dynsym_load_start__ + SIZEOF(.dynsym);__dynstr_load_start__ =  ALIGN(__dynsym_end__ , 4);.dynstr ALIGN(__dynstr_load_start__ , 4) : AT(ALIGN(__dynstr_load_start__, 4)){. = ALIGN(4);KEEP (*(.dynstr))KEEP (*(.dynstr*)). = ALIGN(4);}__dynstr_end__ = __dynstr_load_start__ + SIZEOF(.dynstr);__reldyn_load_start__ =  ALIGN(__dynstr_end__ , 4);.rel.dyn ALIGN(__reldyn_load_start__ , 4) : AT(ALIGN(__reldyn_load_start__ , 4)){. = ALIGN(4);KEEP (*(.rel.dyn))KEEP (*(.rel.dyn*)). = ALIGN(4);}__reldyn_end__ = __reldyn_load_start__ + SIZEOF(.rel.dyn);__relplt_load_start__ =  ALIGN(__reldyn_end__ , 4);.rel.plt ALIGN(__relplt_load_start__ , 4) : AT(ALIGN(__relplt_load_start__ , 4)){. = ALIGN(4);KEEP (*(.rel.plt))KEEP (*(.rel.plt*)). = ALIGN(4);}__relplt_end__ = __relplt_load_start__ + SIZEOF(.rel.plt);__plt_load_start__ =  ALIGN(__relplt_end__ , 4);.plt ALIGN(__plt_load_start__ , 4) : AT(ALIGN(__plt_load_start__ , 4)){. = ALIGN(4);KEEP (*(.plt))KEEP (*(.plt*)). = ALIGN(4);}__plt_end__ = __plt_load_start__ + SIZEOF(.plt);__interp_load_start__ =  ALIGN(__plt_end__ , 4);.interp ALIGN(__interp_load_start__ , 4) : AT(ALIGN(__interp_load_start__ , 4)){. = ALIGN(4);KEEP (*(.interp))KEEP (*(.interp*)). = ALIGN(4);}__interp_end__ = __interp_load_start__ + SIZEOF(.interp);__hash_load_start__ =  ALIGN(__interp_end__ , 4);.hash ALIGN(__hash_load_start__ , 4) : AT(ALIGN(__hash_load_start__, 4)){. = ALIGN(4);KEEP (*(.hash))KEEP (*(.hash*)). = ALIGN(4);}__hash_end__ = __hash_load_start__ + SIZEOF(.hash);__text_load_start__ =  ALIGN(__hash_end__ , 4);.text ALIGN(__text_load_start__ , 4) : AT(ALIGN(__text_load_start__, 4)){__text_start__ = .;*(.text .text.* .glue_7t .glue_7 .gnu.linkonce.t.* .gcc_except_table  )}__text_end__ = __text_start__ + SIZEOF(.text);__dtors_load_start__ = ALIGN(__text_end__ , 4);.dtors ALIGN(__text_end__ , 4) : AT(ALIGN(__text_end__ , 4)){__dtors_start__ = .;KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors))}__dtors_end__ = __dtors_start__ + SIZEOF(.dtors);__ctors_load_start__ = ALIGN(__dtors_end__ , 4);.ctors ALIGN(__dtors_end__ , 4) : AT(ALIGN(__dtors_end__ , 4)){__ctors_start__ = .;KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors))}__ctors_end__ = __ctors_start__ + SIZEOF(.ctors);__got_load_start__ = ALIGN(__ctors_end__ , 4);.got ALIGN(__ctors_end__ , 4) : AT(ALIGN(__ctors_end__ , 4)){. = ALIGN(4);_sgot = .;KEEP (*(.got))KEEP (*(.got*)). = ALIGN(4);_egot = .;}__got_end__ =  __got_load_start__ + SIZEOF(.got);__rodata_load_start__ = ALIGN(__got_end__ , 4);.rodata ALIGN(__got_end__ , 4) : AT(ALIGN(__got_end__ , 4)){__rodata_start__ = .;*(.rodata .rodata.* .gnu.linkonce.r.*)}__rodata_end__ = __rodata_start__ + SIZEOF(.rodata);__code_size__ =  __rodata_end__ - __FLASH_segment_start__;__fast_load_start__ = ALIGN(__rodata_end__ , 4);__fast_load_end__ = __fast_load_start__ + SIZEOF(.fast);__new_got_start__ = ALIGN(__RAM_segment_start__ , 4);__new_got_end__ =  __new_got_start__ + SIZEOF(.got);.fast ALIGN(__new_got_end__ , 4) : AT(ALIGN(__rodata_end__ , 4)){__fast_start__ = .;*(.fast .fast.*)}__fast_end__ = __fast_start__ + SIZEOF(.fast);.fast_run ALIGN(__fast_end__ , 4) (NOLOAD) :{__fast_run_start__ = .;. = MAX(__fast_run_start__ + SIZEOF(.fast), .);}__fast_run_end__ = __fast_run_start__ + SIZEOF(.fast_run);__data_load_start__ = ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4);.data ALIGN(__fast_run_end__ , 4) : AT(ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4)){__data_start__ = .;*(.data .data.* .gnu.linkonce.d.*)}__data_end__ = __data_start__ + SIZEOF(.data);__data_load_end__ = __data_load_start__ + SIZEOF(.data);__FLASH_segment_used_end__ = ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4) + SIZEOF(.data);.data_run ALIGN(__fast_run_end__ , 4) (NOLOAD) :{__data_run_start__ = .;. = MAX(__data_run_start__ + SIZEOF(.data), .);}__data_run_end__ = __data_run_start__ + SIZEOF(.data_run);__bss_load_start__ = ALIGN(__data_run_end__ , 4);.bss ALIGN(__data_run_end__ , 4) (NOLOAD) : AT(ALIGN(__data_run_end__ , 4)){__bss_start__ = .;*(.bss .bss.* .gnu.linkonce.b.*) *(COMMON)}__bss_end__ = __bss_start__ + SIZEOF(.bss);__non_init_load_start__ = ALIGN(__bss_end__ , 4);.non_init ALIGN(__bss_end__ , 4) (NOLOAD) : AT(ALIGN(__bss_end__ , 4)){__non_init_start__ = .;*(.non_init .non_init.*)}__non_init_end__ = __non_init_start__ + SIZEOF(.non_init);__heap_load_start__ = ALIGN(__non_init_end__ , 4);.heap ALIGN(__non_init_end__ , 4) (NOLOAD) : AT(ALIGN(__non_init_end__ , 4)){__heap_start__ = .;*(.heap). = ALIGN(MAX(__heap_start__ + __HEAPSIZE__ , .), 4);}__heap_end__ = __heap_start__ + SIZEOF(.heap);__data_size__ =  __heap_end__ - __RAM_segment_start__;
}

测试方式

  1. 主程序通过jlink直接下载烧录即可
  2. 模块应用,通过脚本生成bin文件,通过jflash进行对应的地址烧录,此步骤不能擦除主程序的存放的空间

烧录模块到对应的地址

在这里插入图片描述

测试结果(通过串口发送对应的命令。测试ok)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/309197.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Abstract Factory抽象工厂模式详解

模式定义 提供一个创建一系列相关或互相依赖对象的接口&#xff0c;而无需指定它们具体的类。 代码示例 public class AbstractFactoryTest {public static void main(String[] args) {IDatabaseUtils iDatabaseUtils new OracleDataBaseUtils();IConnection connection …

shell 调用钉钉通知

使用场景&#xff1a;机器能访问互联网&#xff0c;运行时间任务后通知使用 钉钉建立单人群 手机操作&#xff0c;只能通过手机方式建立单人群 电脑端 2. 配置脚本 #!/bin/bash set -e## 上图中 access_token字段 TOKEN KEYWORDhello # 前文中设置的关键字 function call_…

Java入门教程||Java 变量

Java 变量 Java教程 - Java变量 变量由标识符&#xff0c;类型和可选的初始化程序定义。变量还具有范围&#xff08;可见性/生存期&#xff09;。 Java变量类型 在Java中&#xff0c;必须先声明所有变量&#xff0c;然后才能使用它们。变量声明的基本形式如下所示&#xff1…

【Web】DASCTF X GFCTF 2022十月挑战赛题解

目录 EasyPOP hade_waibo EasyLove BlogSystem EasyPOP 先读hint.php sorry.__destruct -> secret_code::secret() exp: $anew sorry(); $bnew secret_code(); $a->password"suibian"; $a->name"jay"; echo serialize($a); 真暗号啊&…

RMAN数据迁移方案

数据迁移 Oracle环境检查 开启归档 1.首先关闭数据库 shutdown immediate; 2.打开mount状态 startup mount; 3.更改数据库为归档模式 alter database archivelog; 4.打开数据库 alter database open; 5.再次检查 archive log list; 查看构造的表和数据 由于数据会有中文&…

【微信小程序——案例——本地生活(列表页面)】

案例——本地生活&#xff08;列表页面&#xff09; 九宫格中实现导航跳转——以汽车服务为案例&#xff08;之后可以全部实现页面跳转——现在先实现一个&#xff09; 在app.json中添加新页面 修改之前的九宫格view改为navitage 效果图&#xff1a; 动态设置标题内容—…

SpringMVC--获取请求参数 / 域对象共享数据

目录 1. SpringMVC 获取请求参数 1.1. 通过ServletAPI获取 1.2. 控制器方法形参获取 1.3. RequestParam 1.4. RequestHeader 1.5. CookieValue 1.6. 通过POJO获取请求参数 1.7. 解决获取请求参数的乱码问题 2. 域对象共享数据 2.1. 三大域对象 2.2. 准备工作 2.3. S…

Linux awk

文章目录 1. 基础用法2. awk字符获取和筛选获取CPU/MEM占用率将awk指令包封脚本 3.awk条件与循环语句4.awk调用函数 1. 基础用法 操作粒度更加精细&#xff0c;可以以特殊字符&#xff08;: 空格等&#xff09;分割为列再进一步操作。例如 ps -aux获取到自己的进程后想进一步…

React+TS项目搭建

使用webpack5搭建ReactTS项目 一.初始化项目 初始化一个基本的reactts项目,首先创建一个项目文件夹,输入初始化命令 npm init -y 初始化完成后生成package.json文件,之后需要在项目下新增以下所示目录结构和文件 ├── build | ├── webpack.base.js # 公共配置 | ├…

Docker+Nginx部署vue项目

这篇文章给大家分享一下如何使用DockerNginx部署前端vue项目。 第一步&#xff1a;创建vue项目 执行这个命令&#xff0c;创建一个vue项目 npm create vue3将vue项目打包 npm run build此时会看到vue工程中生成了一个dist文件&#xff0c;我们将他上传到服务器中。 第二步…

微服务之LoadBalancer负载均衡服务调用

一、概述 1.1什么是负载均衡 LB&#xff0c;既负载均衡&#xff08;Load Balancer&#xff09;,是高并发、高可用系统必不可少的关键组件&#xff0c;其目标是尽力将网络流量平均分发到多个服务器上&#xff0c;以提高系统整体的响应速度和可用性。 负载均衡的主要作用 高并发…

第十二讲 查询计划 优化

到目前为止&#xff0c;我们一直在说&#xff0c;我们得到一个 SQL 查询&#xff0c;我们希望可以解析它&#xff0c;将其转化为某种逻辑计划&#xff0c;然后生成我们可以用于执行的物理计划。而这正是查询优化器【Optimizer】的功能&#xff0c;对于给定的 SQL &#xff0c;优…

基于RT-Thread(RTT)的BMP280气压计驱动(I2C通信)

前言 本文基于RTT操作系统使用STM32F401RET6驱动BMP280气压计模块&#xff0c;使用I2C协议通信 一、新建工程 二、添加软件包 三、添加这个包 四、打开CubeMX 五、配置时钟源&#xff0c;使用外部晶振 六、配置串行下载口 七、打开I2C&#xff0c;我这里使用的是I2C2&#x…

大模型面试准备(十八):使用 Pytorch 从零实现 Transformer 模型

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何备战、面试常考点分享等热门话题进行了深入的讨论。 合集在这…

VRRP虚拟路由实验(华为)

思科设备参考&#xff1a;VRRP虚拟路由实验&#xff08;思科&#xff09; 一&#xff0c;技术简介 VRRP&#xff08;Virtual Router Redundancy Protocol&#xff09;是一种网络协议&#xff0c;用于实现路由器冗余&#xff0c;提高网络可靠性和容错能力。VRRP允许多台路由器…

Windows Server 2016虚拟机安装教程

一、VMware Workstation虚拟机软件的下载 官网下载入口&#xff1a;​​​​​​Download VMware Workstation Pro - VMware Customer Connect​​​​​ 下载好之后自己看着提示安装软件就好. 二、镜像文件的下载 下载网站入口&#xff1a;MSDN, 我告诉你 - 做一个安静…

架构师系列-搜索引擎ElasticSearch(六)- 映射

映射配置 在创建索引时&#xff0c;可以预先定义字段的类型&#xff08;映射类型&#xff09;及相关属性。 数据库建表的时候&#xff0c;我们DDL依据一般都会指定每个字段的存储类型&#xff0c;例如&#xff1a;varchar、int、datetime等&#xff0c;目的很明确&#xff0c;就…

边缘计算【智能+安全检测】系列教程--使用OpenCV+GStreamer实现真正的硬解码,完全消除马赛克

通过现有博客的GST_URL = "rtspsrc location=rtsp://admin:abcd1234@192.168.1.64:554/h264/ch01/main/av_stream latency=150 ! rtph264depay ! avdec_h264 ! videorate ! videoconvert ! appsink sync=false" GStreamer的解码方式解码,大多情况应该存在上图马赛克…

QQ农场-phpYeFarm添加数据教程

前置知识 plugin\qqfarm\core\data D:\study-project\testweb\upload\source\plugin\qqfarm\core\data 也就是plugin\qqfarm\core\data是一个缓存文件,如果更新农场数据后,必须要删除才可以 解决种子限制(必须要做才可以添加成功) 你不更改加入了id大于2000直接删除种子 D…

matlab学习(三)(4.9-4.15)

一、空域里LSB算法的原理 1.原理&#xff1a; LSB算法通过替换图像像素的最低位来嵌入信息。这些被替换的LSB序列可以是需要加入的水印信息、水印的数字摘要或者由水印生成的伪随机序列。 2.实现步骤&#xff1a; &#xff08;1&#xff09;将图像文件中的所有像素点以RGB形…