前言
- 参考博客 论坛
- 官方资料: 微软
- 开发板核心芯片使用的是stm32f407zgtx,烧录工具使用的是jlink
- 模块的构建使用的是脚本进行构建
- 网上针对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);
#else
if (first_unused_memory) {
tx_mem_pool_init(first_unused_memory);
} else {
// todo 未使用动态内存,后面禁止使用 app_malloc 函数
}
#endif
stat = 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_MEM
static void *mem_ptr = NULL; /*这里要用全局静态变量,不能放在栈上面*/
tx_byte_allocate(&g_byte_pool, (void **) &mem_ptr,
size, TX_NO_WAIT);
return mem_ptr;
#else
return malloc(size);
#endif
}
/**
* @brief 释放内存
* @param mem_ptr
*/
void app_free(void *mem_ptr) {
#if MEM_MANAGER_MODE == TX_BYTE_POOL_MEM
tx_byte_release(mem_ptr);
#else
free(mem_ptr);
#endif
}
/**
* @brief 重新分配内存空间
* @param ptr 原始内存指向的指针
* @param size 重新分配的大小
* @return 新分配内存空间的首地址
* @note 需要用返回回去的指针覆盖原始指针,防止重新分配的内存首地址发生改变
*/
void *app_realloc(void *ptr, ULONG size) {
#if MEM_MANAGER_MODE == TX_BYTE_POOL_MEM
void *nw_ptr = app_malloc(size);
memcpy(nw_ptr, ptr, size);
app_free(ptr);
return nw_ptr;
#else
return 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);
#endif
tx_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);
}
#else
while (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_PRIO
ULONG 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 = 1024K
RAM (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 registers
ldr r3, =__FLASH_segment_start__
ldr r4, =__RAM_segment_start__
mov r5,r0
/* Copy GOT table. */
ldr r0, =__got_load_start__
sub r0,r0,r3
add r0,r0,r5
ldr r1, =__new_got_start__
sub r1,r1, r4
add r1,r1,r9
ldr r2, =__new_got_end__
sub r2,r2,r4
add r2,r2,r9
new_got_setup:
cmp r1, r2 // See if there are more GOT entries
beq got_setup_done // No, done with GOT setup
ldr r6, [r0] // Pickup current GOT entry
cmp r6, #0 // Is it 0?
beq address_built // Yes, just skip the adjustment
cmp r6, r4 // Is it in the code or data area?
blt flash_area // If less than, it is a code address
sub r6, r6, r4 // Compute offset of data area
add r6, r6, r9 // Build address based on the loaded data address
b address_built // Finished building address
flash_area:
sub r6, r6, r3 // Compute offset of code area
add r6, r6, r5 // Build address based on the loaded code address
address_built:
str r6, [r1] // Store in new GOT table
add r0, r0, #4 // Move to next entry
add 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,r3
add r0,r0,r5
ldr r1, =__data_start__
sub r1,r1, r4
add r1,r1,r9
ldr r2, =__data_end__
sub r2,r2,r4
add r2,r2,r9
bl crt0_memory_copy
/* Zero bss. */
ldr r0, =__bss_start__
sub r0,r0,r4
add r0,r0,r9
ldr r1, =__bss_end__
sub r1,r1,r4
add r1,r1,r9
mov r2, #0
bl crt0_memory_set
/* Setup heap - not recommended for Threadx but here for compatibility reasons */
ldr r0, =__heap_start__
sub r0,r0,r4
add r0,r0,r9
ldr r1, =__heap_end__
sub r1,r1,r4
add r1,r1,r9
sub r1,r1,r0
mov r2, #0
str r2, [r0]
add r0, r0, #4
str r1, [r0]
LDMIA sp!, {r3, r4, r5, r6, r7, lr} // Store other preserved registers
bx lr // Return to caller
.align 4
/* Startup helper functions. */
.thumb_func
crt0_memory_copy:
cmp r0, r1
beq memory_copy_done
cmp r2, r1
beq memory_copy_done
sub r2, r2, r1
memory_copy_loop:
ldrb r3, [r0]
add r0, r0, #1
strb r3, [r1]
add r1, r1, #1
sub r2, r2, #1
cmp r2, #0
bne memory_copy_loop
memory_copy_done:
bx lr
.thumb_func
crt0_memory_set:
cmp r0, r1
beq memory_set_done
strb r2, [r0]
add r0, r0, #1
b 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不同的是模块函数 和链接文件中的启动地址不同,其他均一样
入口函数
#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_PRIO
ULONG 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 = 1024K
RAM (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__;
}
测试方式
- 主程序通过jlink直接下载烧录即可
- 模块应用,通过脚本生成bin文件,通过jflash进行对应的地址烧录,此步骤不能擦除主程序的存放的空间