1、问题引出
前阵子开源了一个基于TencentOS tiny
物联网操作系统的危险气体探测仪项目,截止目前在Gitee
上斩获了24个Star以及8个Fork,该项目也成功被Gitee
官方推荐为优质开源项目。
分享的文章如下:
TencentOS tiny危险气体探测仪产品级开发重磅高质量更新
前两天还发了一篇LCD显示曲线的文章,我也把曲线显示这个功能加到这个开源项目进来了,看如下效果:
让传感器数据更直观之LCD曲线显示
但是有个问题,这个项目编译完的信息如下:
这里我们又要来唠一唠之前讲过的基础知识,加强大家的印象:
- Code:表示程序代码部分
- RO-Data:表示程序定义的所有常量以及const型数据
- RW-Data:表示已经初始化的所有静态变量,变量有初值
- ZI-Data:表示未初始化的所有静态变量,变量无初值
关于MCU ROM和RAM的计算规则如下:
- ROM(FLASH) Size = Code RO-Data RW-Data
- RAM Size = RW-Data ZI-Data
我们再来看看这款MCU手册的描述:
由此可见,如果我们再往下继续添加代码的话,很快资源就不够了,但是我还是想继续往下添加更多功能呀,怎么办??如何优化?
2、问题解决
要解决这个问题,就很有必要来瞧瞧xxx.map文件了,我们找到这个MDK-ARM编译目录下的main.map文件:
打开这个文件,然后滑到最底下可以看到如下信息:
通过这个信息,我们可以详细了解我们MCU的资源使用情况,也能基于这个资源使用情况继续评估项目往下做的可行性;然后我们继续从底下往上滑,可以看到这个文件代码占用资源的详细情况:
根据刚刚的编译信息,很显然,RO-Data的占用比较多,那我们就来分析一下这个部分是哪些文件占得比较多,我们就针对这个来进行优化,裁剪一些不必要的功能,最直接有效的方法,我们看到Image component sizes
如下:
cc936.c
这个文件包含了对中文支持的一些处理和转换函数,该文件位于fatfs组件的option目录下,我们打开来看一下:
原来最大的罪魁祸首就是它!
接下来我们把这个数组屏蔽掉,然后将用到它的地方做注释并修改以下转换函数ff_convert
如下:
WCHAR ff_convert ( /* Converted code, 0 means conversion error */
WCHAR chr, /* Character code to be converted */
UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */
)
{
#if 0
const WCHAR *p;
WCHAR c;
int i, n, li, hi;
if (chr < 0x80) { /* ASCII */
c = chr;
} else {
if (dir) { /* OEM code to unicode */
p = oem2uni;
hi = sizeof oem2uni / 4 - 1;
} else { /* Unicode to OEM code */
p = uni2oem;
hi = sizeof uni2oem / 4 - 1;
}
li = 0;
for (n = 16; n; n--) {
i = li (hi - li) / 2;
if (chr == p[i * 2]) break;
if (chr > p[i * 2])
li = i;
else
hi = i;
}
c = n ? p[i * 2 1] : 0;
}
#endif
/*重新改下这个函数*/
WCHAR c;
if (chr < 0x80) { /* ASCII */
c = chr;
}
return c;
}
这样的话就把中文处理的这款逻辑给去掉了,我们再对工程编译一下:
这时候可以发现ROM只有不到84KB的大小,成功实现了优化,并且软件可以正常运行,不受影响。
针对RAM的优化方法,和ROM方法一样的分析方法,我们最终发现RAM占用得比较多的地方是:tos_global.c
这个文件,如下:
这个文件主要定义了一些和TencentOS tiny
内核相关的一些核心变量,最终发现RAM占用其实依赖于tos_config.h
里的一些配置选项,我们可以根据项目需求动态调整是否需要支持一些OS提供的组件,还可以修改堆栈大小,忽然发现我之前配置的0x8000有点大,所以给它改成了0x4000,然后把一些不必要的模块裁剪掉,最后裁剪结果如下:
#ifndef _TOS_CONFIG_H_
#define _TOS_CONFIG_H_
#include "stm32l4xx_hal.h" // 目标芯片头文件,用户需要根据情况更改
#define TOS_CFG_TASK_PRIO_MAX 10u // 配置TencentOS tiny默认支持的最大优先级数量
#define TOS_CFG_ROUND_ROBIN_EN 1u // 配置TencentOS tiny的内核是否开启时间片轮转
#define TOS_CFG_OBJECT_VERIFY_EN 1u // 配置TencentOS tiny是否校验指针合法
#define TOS_CFG_TASK_DYNAMIC_CREATE_EN 1u // TencentOS tiny 动态任务创建功能宏
#define TOS_CFG_EVENT_EN 1u // TencentOS tiny 事件模块功能宏
#define TOS_CFG_MMBLK_EN 1u //配置TencentOS tiny是否开启内存块管理模块
#define TOS_CFG_MMHEAP_EN 1u //配置TencentOS tiny是否开启动态内存模块
#define TOS_CFG_MMHEAP_DEFAULT_POOL_EN 1u // TencentOS tiny 默认动态内存池功能宏
#define TOS_CFG_MMHEAP_DEFAULT_POOL_SIZE 0x4000 // 配置TencentOS tiny默认动态内存池大小
#define TOS_CFG_MUTEX_EN 1u // 配置TencentOS tiny是否开启互斥锁模块
#define TOS_CFG_MESSAGE_QUEUE_EN 0u // 配置TencentOS tiny是否开启消息队列模块
#define TOS_CFG_MAIL_QUEUE_EN 0u // 配置TencentOS tiny是否开启消息邮箱模块
#define TOS_CFG_PRIORITY_MESSAGE_QUEUE_EN 0u // 配置TencentOS tiny是否开启优先级消息队列模块
#define TOS_CFG_PRIORITY_MAIL_QUEUE_EN 0u // 配置TencentOS tiny是否开启优先级消息邮箱模块
#define TOS_CFG_TIMER_EN 0u // 配置TencentOS tiny是否开启软件定时器模块
#define TOS_CFG_PWR_MGR_EN 0u // 配置TencentOS tiny是否开启外设电源管理模块
#define TOS_CFG_TICKLESS_EN 0u // 配置Tickless 低功耗模块开关
#define TOS_CFG_SEM_EN 1u // 配置TencentOS tiny是否开启信号量模块
#define TOS_CFG_TASK_STACK_DRAUGHT_DEPTH_DETACT_EN 1u // 配置TencentOS tiny是否开启任务栈深度检测
#define TOS_CFG_FAULT_BACKTRACE_EN 0u // 配置TencentOS tiny是否开启异常栈回溯功能
#define TOS_CFG_IDLE_TASK_STK_SIZE 64u // 配置TencentOS tiny空闲任务栈大小
#define TOS_CFG_CPU_TICK_PER_SECOND 1000u // 配置TencentOS tiny的tick频率
#define TOS_CFG_CPU_CLOCK (SystemCoreClock) // 配置TencentOS tiny CPU频率
#define TOS_CFG_TIMER_AS_PROC 1u // 配置是否将TIMER配置成函数模式
#endif
然后我们继续编译,然后看map文件,看看RAM是否变小了:
在此我们可以发现经过裁剪优化后,确实达到了效果;这样我们就可以继续往下添加新的功能了!
这种分析和优化方法也是我工作乃至平时做项目的时候最常用的一种手段,当然还有其它更好的辅助手段,也希望小伙伴们积极分享,大家一起共同学习、共同成长!
本节代码已同步到码云的代码仓库中,获取方法如下:
1、新建一个文件夹
2、使用git clone远程获取例程存放的代码仓库
项目开源仓库:
代码语言:javascript复制https://gitee.com/morixinguan/tencent-os-tiny-hazardous-gas-detector
我还将之前做的一些项目以及练习例程在近期内全部上传完毕,与大家一起分享交流: