构建配置与内存分区

解释CMake/SDK配置/编译链接、Flash与运行内存、16MiB分区及字库成本;旧脚本和缓存不能证明当前构建。

版本与验证范围

静态源码/电路核对;用户历史反馈单独注明;本次未编译、烧录或测量

返回00-项目导航;先读01-工程版本与真实现状。

本篇解释真实工程怎样变成固件,以及代码、字库和数据分别占用什么空间。命令仅供后续练习,本次没有执行构建或烧录。

一、从三个源文件到固件

驱动验证工程的 main/CMakeLists.txt 登记了:

cmake
idf_component_register(
    SRCS "main.c" "epd_ssd1683.c" "epd_gui.c"
    INCLUDE_DIRS "."
    REQUIRES driver
)

SRCS决定该组件的哪些源文件参与编译,INCLUDE_DIRS指定头文件搜索位置,REQUIRES声明组件依赖。头文件存在不代表对应实现已经参与链接;源文件放进目录也不代表构建系统一定会使用。

构建可以按下列流程理解:

流程示意 按原 Mermaid 线性链重绘
  1. 源代码和工程配置
  2. 构建配置生成
  3. 逐个编译为目标文件
  4. 链接为可执行文件
  5. 生成烧录镜像
  6. 结合分区和偏移烧录
查看原始 Mermaid 源码
mermaid
flowchart LR
  A[源代码和工程配置] --> B[构建配置生成]
  B --> C[逐个编译为目标文件]
  C --> D[链接为可执行文件]
  D --> E[生成烧录镜像]
  E --> F[结合分区和偏移烧录]

idf.py是操作入口,CMake组织依赖,Ninja执行构建步骤,编译器处理C/C++,链接器合并实现并分配地址。.elf保留调试符号,.bin用于烧录;二者不能互相替代。

工程能编译说明语法、类型和链接等检查通过,不能证明排线方向、忙信号、升压或页面逻辑正确。

二、配置的来源有先后

本项目同时有 Kconfig.projbuild、sdkconfig.defaults 和 sdkconfig:

  • Kconfig.projbuild定义可配置项及默认值,例如屏幕数据引脚。
  • sdkconfig.defaults提供建立配置时使用的默认项,不能把它当作覆盖全部现有配置的指令。
  • sdkconfig保存当前实际工程配置,构建还会生成供源码使用的配置头文件。

驱动验证工程存在一个具体例子:配置菜单提供屏幕宽高,但 epd_ssd1683.h中仍直接定义 EPD_WIDTH=400、EPD_HEIGHT=300。所以仅在菜单里改分辨率,不代表画布和驱动就全部适配了新屏。

另一例是 N16R8的注释与8MB Flash配置不一致。应按实物、配置、启动记录三方核实,不能选看起来最像正确答案的一项。

三、Flash、内部运行内存与外部运行内存

类型 主要用途 断电后 本项目中的例子
Flash 固件、只读字库、配置与文件分区 一般保留 程序镜像、非易失配置、图片文件
内部运行内存 任务栈、变量、通信和驱动缓冲 通常丢失 静态画布、实时任务数据
外部运行内存 扩展可用堆空间 通常丢失 验证工程优先尝试分配的画布、加载的字库

Flash容量不是可直接用于malloc()的内存容量。 一个16MB Flash的系统仍可能因为内部堆不足而请求失败。

单色400×300画布每像素占1比特:

text
400 × 300 ÷ 8 = 15000字节

驱动验证工程的 epd_gui.c:23 起先尝试外部运行内存,失败后再尝试普通分配。只有拿到非空指针才可写画布。

信息终端工程的 main.c:100 与 main.c:212 则分别定义当前画布和上次画布,共30000字节静态数组。它们不是同一个15000字节区域;最终放在哪个内存段,要看链接映射文件,而不是因为“启用了外部运行内存”就默认它们在那里。

四、分区是Flash的地址规划

信息终端工程启用了自定义 partitions.csv:

名称 起始偏移 大小 用途
nvs 0x9000 0x5000 小型键值配置
phy_init 0xe000 0x1000 射频初始化数据区域
factory 0x10000 0x300000 应用镜像分区,3MiB
storage 0x310000 0xCF0000 文件系统分区

最后一个分区结束地址为 0x1000000,对应16MiB地址空间。这里MiB按1024×1024字节计算。

大部分空间留给文件系统,不代表应用可以长到16MB;应用仍受3MiB分区限制。当前表也没有两个升级应用槽,不能因为留有空间就说已具备远程升级机制。

驱动验证工程使用单应用分区配置,不能把信息终端的分区表直接套过去。

五、字库为什么特别占空间

信息终端有中文和大字号字库,main/CMakeLists.txt明确启用 FONT48_INCLUDE,其他尺寸根据编译开关选择。源代码文件占了数兆字节,不等于链接后二进制也占同样大小,因为源文件包含文本形式的十六进制数字、逗号和注释。

反过来,字库被引用并参与链接后,就会占固件分区或只读数据空间。判断应看.map、idf.py size和实际镜像大小。

对于从存储卡加载的字库,还要算加载后的运行内存、读取失败回退和字形索引;它节省固件空间时,可能增加启动时间和存储卡依赖。

六、建立可信的构建记录

当前两个工程的旧构建缓存都带有旧目录。验证工程的批处理脚本还切到了另一个项目,所以不要先双击脚本再根据最后一行猜编译了什么。

后续在正确开发环境中,可以按以下顺序练习;这些命令未在本次运行:

powershell
# 先在终端进入所选工程目录
Get-Location
idf.py --version
idf.py -B build_current_check build
idf.py -B build_current_check size

先确认终端已加载正确ESP-IDF环境;idf.py --version应实际成功。使用新的构建目录可以避开原有缓存,但仍会写入工程文件夹,只在准备开发时执行。

记录至少包含:工程绝对路径、源码版本或校验值、ESP-IDF版本、目标芯片、配置副本、完整退出结果、镜像大小及警告。遇到分区超限、字库膨胀、缺头文件或找不到实现时,分别沿分区、编译列表与链接关系检查。

七、练习与验收

  1. 不运行程序,指出三个主要源文件在哪里登记,解释删去绘图源文件可能出现什么链接错误。
  2. 算出一帧、两帧单色画布占用;再算相同分辨率每像素16比特时的占用,解释当前项目为何不使用这种格式。
  3. 核算分区末地址,区分“整个Flash还很大”和“应用分区已满”。
  4. 后续取得一次新的成功构建日志,与旧缓存对照,明确哪一份证明当前源码可构建。

官方参考:乐鑫构建系统、乐鑫堆内存分配。具体源码位置按本次核对版本记录。

来源与关联索引
来源
嵌入式比赛
原笔记
项目/墨嵌墨水屏/知识讲解/09-构建配置与内存分区.md
资料性质
实践指南。原文的版本、来源与验证边界继续保留。
关联笔记 4
返回文章目录

想去哪里?

22 个入口

首页作品作品展厅全部项目文章总览文件夹标签资料归档关于认识 Lan探索路线工具与工作台最近在做InkFeed · 4.2 英寸电子纸信息终端VIBRATION · 柔性振动检测与采集链路TRACE · 航向保持与灰度循迹小车STRIDE · 八自由度四足机器人SCOPE · 固件日志浏览器温度为什么被 AI 改了?FIFO 有半帧,就一定是故障吗?直线守航向,弧线再看黑线。

Tab 选择入口 · Enter 打开 · Esc 关闭