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);
#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. 与模块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__;
}

测试方式

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

烧录模块到对应的地址

在这里插入图片描述

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

在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

詩不诉卿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值