前言
- 参考博客 论坛
- 官方资料: 微软
- 开发板核心芯片使用的是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);
#elseif (first_unused_memory) {tx_mem_pool_init(first_unused_memory);} else {// todo 未使用动态内存,后面禁止使用 app_malloc 函数}
#endifstat = tx_thread_create(&app_start_thread, "app start thread",app_start_entry, 0,app_malloc(APP_MAIN_STACK_SIZE), APP_MAIN_STACK_SIZE,2, 2,TX_NO_TIME_SLICE, TX_AUTO_START);if (stat != TX_SUCCESS) {/*错误处理: 线程创建失败*/Error_Handler();}}
日志
/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2024-4-4 shchl first version*/
#include "includes.h"/*
*******************************************************************************************************
* 外部引入变量
*******************************************************************************************************
*/
extern TX_MUTEX AppPrintfSemp; /* 用于printf互斥 */
/*
*******************************************************************************************************
* 变量
*******************************************************************************************************
*//*
*********************************************************************************************************
* 静态全局变量
*********************************************************************************************************
*/
static char buf_str[TX_LOG_BUF_SZ] = {0}; /* 特别注意,如果printf的变量较多,注意此局部变量的大小是否够用 */
/*
*********************************************************************************************************
* 函数声明
*********************************************************************************************************
*//*
*********************************************************************************************************
* 外部函数
*********************************************************************************************************
*/
void tx_log(const char *fmt, ...) {va_list v_args;va_start(v_args, fmt);int len = vsnprintf((char *) &buf_str[0],(size_t) sizeof(buf_str),(char const *) fmt,v_args);va_end(v_args);/* 互斥操作 */tx_mutex_get(&AppPrintfSemp, TX_WAIT_FOREVER);if (len > TX_LOG_BUF_SZ - 1) {len = TX_LOG_BUF_SZ - 1;}buf_str[len] = '\0';printf("%s", buf_str);tx_mutex_put(&AppPrintfSemp);}void tx_log_no_mutex(const char *fmt, ...) {va_list v_args;va_start(v_args, fmt);(void) vsnprintf((char *) &buf_str[0],(size_t) sizeof(buf_str),(char const *) fmt,v_args);va_end(v_args);/* 互斥操作 */printf("%s", buf_str);
}
内存管理
/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2024-4-9 shchl first version*/
#include "includes.h"#define RAM_START (0x20000000) /*ram起始地址*/
#define RAM_SIZE (128 * 1024) /*总大小*/
#define RAM_END (RAM_START + RAM_SIZE) /*结束地址*/#define STAND_C_LIB 0 /*使用c标准库提供的内存分配函数进行管理*/
#define TX_BYTE_POOL_MEM 1 /*使用threadx提供的字节池对象进行内存分配管理*/
#define MEM_MANAGER_MODE TX_BYTE_POOL_MEM
/*
*********************************************************************************************************
* 静态全局变量
*********************************************************************************************************
*/
static TX_BYTE_POOL g_byte_pool; /*全局字节池*/
static ULONG mem_size; /*内存总大小(字节)*//*
*********************************************************************************************************
* 外部函数
*********************************************************************************************************
*/
/*** @brief 内存池初始化* @param start_addr 其实地址*/
void tx_mem_pool_init(void *start_addr) {
#if MEM_MANAGER_MODE == TX_BYTE_POOL_MEM// 地址对齐-保证4字节 内部已处理这里就不需要进行字节对齐处理了ULONG begin_align =(ULONG) start_addr;mem_size = (RAM_END - begin_align); /*动态内存总大小(字节)*//*通过threadx 提供的字节池对象进行管理动态内存空间*/if (tx_byte_pool_create(&g_byte_pool, "heap",start_addr, mem_size) != TX_SUCCESS) {/*错误处理*/Error_Handler();}#elif MEM_MANAGER_MODE == TX_BYTE_POOL_MEM
#endif
}void tx_mem_pool_static_init(void *start_addr, uint16_t byte_cnt){mem_size = byte_cnt; /*动态内存总大小(字节)*//*通过threadx 提供的字节池对象进行管理动态内存空间*/if (tx_byte_pool_create(&g_byte_pool, "heap",start_addr, mem_size) != TX_SUCCESS) {/*错误处理*/Error_Handler();}}/*** @brief 内存分配* @param size 分配大小(字节)* @return 指向分配内存的首地址*/
void *app_malloc(ULONG size) {
#if MEM_MANAGER_MODE == TX_BYTE_POOL_MEMstatic void *mem_ptr = NULL; /*这里要用全局静态变量,不能放在栈上面*/tx_byte_allocate(&g_byte_pool, (void **) &mem_ptr,size, TX_NO_WAIT);return mem_ptr;
#elsereturn malloc(size);
#endif}/*** @brief 释放内存* @param mem_ptr*/
void app_free(void *mem_ptr) {
#if MEM_MANAGER_MODE == TX_BYTE_POOL_MEMtx_byte_release(mem_ptr);
#elsefree(mem_ptr);
#endif}/*** @brief 重新分配内存空间* @param ptr 原始内存指向的指针* @param size 重新分配的大小* @return 新分配内存空间的首地址* @note 需要用返回回去的指针覆盖原始指针,防止重新分配的内存首地址发生改变*/
void *app_realloc(void *ptr, ULONG size) {
#if MEM_MANAGER_MODE == TX_BYTE_POOL_MEMvoid *nw_ptr = app_malloc(size);memcpy(nw_ptr, ptr, size);app_free(ptr);return nw_ptr;#elsereturn realloc(ptr,size);
#endif}
模块管理
#include "includes.h"
#include "txm_module.h"#define APP_MODULE_MANAGER_STACK_SIZE 4096U /*模块管理栈字节大小*/
#define APP_MODULE_MANAGER_THREAD_PRIORITY 4 /*模块管理线程优先级*/
#define APP_MODULE_MANAGER_THREAD_PREEMPTION_THRESHOLD APP_MODULE_MANAGER_THREAD_PRIORITY /*模块管理抢占阈值优先级*/#define MODULE_DATA_SIZE (20*1024) /* 供动态APP使用 */
#define OBJECT_MEM_SIZE (32*1024) /* 供动态APP的动态内存管理申请使用 */
enum {READY_FLAG, /*未启动*/STARTED_FLAG, /*已启动*/
};
/*** @brief 模块信息结构体*/
struct module_info_struct {uint8_t start_flag; /*启动标志位*/char *module_name; /*模块名*/uint32_t load_addr; /*加载地址地址*/TXM_MODULE_INSTANCE instance; /* 模块实例 */
};
/*
*******************************************************************************************************
* 外部引入变量
*******************************************************************************************************
*//*
*******************************************************************************************************
* 变量
*******************************************************************************************************
*/
struct module_info_struct module_tbl[] = {{READY_FLAG, "app module 01", 0x08020000U},{READY_FLAG, "app module 02", 0x08040000U}
};
#define MODULE_TBL_SIZE (sizeof(module_tbl)/sizeof(module_tbl[0]))TX_QUEUE ResidentQueue; /* 消息队列,用于主程序和动态APP通信 */
uint32_t MessageQueuesBuf[100];/*
*********************************************************************************************************
* 静态全局变量
*********************************************************************************************************
*/
static TX_THREAD module_manager_thread; /*模块管理线程*/
static ULONG memory_faults = 0;
static UCHAR *module_data_area;
static UCHAR *object_memory;/*
*********************************************************************************************************
* 函数声明
*********************************************************************************************************
*/
static void app_txm_module_info_out(TXM_MODULE_INSTANCE *instance, ULONG prop);static VOID module_fault_handler(TX_THREAD *thread, TXM_MODULE_INSTANCE *module);static void app_module_load(uint8_t idx);static void app_module_unload(uint8_t idx);static VOID module_manager_entry(ULONG thread_input);
/*
*********************************************************************************************************
* 外部函数
*********************************************************************************************************
*//*
*********************************************************************************************************
* 函 数 名: module_application_define
* 功能说明: 创建 模块管理任务线程
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
int module_application_define(void) {/*模块 分配内存空间*/object_memory = app_malloc(OBJECT_MEM_SIZE);module_data_area = app_malloc(MODULE_DATA_SIZE);/* 创建动态APP管理器任务 */if (tx_thread_create(&module_manager_thread, "Module Manager Thread",module_manager_entry, 0,app_malloc(APP_MODULE_MANAGER_STACK_SIZE), APP_MODULE_MANAGER_STACK_SIZE,APP_MODULE_MANAGER_THREAD_PRIORITY, APP_MODULE_MANAGER_THREAD_PREEMPTION_THRESHOLD,TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS) {Error_Handler();}/* 创建常驻消息队列 */if (tx_queue_create(&ResidentQueue, "Resident Queue",TX_1_ULONG, MessageQueuesBuf,16 * sizeof(ULONG)) != TX_SUCCESS) {Error_Handler();}return TX_SUCCESS;
}TX_THREAD_EXPORT_LV1(module_application_define); /*首先创建模块应用*//*
*********************************************************************************************************
* 函 数 名: module_manager_entry
* 功能说明: 动态加载管理任务。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/static VOID module_manager_entry(ULONG thread_input) {TX_PARAMETER_NOT_USED(thread_input);UINT status;uint8_t cmd;/* 初始化动态加载管理器,主要是给动态APP的数据空间使用 */status = txm_module_manager_initialize((VOID *) module_data_area, MODULE_DATA_SIZE);if (status != TX_SUCCESS) {Error_Handler();}/* 供动态APP使用的对象内存池,主要各种控制块申请 */status = txm_module_manager_object_pool_create(object_memory, OBJECT_MEM_SIZE);if (status != TX_SUCCESS) {Error_Handler();}/* 注册faults管理 */status = txm_module_manager_memory_fault_notify(module_fault_handler);if (status != TX_SUCCESS) {Error_Handler();}while (1) {if (comGetChar(COM1, &cmd)) /* 从串口读入一个字符(非阻塞方式) */{switch (cmd) {/* 加载APP1 */case '1':app_module_load(0);break;/* 卸载APP1 */case '2':app_module_unload(0);break;/* 加载APP2 */case '3':app_module_load(1);break;/* 卸载APP2 */case '4':app_module_unload(1);break;/* 打印任务执行情况 */case '5':app_task_info_out();break;default:break;}}tx_thread_sleep(1);}
}/*
*********************************************************************************************************
* 函 数 名: module_fault_handler
* 功能说明: 监测faults
* 形 参: ---
* 返 回 值: 无
*********************************************************************************************************
*/
static VOID module_fault_handler(TX_THREAD *thread, TXM_MODULE_INSTANCE *module) {tx_log("module_fault_handler: thread[%s],module[%s]\r\n", thread->tx_thread_name, module->txm_module_instance_name);/* 统计错误消息 */memory_faults++;
}/*** @brief 加载模块* @param idx 模块下标*/
static void app_module_load(uint8_t idx) {UINT status;ULONG module_properties;struct module_info_struct *module_inf;if (idx >= MODULE_TBL_SIZE) {tx_log("load idx(%d) out of bound\r\n", idx);return;}/*模块信息*/module_inf = &module_tbl[idx];if (module_inf->start_flag == STARTED_FLAG) {tx_log("module(%s) already started \r\n", module_inf->module_name);return;}/* 加载动态APP */status = txm_module_manager_in_place_load(&module_inf->instance,module_inf->module_name,(VOID *) module_inf->load_addr);if (status) {tx_log("txm_module_manager_in_place_load error:[%d]\r\n", status);return;}/* 获取动态APP属性 */status = txm_module_manager_properties_get(&module_inf->instance, &module_properties);if (status) {tx_log("txm_module_manager_properties_get error:[%d]\r\n", status);return;}/*模块信息打印*/app_txm_module_info_out(&module_inf->instance, module_properties);/* 启动动态APP */status = txm_module_manager_start(&module_inf->instance);tx_thread_sleep(1000);if (status != TX_SUCCESS) {tx_log("txm_module_manager_start error:[%d]\r\n", status);return;}/*更新信息*/module_inf->start_flag = STARTED_FLAG;tx_log("Module execution is started\n");}/*** @brief 卸载模块* @param idx 模块下标*/
static void app_module_unload(uint8_t idx) {UINT status;struct module_info_struct *module_inf;if (idx >= MODULE_TBL_SIZE) {tx_log("load idx(%d) out of bound\r\n", idx);return;}/*模块信息*/module_inf = &module_tbl[idx];if (module_inf->start_flag == STARTED_FLAG) { /*已经启动,才会卸载*//* 停止动态APP */status = txm_module_manager_stop(&module_inf->instance);if (status != TX_SUCCESS) {tx_log("==========================MODULE(%s) STOP ERR(%d)========================\r\n",module_inf->module_name, status);return;}/* 卸载动态APP */status = txm_module_manager_unload(&module_inf->instance);if (status != TX_SUCCESS) {tx_log("==========================MODULE(%s) UNLOAD ERR(%d)========================\r\n",module_inf->module_name, status);return;}tx_log("==========================MODULE(%s) UNLOAD OK========================\r\n", module_inf->module_name);} else {tx_log("==========================MODULE(%s) NOT STARTED========================\r\n", module_inf->module_name);}}static void app_txm_module_info_out(TXM_MODULE_INSTANCE *instance, ULONG prop) {tx_log("===============================app_txm_module_info_out================================\r\n");tx_log("------------------module build info------------------\r\n");tx_log("\t--Compiled for %s compiler\r\n",((prop >> 25) == 1) ? "CubeIDE (GNU)" : ((prop >> 24) == 1) ? "ARM KEIL" : "IAR EW");tx_log("\t--Shared/external memory access is %s\r\n", ((prop & 0x04) == 0) ? "Disabled" : "Enabled");tx_log("\t--MPU protection is %s\r\n", ((prop & 0x02) == 0) ? "Disabled" : "Enabled");tx_log("\t--%s mode execution is enabled for the module\r\n\r\n", ((prop & 0x01) == 0) ? "Privileged" : "User");tx_log("------------------module application info------------------\r\n");tx_log("\t--application id %#x;instance id:%#x;name:%s\r\n",instance->txm_module_instance_application_module_id,instance->txm_module_instance_id,instance->txm_module_instance_name);tx_log("\t--code section【start addr: %#x||end addr:%#x||size(bytes):%d】\r\n",instance->txm_module_instance_code_start,instance->txm_module_instance_code_end,instance->txm_module_instance_code_size);tx_log("\t--data section【start addr: %#x||end addr:%#x||size(bytes):%d】\r\n",instance->txm_module_instance_data_start,instance->txm_module_instance_data_end,instance->txm_module_instance_data_size);tx_log("\t--shared_memory 【addr:%#x||size(bytes): %d】\r\n",instance->txm_module_instance_shared_memory_address,instance->txm_module_instance_shared_memory_length);}
主程序和模块的通信
/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2024-4-13 shchl first version*/
#include "includes.h"
#include "txm_module.h"#define App_Printf_ID1 (TXM_APPLICATION_REQUEST_ID_BASE)
#define App_Printf_ID2 (TXM_APPLICATION_REQUEST_ID_BASE + 1)UINT module_manager_application_request(ULONG request_id,ALIGN_TYPE param_1,ALIGN_TYPE param_2,ALIGN_TYPE param_3) {switch (request_id) {/* 执行函数printf */case App_Printf_ID1:printf("执行APP1的打印函数:%lu\r\n", param_1);return TX_SUCCESS;/* 执行函数printf */case App_Printf_ID2:printf("执行APP2的打印函数:%lu\r\n", param_1);return TX_SUCCESS;default:{printf("module_manager_application_request:%lu not available\r\n",request_id);return TX_NOT_AVAILABLE;}}}
cpu 任务状态线程(未使用到threadx的内部工具代码)
/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2024-4-4 shchl first version*/
#include "includes.h"
/*
*******************************************************************************************************
* 任务相关宏定义
*******************************************************************************************************
*/
#define APP_TASK_CPU_STAT_PRIO 30
#define APP_TASK_CPU_STAT_STK_SIZE 1024
/*
*******************************************************************************************************
* 外部引入变量
*******************************************************************************************************
*/
#if defined(TX_EXECUTION_PROFILE_ENABLE)
extern EXECUTION_TIME _tx_execution_idle_time_total;
extern EXECUTION_TIME _tx_execution_thread_time_total;
extern EXECUTION_TIME _tx_execution_isr_time_total;
#endif/*
*******************************************************************************************************
* 变量
*******************************************************************************************************
*/
__IO double OSCPUUsage; /* CPU百分比 */
/*
*********************************************************************************************************
* 静态全局变量
*********************************************************************************************************
*/
static TX_THREAD cpu_stat_task_thread;
/*
*********************************************************************************************************
* 函数声明
*********************************************************************************************************
*/
static VOID task_cpu_stat_entry(ULONG input);
/*
*********************************************************************************************************
* 外部函数
*********************************************************************************************************
*/
/*** @brief cpu 状态任务* @param first_thread 第一个启动的任务线程首地址*/
int tx_task_cpu_stat_create() {tx_thread_create(&cpu_stat_task_thread, /* 任务控制块地址 */"app_cpu_stat", /* 任务名 */task_cpu_stat_entry, /* 启动任务函数地址 */0, /* 传递给任务的参数 */app_malloc(APP_TASK_CPU_STAT_STK_SIZE), /* 堆栈基地址 */APP_TASK_CPU_STAT_STK_SIZE, /* 堆栈空间大小 */APP_TASK_CPU_STAT_PRIO, /* 任务优先级*/APP_TASK_CPU_STAT_PRIO, /* 任务抢占阀值 */TX_NO_TIME_SLICE, /* 不开启时间片 */TX_AUTO_START); /* 创建后立即启动 */return TX_SUCCESS;
}TX_THREAD_EXPORT(tx_task_cpu_stat_create);/*
*********************************************************************************************************
* 函 数 名: app_task_info_out
* 功能说明: 将ThreadX任务信息通过串口打印出来
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/void app_task_info_out(void) {TX_THREAD *p_tcb = _tx_thread_identify(); /* 定义一个任务控制块指针,并指向当前线程 *//* 打印标题 */tx_log("调用线程======[%s]\r\n", p_tcb->tx_thread_name);
#if defined(TX_EXECUTION_PROFILE_ENABLE)tx_log("CPU利用率 = %5.2f%%\r\n", OSCPUUsage);tx_log("任务执行时间 = %.9fs\r\n", (double) _tx_execution_thread_time_total / SystemCoreClock);tx_log("空闲执行时间 = %.9fs\r\n", (double) _tx_execution_idle_time_total / SystemCoreClock);tx_log("中断执行时间 = %.9fs\r\n", (double) _tx_execution_isr_time_total / SystemCoreClock);tx_log("系统总执行时间 = %.9fs\r\n", (double) (_tx_execution_thread_time_total + \_tx_execution_idle_time_total + \_tx_execution_isr_time_total) / SystemCoreClock);
#endiftx_log("===============================================================\r\n");tx_log(" 任务优先级 任务栈大小 当前使用栈 最大栈使用 状态 任务名\r\n");tx_log(" Prio StackSize CurStack MaxStack Taskname\r\n");/* 遍历任务控制列表TCB list),打印所有的任务的优先级和名称 */while (p_tcb != (TX_THREAD *) 0) {tx_log(" %2d %5d %5d %5d %5d %s\r\n",p_tcb->tx_thread_priority,p_tcb->tx_thread_stack_size,(int) p_tcb->tx_thread_stack_end - (int) p_tcb->tx_thread_stack_ptr,(int) p_tcb->tx_thread_stack_end - (int) p_tcb->tx_thread_stack_highest_ptr,p_tcb->tx_thread_state,p_tcb->tx_thread_name);p_tcb = p_tcb->tx_thread_created_next;if (p_tcb == _tx_thread_identify()) break;}
}/*
*********************************************************************************************************
* 内部函数
*********************************************************************************************************
*/
static VOID task_cpu_stat_entry(ULONG input) {
#if defined(TX_EXECUTION_PROFILE_ENABLE)EXECUTION_TIME TolTime, IdleTime, deltaTolTime, deltaIdleTime;uint32_t uiCount = 0;(void) input;/* 计算CPU利用率 */IdleTime = _tx_execution_idle_time_total;TolTime = _tx_execution_thread_time_total + _tx_execution_isr_time_total + _tx_execution_idle_time_total;while (1) {/* CPU利用率统计 */uiCount++;if (uiCount == 20) {uiCount = 0;deltaIdleTime = _tx_execution_idle_time_total - IdleTime;deltaTolTime =_tx_execution_thread_time_total + _tx_execution_isr_time_total + _tx_execution_idle_time_total -TolTime;OSCPUUsage = (double) deltaIdleTime / deltaTolTime;OSCPUUsage = 100 - OSCPUUsage * 100;IdleTime = _tx_execution_idle_time_total;TolTime = _tx_execution_thread_time_total + _tx_execution_isr_time_total + _tx_execution_idle_time_total;}tx_thread_sleep(10);}
#elsewhile (1) {bsp_Idle();tx_thread_sleep(10);}#endif
}
模块脚本生成代码(根据实际情况进行调整)
生成txm静态库文件的脚本(注意代码中的路径)
/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2024-4-14 shchl thread txm lib 脚本构建*/
#include "main.h"
#include <dirent.h>
#include <sys/stat.h>
/*** @brief txm 源文件构建命令*/
const char *tx_txm_lib_source_build_cmd ="arm-none-eabi-gcc -c -g ""-mcpu=cortex-m4 ""-mfloat-abi=hard ""-mfpu=vfpv4 ""-mthumb ""-fpic -fno-plt ""-mno-pic-data-is-text-relative ""-msingle-pic-base ";
const char *tx_txm_lib_script = "tx_txm_static_lib_build.bat";/*根据实际情况修改*/
static char *txm_inc_list ="\t-IE:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\common\\inc""\t-IE:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\common_modules\\inc""\t-IE:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\ports_module\\cortex_m4\\gnu\\inc ";
static char *txm_lib_src_dir = "E:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\common_modules\\module_lib\\src";
static char *txm_lib_port_file = "E:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\ports_module\\cortex_m4\\gnu\\module_lib\\src\\txm_module_thread_shell_entry.c";void build_txm_lib() {FILE *pSaveFile = fopen(tx_txm_lib_script, "w");if (pSaveFile) {DIR *pDir = opendir(txm_lib_src_dir);/*删除之前的静态库文件*/fputs("del txm.a\n",pSaveFile);if (pDir) {struct dirent *pDirent = readdir(pDir);while (pDirent) {/*判断是否是.c文件*/if (strstr(pDirent->d_name, ".c")) {fprintf(pSaveFile, "%s %s %s\\%s\n",tx_txm_lib_source_build_cmd,txm_inc_list,txm_lib_src_dir,pDirent->d_name);} else if (strstr(pDirent->d_name, ".") && pDirent->d_namlen == 1) {// 当前目录} else if (strstr(pDirent->d_name, "..") && pDirent->d_namlen == 2) {// 上一级目录} else {// 其他判断}pDirent = readdir(pDir);}/*单独添加接口编译源文件*/fprintf(pSaveFile, "%s %s %s\n",tx_txm_lib_source_build_cmd,txm_inc_list,txm_lib_port_file);/*构建静态库*/fputs("arm-none-eabi-ar -r txm.a *.o\n",pSaveFile);/*删除.o文件*/fputs("del *.o\n",pSaveFile);}fclose(pSaveFile);}}
生成模块构建bin文件的脚本(注意对应的threadx的实际位置)
/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2024-4-14 shchl 生成模块应用脚本代码*/
#include "main.h"const char *tx_module_build_script = "tx_module_build.bat";/*指令格式*/
const char *common_del_cmd = "del *.o *.axf *.map"; /*通用删除指令*/
/*** @brief 编译指令 c文件编译成 目标文件*/
const char *module_compilar_to_obj_cmd ="arm-none-eabi-gcc -c -g ^\n""\t\t-mcpu=cortex-m4 ^\n""\t\t-mfloat-abi=hard ^\n""\t\t-mfpu=vfpv4 -fpie -fno-plt ^\n""\t\t-mno-pic-data-is-text-relative ^\n""\t\t-msingle-pic-base ";/*** @brief 链接文件+目标文件*/
const char *module_compilar_to_axf_cmd ="arm-none-eabi-ld -A cortex-m4 ^\n""\t\t-T %s %s ^\n""\t\t-e _txm_module_thread_shell_entry txm.a ^\n""\t\t-o app_module.axf ^\n""\t\t-M > app_module.map ";
const char *module_compilar_to_bin_cmd ="\narm-none-eabi-objcopy -O binary app_module.axf \"app_module.bin\" ""\narm-none-eabi-objcopy -O ihex app_module.axf \"app_module.hex\" ";/*模块使用的头文件目录*/
const char *module_inc_dir ="^\n\t\t-IE:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\common\\inc ""^\n\t\t-IE:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\common_modules\\inc ""^\n\t\t-IE:\\code\\clion\\STM32_Project\\Middleware\\threadx_6_4\\ports_module\\cortex_m4\\gnu\\inc ";void build_app_module_bat() {char *link_file = " ..\\app_module.ld ";char *asm_file_list = "^\n\t\t..\\app_module_preamble.S ""^\n\t\t..\\app_module_setup.s ";char *source_c_file_list ="^\n\t\t..\\app_module.c """;char *obj_file_list = "\tapp_module_preamble.o ""\tapp_module_setup.o ""\tapp_module.o ";const char *cmd_asm_fmt = "%s %s\n"; /*汇编指令格式*/const char *cmd_source_fmt = "%s %s %s\n"; /*汇编指令格式*/FILE *pFile = fopen(tx_module_build_script, "w");fprintf(pFile, "del *.bin *.hex\n");/*清除*//*汇编文件构建目标文件*/fprintf(pFile, cmd_asm_fmt, module_compilar_to_obj_cmd, asm_file_list);/*源文件构建目标文件*/fprintf(pFile, cmd_source_fmt, module_compilar_to_obj_cmd, module_inc_dir, source_c_file_list);/*目标文件构建axf 文件*/fprintf(pFile, module_compilar_to_axf_cmd, link_file, obj_file_list);/*生成bin文件和map文件*/fprintf(pFile, "%s", module_compilar_to_bin_cmd);/*删除 构建中间文件*/fprintf(pFile, "\n%s\n", common_del_cmd);/*清除*/fclose(pFile);
}
主函数
/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2024-4-14 shchl first version*/
#include "main.h"int main(void) {build_txm_lib();build_app_module_bat();return 0;
}
模块1
上述名称,可自行定义。
入口函数
#define TXM_MODULE#include "txm_module.h"/*
*********************************************************************************************************
* 宏定义
*********************************************************************************************************
*/
#define DEFAULT_STACK_SIZE 1024#define App_Printf_ID1 (TXM_APPLICATION_REQUEST_ID_BASE)
#define App_Printf_ID2 (TXM_APPLICATION_REQUEST_ID_BASE + 1)#define MODULE_THREAD_PRIO 3
#define MODULE_THREAD_PREEMPTION_THRESHOLD MODULE_THREAD_PRIOULONG AppModuleStk[DEFAULT_STACK_SIZE/4];/* 相关控制块 */
TX_THREAD *thread_0;
TX_QUEUE *resident_queue;/* 函数 */
void thread_0_entry(ULONG thread_input);
void Error_Handler1(void);/*
*********************************************************************************************************
* 函 数 名: default_module_start
* 功能说明: 动态APP入口
* 形 参: ---
* 返 回 值: 无
*********************************************************************************************************
*/
void demo_module_start(ULONG id)
{CHAR *pointer;/* 从主程序申请相关控制块,不在APP里面申请,防止APP出问题了影响主程序 */txm_module_object_allocate((void*)&thread_0, sizeof(TX_THREAD));/* 创建任务 */tx_thread_create(thread_0,"module thread 1",thread_0_entry,0,&AppModuleStk[0],DEFAULT_STACK_SIZE,MODULE_THREAD_PRIO,MODULE_THREAD_PREEMPTION_THRESHOLD,TX_NO_TIME_SLICE,TX_AUTO_START);}/*
*********************************************************************************************************
* 函 数 名: thread_0_entry
* 功能说明: 动态APP里面的任务
* 形 参: ---
* 返 回 值: 无
*********************************************************************************************************
*/
void thread_0_entry(ULONG thread_input)
{/* 防止警告 */UINT num = 0;while(1){/* 调用主程序里面的串口打印 */num++;txm_module_application_request(App_Printf_ID1, num, 0, 0);tx_thread_sleep(1000);}
}/*
*********************************************************************************************************
* 函 数 名: thread_0_entry
* 功能说明: 执行出错
* 形 参: ---
* 返 回 值: 无
*********************************************************************************************************
*/
void Error_Handler1(void)
{tx_thread_sleep(TX_WAIT_FOREVER);
}
链接文件(参考官网对应的设备内核)
这里设置的启动地址为0x08020000为的第一个模块的地址
MEMORY
{FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024KRAM (wx) : ORIGIN = 0x20000000, LENGTH = 128K
}SECTIONS
{__FLASH_segment_start__ = 0x08020000;__FLASH_segment_end__ = 0x08030000;__RAM_segment_start__ = 0x20000000;__RAM_segment_end__ = 0x20020000;__HEAPSIZE__ = 128;__preamble_load_start__ = __FLASH_segment_start__;.preamble __FLASH_segment_start__ : AT(__FLASH_segment_start__){__preamble_start__ = .;*(.preamble .preamble.*)}__preamble_end__ = __preamble_start__ + SIZEOF(.preamble);__dynsym_load_start__ = ALIGN(__preamble_end__ , 4);.dynsym ALIGN(__dynsym_load_start__ , 4) : AT(ALIGN(__dynsym_load_start__ , 4)){. = ALIGN(4);KEEP (*(.dynsym))KEEP (*(.dynsym*)). = ALIGN(4);}__dynsym_end__ = __dynsym_load_start__ + SIZEOF(.dynsym);__dynstr_load_start__ = ALIGN(__dynsym_end__ , 4);.dynstr ALIGN(__dynstr_load_start__ , 4) : AT(ALIGN(__dynstr_load_start__, 4)){. = ALIGN(4);KEEP (*(.dynstr))KEEP (*(.dynstr*)). = ALIGN(4);}__dynstr_end__ = __dynstr_load_start__ + SIZEOF(.dynstr);__reldyn_load_start__ = ALIGN(__dynstr_end__ , 4);.rel.dyn ALIGN(__reldyn_load_start__ , 4) : AT(ALIGN(__reldyn_load_start__ , 4)){. = ALIGN(4);KEEP (*(.rel.dyn))KEEP (*(.rel.dyn*)). = ALIGN(4);}__reldyn_end__ = __reldyn_load_start__ + SIZEOF(.rel.dyn);__relplt_load_start__ = ALIGN(__reldyn_end__ , 4);.rel.plt ALIGN(__relplt_load_start__ , 4) : AT(ALIGN(__relplt_load_start__ , 4)){. = ALIGN(4);KEEP (*(.rel.plt))KEEP (*(.rel.plt*)). = ALIGN(4);}__relplt_end__ = __relplt_load_start__ + SIZEOF(.rel.plt);__plt_load_start__ = ALIGN(__relplt_end__ , 4);.plt ALIGN(__plt_load_start__ , 4) : AT(ALIGN(__plt_load_start__ , 4)){. = ALIGN(4);KEEP (*(.plt))KEEP (*(.plt*)). = ALIGN(4);}__plt_end__ = __plt_load_start__ + SIZEOF(.plt);__interp_load_start__ = ALIGN(__plt_end__ , 4);.interp ALIGN(__interp_load_start__ , 4) : AT(ALIGN(__interp_load_start__ , 4)){. = ALIGN(4);KEEP (*(.interp))KEEP (*(.interp*)). = ALIGN(4);}__interp_end__ = __interp_load_start__ + SIZEOF(.interp);__hash_load_start__ = ALIGN(__interp_end__ , 4);.hash ALIGN(__hash_load_start__ , 4) : AT(ALIGN(__hash_load_start__, 4)){. = ALIGN(4);KEEP (*(.hash))KEEP (*(.hash*)). = ALIGN(4);}__hash_end__ = __hash_load_start__ + SIZEOF(.hash);__text_load_start__ = ALIGN(__hash_end__ , 4);.text ALIGN(__text_load_start__ , 4) : AT(ALIGN(__text_load_start__, 4)){__text_start__ = .;*(.text .text.* .glue_7t .glue_7 .gnu.linkonce.t.* .gcc_except_table )}__text_end__ = __text_start__ + SIZEOF(.text);__dtors_load_start__ = ALIGN(__text_end__ , 4);.dtors ALIGN(__text_end__ , 4) : AT(ALIGN(__text_end__ , 4)){__dtors_start__ = .;KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors))}__dtors_end__ = __dtors_start__ + SIZEOF(.dtors);__ctors_load_start__ = ALIGN(__dtors_end__ , 4);.ctors ALIGN(__dtors_end__ , 4) : AT(ALIGN(__dtors_end__ , 4)){__ctors_start__ = .;KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors))}__ctors_end__ = __ctors_start__ + SIZEOF(.ctors);__got_load_start__ = ALIGN(__ctors_end__ , 4);.got ALIGN(__ctors_end__ , 4) : AT(ALIGN(__ctors_end__ , 4)){. = ALIGN(4);_sgot = .;KEEP (*(.got))KEEP (*(.got*)). = ALIGN(4);_egot = .;}__got_end__ = __got_load_start__ + SIZEOF(.got);__rodata_load_start__ = ALIGN(__got_end__ , 4);.rodata ALIGN(__got_end__ , 4) : AT(ALIGN(__got_end__ , 4)){__rodata_start__ = .;*(.rodata .rodata.* .gnu.linkonce.r.*)}__rodata_end__ = __rodata_start__ + SIZEOF(.rodata);__code_size__ = __rodata_end__ - __FLASH_segment_start__;__fast_load_start__ = ALIGN(__rodata_end__ , 4);__fast_load_end__ = __fast_load_start__ + SIZEOF(.fast);__new_got_start__ = ALIGN(__RAM_segment_start__ , 4);__new_got_end__ = __new_got_start__ + SIZEOF(.got);.fast ALIGN(__new_got_end__ , 4) : AT(ALIGN(__rodata_end__ , 4)){__fast_start__ = .;*(.fast .fast.*)}__fast_end__ = __fast_start__ + SIZEOF(.fast);.fast_run ALIGN(__fast_end__ , 4) (NOLOAD) :{__fast_run_start__ = .;. = MAX(__fast_run_start__ + SIZEOF(.fast), .);}__fast_run_end__ = __fast_run_start__ + SIZEOF(.fast_run);__data_load_start__ = ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4);.data ALIGN(__fast_run_end__ , 4) : AT(ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4)){__data_start__ = .;*(.data .data.* .gnu.linkonce.d.*)}__data_end__ = __data_start__ + SIZEOF(.data);__data_load_end__ = __data_load_start__ + SIZEOF(.data);__FLASH_segment_used_end__ = ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4) + SIZEOF(.data);.data_run ALIGN(__fast_run_end__ , 4) (NOLOAD) :{__data_run_start__ = .;. = MAX(__data_run_start__ + SIZEOF(.data), .);}__data_run_end__ = __data_run_start__ + SIZEOF(.data_run);__bss_load_start__ = ALIGN(__data_run_end__ , 4);.bss ALIGN(__data_run_end__ , 4) (NOLOAD) : AT(ALIGN(__data_run_end__ , 4)){__bss_start__ = .;*(.bss .bss.* .gnu.linkonce.b.*) *(COMMON)}__bss_end__ = __bss_start__ + SIZEOF(.bss);__non_init_load_start__ = ALIGN(__bss_end__ , 4);.non_init ALIGN(__bss_end__ , 4) (NOLOAD) : AT(ALIGN(__bss_end__ , 4)){__non_init_start__ = .;*(.non_init .non_init.*)}__non_init_end__ = __non_init_start__ + SIZEOF(.non_init);__heap_load_start__ = ALIGN(__non_init_end__ , 4);.heap ALIGN(__non_init_end__ , 4) (NOLOAD) : AT(ALIGN(__non_init_end__ , 4)){__heap_start__ = .;*(.heap). = ALIGN(MAX(__heap_start__ + __HEAPSIZE__ , .), 4);}__heap_end__ = __heap_start__ + SIZEOF(.heap);__data_size__ = __heap_end__ - __RAM_segment_start__;
}
模块要求汇编文件(具体含义参考官方文档,这里主要注意入口函数名要对应模块文件中的入口函数)
.text.align 4.syntax unified/* Define public symbols. */.global __txm_module_preamble/* Define application-specific start/stop entry points for the module. */.global demo_module_start/* Define common external refrences. */.global _txm_module_thread_shell_entry.global _txm_module_callback_request_thread_entry__txm_module_preamble:.dc.l 0x4D4F4455 // Module ID.dc.l 0x6 // Module Major Version.dc.l 0x1 // Module Minor Version.dc.l 32 // Module Preamble Size in 32-bit words.dc.l 0x12345678 // Module ID (application defined).dc.l 0x02000004 // Module Properties where:// Bits 31-24: Compiler ID// 0 -> IAR// 1 -> ARM// 2 -> GNU// Bits 23-3: Reserved// Bit 2: 0 -> Disable shared/external memory access// 1 -> Enable shared/external memory access// Bit 1: 0 -> No MPU protection// 1 -> MPU protection (must have user mode selected - bit 0 set)// Bit 0: 0 -> Privileged mode execution// 1 -> User mode execution.dc.l _txm_module_thread_shell_entry - . - 0 // Module Shell Entry Point.dc.l demo_module_start - . - 0 // Module Start Thread Entry Point.dc.l 0 // Module Stop Thread Entry Point .dc.l 1 // Module Start/Stop Thread Priority.dc.l 1024 // Module Start/Stop Thread Stack Size.dc.l _txm_module_callback_request_thread_entry - . - 0 // Module Callback Thread Entry.dc.l 1 // Module Callback Thread Priority.dc.l 1024 // Module Callback Thread Stack Size.dc.l __code_size__ // Module Code Size.dc.l __data_size__ // Module Data Size.dc.l 0 // Reserved 0.dc.l 0 // Reserved 1.dc.l 0 // Reserved 2.dc.l 0 // Reserved 3.dc.l 0 // Reserved 4.dc.l 0 // Reserved 5.dc.l 0 // Reserved 6.dc.l 0 // Reserved 7.dc.l 0 // Reserved 8.dc.l 0 // Reserved 9.dc.l 0 // Reserved 10.dc.l 0 // Reserved 11.dc.l 0 // Reserved 12.dc.l 0 // Reserved 13.dc.l 0 // Reserved 14.dc.l 0 // Reserved 15
设置汇编文件 (这个直接使用的是threadx源码中提供的,主要做数据的拷贝和填充,共其他地方调用)
.text.align 4.syntax unified.global _gcc_setup.thumb_func
_gcc_setup:STMDB sp!, {r3, r4, r5, r6, r7, lr} // Store other preserved registersldr r3, =__FLASH_segment_start__ldr r4, =__RAM_segment_start__mov r5,r0/* Copy GOT table. */ldr r0, =__got_load_start__sub r0,r0,r3add r0,r0,r5ldr r1, =__new_got_start__sub r1,r1, r4add r1,r1,r9ldr r2, =__new_got_end__sub r2,r2,r4add r2,r2,r9new_got_setup:cmp r1, r2 // See if there are more GOT entriesbeq got_setup_done // No, done with GOT setupldr r6, [r0] // Pickup current GOT entrycmp r6, #0 // Is it 0?beq address_built // Yes, just skip the adjustmentcmp r6, r4 // Is it in the code or data area?blt flash_area // If less than, it is a code addresssub r6, r6, r4 // Compute offset of data areaadd r6, r6, r9 // Build address based on the loaded data addressb address_built // Finished building address
flash_area:sub r6, r6, r3 // Compute offset of code areaadd r6, r6, r5 // Build address based on the loaded code address
address_built:str r6, [r1] // Store in new GOT tableadd r0, r0, #4 // Move to next entryadd r1, r1, #4 // b new_got_setup // Continue at the top of the loop
got_setup_done:/* Copy initialised sections into RAM if required. */ldr r0, =__data_load_start__sub r0,r0,r3add r0,r0,r5ldr r1, =__data_start__sub r1,r1, r4add r1,r1,r9ldr r2, =__data_end__sub r2,r2,r4add r2,r2,r9bl crt0_memory_copy/* Zero bss. */ldr r0, =__bss_start__sub r0,r0,r4add r0,r0,r9ldr r1, =__bss_end__sub r1,r1,r4add r1,r1,r9mov r2, #0bl crt0_memory_set/* Setup heap - not recommended for Threadx but here for compatibility reasons */ldr r0, =__heap_start__sub r0,r0,r4add r0,r0,r9ldr r1, =__heap_end__sub r1,r1,r4add r1,r1,r9sub r1,r1,r0mov r2, #0str r2, [r0]add r0, r0, #4str r1, [r0]LDMIA sp!, {r3, r4, r5, r6, r7, lr} // Store other preserved registersbx lr // Return to caller.align 4/* Startup helper functions. */.thumb_func
crt0_memory_copy:cmp r0, r1beq memory_copy_donecmp r2, r1beq memory_copy_donesub r2, r2, r1
memory_copy_loop:ldrb r3, [r0]add r0, r0, #1strb r3, [r1]add r1, r1, #1sub r2, r2, #1cmp r2, #0bne memory_copy_loop
memory_copy_done:bx lr.thumb_func
crt0_memory_set:cmp r0, r1beq memory_set_donestrb r2, [r0]add r0, r0, #1b crt0_memory_set
memory_set_done:bx lr/* Setup attibutes of heap section so it doesn't take up room in the elf file */.section .heap, "wa", %nobits
模块2
- 与模块1不同的是模块函数 和链接文件中的启动地址不同,其他均一样
入口函数
#define TXM_MODULE#include "txm_module.h"/*
*********************************************************************************************************
* 宏定义
*********************************************************************************************************
*/
#define DEFAULT_STACK_SIZE 1024#define App_Printf_ID1 (TXM_APPLICATION_REQUEST_ID_BASE)
#define App_Printf_ID2 (TXM_APPLICATION_REQUEST_ID_BASE + 1)#define MODULE_THREAD_PRIO 3
#define MODULE_THREAD_PREEMPTION_THRESHOLD MODULE_THREAD_PRIOULONG AppModuleStk[DEFAULT_STACK_SIZE/4];/* 相关控制块 */
TX_THREAD *thread_0;
TX_QUEUE *resident_queue;/* 函数 */
void thread_0_entry(ULONG thread_input);
void Error_Handler1(void);/*
*********************************************************************************************************
* 函 数 名: default_module_start
* 功能说明: 动态APP入口
* 形 参: ---
* 返 回 值: 无
*********************************************************************************************************
*/
void demo_module_start(ULONG id)
{CHAR *pointer;/* 从主程序申请相关控制块,不在APP里面申请,防止APP出问题了影响主程序 */txm_module_object_allocate((void*)&thread_0, sizeof(TX_THREAD));/* 创建任务 */tx_thread_create(thread_0,"module thread 22",thread_0_entry,0,&AppModuleStk[0],DEFAULT_STACK_SIZE,MODULE_THREAD_PRIO,MODULE_THREAD_PREEMPTION_THRESHOLD,TX_NO_TIME_SLICE,TX_AUTO_START);}/*
*********************************************************************************************************
* 函 数 名: thread_0_entry
* 功能说明: 动态APP里面的任务
* 形 参: ---
* 返 回 值: 无
*********************************************************************************************************
*/
void thread_0_entry(ULONG thread_input)
{/* 防止警告 */UINT num = 0;while(1){/* 调用主程序里面的串口打印 */num++;txm_module_application_request(App_Printf_ID2, num, 0, 0);tx_thread_sleep(1000);}
}/*
*********************************************************************************************************
* 函 数 名: thread_0_entry
* 功能说明: 执行出错
* 形 参: ---
* 返 回 值: 无
*********************************************************************************************************
*/
void Error_Handler1(void)
{tx_thread_sleep(TX_WAIT_FOREVER);
}
链接文件
MEMORY
{FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024KRAM (wx) : ORIGIN = 0x20000000, LENGTH = 128K
}SECTIONS
{__FLASH_segment_start__ = 0x08040000;__FLASH_segment_end__ = 0x08050000;__RAM_segment_start__ = 0x20000000;__RAM_segment_end__ = 0x20020000;__HEAPSIZE__ = 128;__preamble_load_start__ = __FLASH_segment_start__;.preamble __FLASH_segment_start__ : AT(__FLASH_segment_start__){__preamble_start__ = .;*(.preamble .preamble.*)}__preamble_end__ = __preamble_start__ + SIZEOF(.preamble);__dynsym_load_start__ = ALIGN(__preamble_end__ , 4);.dynsym ALIGN(__dynsym_load_start__ , 4) : AT(ALIGN(__dynsym_load_start__ , 4)){. = ALIGN(4);KEEP (*(.dynsym))KEEP (*(.dynsym*)). = ALIGN(4);}__dynsym_end__ = __dynsym_load_start__ + SIZEOF(.dynsym);__dynstr_load_start__ = ALIGN(__dynsym_end__ , 4);.dynstr ALIGN(__dynstr_load_start__ , 4) : AT(ALIGN(__dynstr_load_start__, 4)){. = ALIGN(4);KEEP (*(.dynstr))KEEP (*(.dynstr*)). = ALIGN(4);}__dynstr_end__ = __dynstr_load_start__ + SIZEOF(.dynstr);__reldyn_load_start__ = ALIGN(__dynstr_end__ , 4);.rel.dyn ALIGN(__reldyn_load_start__ , 4) : AT(ALIGN(__reldyn_load_start__ , 4)){. = ALIGN(4);KEEP (*(.rel.dyn))KEEP (*(.rel.dyn*)). = ALIGN(4);}__reldyn_end__ = __reldyn_load_start__ + SIZEOF(.rel.dyn);__relplt_load_start__ = ALIGN(__reldyn_end__ , 4);.rel.plt ALIGN(__relplt_load_start__ , 4) : AT(ALIGN(__relplt_load_start__ , 4)){. = ALIGN(4);KEEP (*(.rel.plt))KEEP (*(.rel.plt*)). = ALIGN(4);}__relplt_end__ = __relplt_load_start__ + SIZEOF(.rel.plt);__plt_load_start__ = ALIGN(__relplt_end__ , 4);.plt ALIGN(__plt_load_start__ , 4) : AT(ALIGN(__plt_load_start__ , 4)){. = ALIGN(4);KEEP (*(.plt))KEEP (*(.plt*)). = ALIGN(4);}__plt_end__ = __plt_load_start__ + SIZEOF(.plt);__interp_load_start__ = ALIGN(__plt_end__ , 4);.interp ALIGN(__interp_load_start__ , 4) : AT(ALIGN(__interp_load_start__ , 4)){. = ALIGN(4);KEEP (*(.interp))KEEP (*(.interp*)). = ALIGN(4);}__interp_end__ = __interp_load_start__ + SIZEOF(.interp);__hash_load_start__ = ALIGN(__interp_end__ , 4);.hash ALIGN(__hash_load_start__ , 4) : AT(ALIGN(__hash_load_start__, 4)){. = ALIGN(4);KEEP (*(.hash))KEEP (*(.hash*)). = ALIGN(4);}__hash_end__ = __hash_load_start__ + SIZEOF(.hash);__text_load_start__ = ALIGN(__hash_end__ , 4);.text ALIGN(__text_load_start__ , 4) : AT(ALIGN(__text_load_start__, 4)){__text_start__ = .;*(.text .text.* .glue_7t .glue_7 .gnu.linkonce.t.* .gcc_except_table )}__text_end__ = __text_start__ + SIZEOF(.text);__dtors_load_start__ = ALIGN(__text_end__ , 4);.dtors ALIGN(__text_end__ , 4) : AT(ALIGN(__text_end__ , 4)){__dtors_start__ = .;KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors))}__dtors_end__ = __dtors_start__ + SIZEOF(.dtors);__ctors_load_start__ = ALIGN(__dtors_end__ , 4);.ctors ALIGN(__dtors_end__ , 4) : AT(ALIGN(__dtors_end__ , 4)){__ctors_start__ = .;KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors))}__ctors_end__ = __ctors_start__ + SIZEOF(.ctors);__got_load_start__ = ALIGN(__ctors_end__ , 4);.got ALIGN(__ctors_end__ , 4) : AT(ALIGN(__ctors_end__ , 4)){. = ALIGN(4);_sgot = .;KEEP (*(.got))KEEP (*(.got*)). = ALIGN(4);_egot = .;}__got_end__ = __got_load_start__ + SIZEOF(.got);__rodata_load_start__ = ALIGN(__got_end__ , 4);.rodata ALIGN(__got_end__ , 4) : AT(ALIGN(__got_end__ , 4)){__rodata_start__ = .;*(.rodata .rodata.* .gnu.linkonce.r.*)}__rodata_end__ = __rodata_start__ + SIZEOF(.rodata);__code_size__ = __rodata_end__ - __FLASH_segment_start__;__fast_load_start__ = ALIGN(__rodata_end__ , 4);__fast_load_end__ = __fast_load_start__ + SIZEOF(.fast);__new_got_start__ = ALIGN(__RAM_segment_start__ , 4);__new_got_end__ = __new_got_start__ + SIZEOF(.got);.fast ALIGN(__new_got_end__ , 4) : AT(ALIGN(__rodata_end__ , 4)){__fast_start__ = .;*(.fast .fast.*)}__fast_end__ = __fast_start__ + SIZEOF(.fast);.fast_run ALIGN(__fast_end__ , 4) (NOLOAD) :{__fast_run_start__ = .;. = MAX(__fast_run_start__ + SIZEOF(.fast), .);}__fast_run_end__ = __fast_run_start__ + SIZEOF(.fast_run);__data_load_start__ = ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4);.data ALIGN(__fast_run_end__ , 4) : AT(ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4)){__data_start__ = .;*(.data .data.* .gnu.linkonce.d.*)}__data_end__ = __data_start__ + SIZEOF(.data);__data_load_end__ = __data_load_start__ + SIZEOF(.data);__FLASH_segment_used_end__ = ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4) + SIZEOF(.data);.data_run ALIGN(__fast_run_end__ , 4) (NOLOAD) :{__data_run_start__ = .;. = MAX(__data_run_start__ + SIZEOF(.data), .);}__data_run_end__ = __data_run_start__ + SIZEOF(.data_run);__bss_load_start__ = ALIGN(__data_run_end__ , 4);.bss ALIGN(__data_run_end__ , 4) (NOLOAD) : AT(ALIGN(__data_run_end__ , 4)){__bss_start__ = .;*(.bss .bss.* .gnu.linkonce.b.*) *(COMMON)}__bss_end__ = __bss_start__ + SIZEOF(.bss);__non_init_load_start__ = ALIGN(__bss_end__ , 4);.non_init ALIGN(__bss_end__ , 4) (NOLOAD) : AT(ALIGN(__bss_end__ , 4)){__non_init_start__ = .;*(.non_init .non_init.*)}__non_init_end__ = __non_init_start__ + SIZEOF(.non_init);__heap_load_start__ = ALIGN(__non_init_end__ , 4);.heap ALIGN(__non_init_end__ , 4) (NOLOAD) : AT(ALIGN(__non_init_end__ , 4)){__heap_start__ = .;*(.heap). = ALIGN(MAX(__heap_start__ + __HEAPSIZE__ , .), 4);}__heap_end__ = __heap_start__ + SIZEOF(.heap);__data_size__ = __heap_end__ - __RAM_segment_start__;
}
测试方式
- 主程序通过jlink直接下载烧录即可
- 模块应用,通过脚本生成bin文件,通过jflash进行对应的地址烧录,此步骤不能擦除主程序的存放的空间