文章目录
在前一篇 《DIY USB 电流表(8):绘制功率曲线》 的开发过程中,我还碰到一个额外的问题,在最终开源的代码中虽然已经解决了,但是在文章中并没有提到,这就是编译固件体积超出 Flash 限制的问题。
这里就分享一下碰到 CH32V003 固件编译后体积超过 Flash 如何查找原因、解决问题的过程。
PS. 我也还是一个初学者,如果文章中有一些错误或不足,还请多多指教。
编译后固件体积超标
在定义了功率历史数据缓存的变量,添加数据存储、屏幕画点驱动、按键检测等代码之后,照常编译一下固件,检查一下代码有没有错误,却突然发现编译出错了:
一看错误原因: region 'FLASH' overflowed by 772 bytes
,这就意味着编译完的固件体积已经超过了 CH32V003 的限制,毕竟CH32V003 只有 16KB 的用户代码空间。
在前几篇中编译完成也可以发现,固件体积已经快到达极限了,没想到这么快就已经超出不够用了。
排查固体体积构成
幸好 PlatformIO 提供了 Inspect 功能,可以用于分析固件编译产物中的各种资源使用情况,包括 Flash 占用、内存使用、静态代码检查等,通过这个工具,就可以快速分析固件编译完后,哪块代码或资源占用的体积最大。
PlatformIO Inspect 文档可以参考这里: https://docs.platformio.org/en/latest/home/index.html#project-inspect
使用 Inspect
要使用 PlatformIO Inspect 功能很简单,直接在 PlatformIO 侧边栏中通过菜单打开 Inspect 工具。
PlatformIO 会展示 Project Inspection 选项界面,这里可以选择分析哪个项目、分析哪些内容:
注意:要使用 PlatformIO Inspect,需要先保证固件能在 Inspect 环境编译通过,并且使用 Inspect 功能时,可能固件体积会相比正常编译更大,这个时候可以通过删除一部分代码来使编译通过,从而正常使用 Inspect 功能。
分析结果
在点击 Inspect 按钮后,PlatformIO 就会开始编译整个项目,并且记录项目中各种资源、符号的体积。
最终 PlatformIO 会生成一个报表,包括固件的内存使用情况、Flash 使用情况以及可能存在的代码缺陷。
另外在统计界面,还可以看到主要的体积占用是哪些符号或文件导致的。
在这里我们主要关注 Flash 占用情况,并且主要关注 Symbols 中的体积大小。
解决问题
排查固件大小超标元凶
进入到 Inspect 功能的 Symbols 界面,并将整个列表按 Size 倒序排列,可以看到哪些符号占用了特别大的体积。
在这个列表中,如果符号有对应的源代码位置,也可以直接通过符号后面的放大镜定位到代码位置。
在上面的符号列表中,可以看到 __subdf3
、__divdf3
、ssd1306xled_font8x16mdos
、__muldf3
这几个符号的体积特别大,单个体积都超过了 1K。其中 ssd1306xled_font8x16mdos
我们可以明确知道,这个是英文字符的字体文件,没办法删除。
那么另外三个符号就很可疑了,通过搜索我们可以发现,这三个符号都是浮点计算相关的代码,并且还是软件浮点计算库。
这就奇怪了,难道 CH32V003 并没有集成硬件浮点计算功能吗?通过查阅数据手册以及 RISC-V 指令集的支持情况,CH32V003 使用的指令集为 RV32EC,它并不包含浮点计算相关的指令。
找寻浮点计算源头
在我们自己编写的固件代码中,基本都没有使用浮点类型,少有的浮点数据也是从 INA219 驱动中获取的,因此就从 INA219 开始排查。
在 INA219_WE 库的代码中,可以看到大量浮点计算相关的代码,并且在我们主要使用的两个方法 setShuntSizeInOhms
和 getShuntVoltage_mV
中,就有浮点计算的代码。
可以看到,在这两个方法中,分别使用除法和减法,计算了采样电阻的系数和用户设置的采样电阻电压偏移。
那么我们就从这两个方法入手,优化一下看看能不能减少固件体积吧。
优化固件体积
在前面的符号表中,我们可以知道这里同样有浮点乘法的使用,并且在数据管理中,也会存在需要使用浮点乘法的情况,例如通过电压、电流计算功率。
除法换乘法
在采样电阻系数的计算中,可以看到它是按标准 100 豪欧采样电阻来计算的,它这里使用了除法来计算系数,因为乘法必不可少,这里将它换成乘法来减少除法的使用。
去掉减法
另外,我们并没有去设置采样电阻偏移校正,因此可以将 getShuntVoltage_mV
中的偏移校正直接去掉,这样就可以去掉浮点减法的使用了。
当然,这只是我们的一次尝试,还需要实际检验一下,才能知道这样的优化是否有效果。
检验优化效果
再次使用 PlatformIO Inspect 工具,对固件体积进行分析。
从分析结果看,固件体积减少了 2.8KB,大大小于之前的 15.5KB。
并且在 Symbols 页面中也看不到 __subdf3
、__divdf3
方法了。
再次将固件需要的代码添加进项目,已经可以正常编译了:
小结
CH32V003 的资源相当紧张,还不支持硬件浮点指令,因此在固件开发时需要额外注意资源、指令的使用情况,尽量使用整数的计算,如果需要使用浮点,也可以尽量合并,否则就要面临 Flash 不够用的问题了 😂。
从这个问题也感受了一下廉价 MCU 在开发时的局限性,作为现代移动端和桌面端软件工程师,平时也难感受到在 Flash 和内存以 KB 为单位场景中的开发体验。
USB 电流表开源地址
这个 USB 电流表所有资料已经开源,可以在以下仓库中获取,包含固件代码、PCB 生产 Gerber 文件、原理图和外壳 STL 文件。
https://github.com/ohdarling/CH32V003-USBMeter
硬件相关的源文件已经在立创开源平台开源,访问以下地址可以进行一键 PCB 下单和一键 BOM 配单操作:
https://oshwhub.com/wandaeda/ji-yu-ch32v003-de-usb-dian-liu-biao
DIY USB 电流表系列
- DIY USB 电流表(8):检测按键和绘制功率曲线
- DIY USB 电流表(7):读取和显示 INA219 电流电压数据
- DIY USB 电流表(6):点个屏,使用 I2C 驱动 0.96 寸 OLED
- DIY USB 电流表(5):使用 VSCode + PlatformIO 搭建固件开发环境
- DIY USB 电流表(4):PCB 焊接与调试
- DIY USB 电流表(3):PCB 免费打样详解
- DIY USB 电流表(2):PCB 布局布线
- DIY USB 电流表(1):元件选型和原理图绘制
其他 DIY 项目
30 元 DIY 一个柔性灯丝氛围灯
教程地址: https://xujiwei.com/blog/2024/04/diy-ambient-light/
参考资料
- https://github.com/wagiminator/CH32V003-GameConsole
- https://github.com/ohdarling/CH32V003-USBMeter
- https://oshwhub.com/wandaeda/ji-yu-ch32v003-de-usb-dian-liu-biao
- https://docs.platformio.org/en/latest/home/index.html#project-inspect
- https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html
- https://zh.wikipedia.org/wiki/RISC-V
0 条评论。