Skip to content

docs(esp32c3): 刷写配方与格式级验证(esptool elf2image/image_info) - #22

Merged
gqf2008 merged 3 commits into
masterfrom
docs/esp32c3-flash-recipe
Sep 19, 2026
Merged

gqf2008 merged 3 commits into
masterfrom
docs/esp32c3-flash-recipe

Conversation

@gqf2008

@gqf2008 gqf2008 commented Sep 19, 2026

Copy link
Copy Markdown
Owner

第 4 项:esp32c3 可刷写镜像——不做手搓格式,而是把"用官方工具把本口 ELF 变成 esp 镜像"
这条正路验证出来并写进文档。

做法与验证(本机无硬件 → 只能到格式级,这正是本项的边界)

  1. 装官方工具:python -m venv … && pip install esptool → esptool 5.4.0。
  2. 用本口的 imc(真 ISA)产物跑官方转换:
    esptool --chip esp32c3 elf2image <target/riscv32imc-.../examples/multitask_esp32c3>
    → 直接成功("Creating ESP32-C3 image… Successfully created ESP32-C3 image.",合并 1 个 ELF 段)。
    说明本口 memory.x 的映射(FLASH 0x42000000 IROM / RAM 0x3FC88000 DRAM)正是 C3 期望的形态。
  3. 用官方解析器复核产物:esptool --chip esp32c3 image_info <out.bin> →
    Image version 1、magic 0xE9、3 段、entry 0x42000000、Chip ID 5 (ESP32-C3)、
    WP pin disabled、扩展头正常。产物 103,696 B。
  4. 两条上板路径写进文档:(a) direct boot = 把该镜像直接烧到 flash 0x0(ROM 读 0x0 的镜像头跳 entry);
    (b) 常规 = 配合 esp-idf 的 bootloader + 分区表把 app 烧到 0x10000。
    ⚠️ 如实标注:走 (b) 时 IDF bootloader 还会校验 app 描述符(esp_app_desc_t / .flash.appdesc 段),
    本口还没提供——上板前要么补它,要么走 (a)。这条"缺口"是本轮唯一没有闭环的点,已写进
    src/chip/esp32c3/mod.rs 的核对清单。

改动

  • src/chip/esp32c3/mod.rs 头注:核对点①由"常规路径本口未做"改成两条路径 + 已做的格式级验证 + (b) 的 app 描述符缺口。
  • README.md 的 ESP32C3 条目:补刷写配方与验证结论。

验证

  • 完整 bash ci/gate.sh 全绿(见下,与文档一致);esp32c3 按 imc 的构建步骤仍在门禁里。

Refs #14

问题:`READYQ = [[TaskQueue; 16]; MAX_HARTS]`,而 `MAX_HARTS` 恒为 16 → **单核口**也静态占
`16 × 16 × 16B = 4096B`(实测符号 `READYQ = 0x1000`)。CH572 只有 12K RAM,这一项等于
**三分之一的 RAM**,直接挤掉了应用可用的堆。

改法:`MAX_HARTS` 移进 `src/chip/env.rs` 按芯片取值——单核 WCH 口(ch583/ch572)取 **1**,
其余口(含多核的 qemu_riscv)保持 16;`src/port.rs` 改为 re-export,既有
`crate::port::MAX_HARTS` 的引用路径不变(全部调用点沿用 `.min(MAX_HARTS-1)` 的既有守卫)。

## 效果(实测符号/段地址)

| 口 | READYQ | `_sheap` | 可用堆 |
|---|---|---|---|
| ch572 | 0x1000 → **0x100** | 0x20001180 → **0x200001B0** | 7.6K → **11.6K** |
| ch583 | 0x1000 → 0x100 | 前移 3.8K | 同步 +3.8K |

由此把 ch572 示例从"3 个 192 字栈任务 + 5.5K 堆"那种 12K 下的妥协,恢复成
**5 个任务用内核默认 256 字栈(1K)+ Queue 演示 + 9.5K 堆**——实测账:
5×1.19K + 软件定时器 1.16K + idle 1.16K ≈ 8.3K,余量 ~1.4K(堆顶 0x200027B0,
距中断栈基 0x20002E00 还有 ~1.6K)。

## 验证

- `bash ci/gate.sh` 全绿:host 159 / ISR 向量 / 启动头 ×3 / 乒乓 A×200 B×200 /
  kernel_tests 24-24 ×3 / **qemu_smp 9/9**——最后一项专门证明多核口未受影响
  (`MAX_HARTS` 在 qemu_riscv 仍是 16)。
- 14 口 `cargo build --lib` 全绿;ch583/ch572 示例构建 + 启动头产物校验 PASS;宿主 82 passed。

Refs #14
把 issue #14 里"只能上板回答"的那批核对点,收敛成**一次烧写就能出答案**的自检例程;
顺带补上 ch57x 家族的最小 BSP(ch583/ch572 的 UART 与 PA 口寄存器同址同偏移,一份够用)。

## BSP(`src/bsp/ch57x/`)

- `uart::configure(clk_hz, baud)` / `putc` / `write_str` + `core::fmt::Write` 出口。
- 寄存器与公式**照官方 EVT 源码**:基址 `0x40003400`(`IER@+1 / FCR@+2 / LCR@+3 /
  LSR@+5(bit6 发送全空) / THR@+8 / R16_DL@+0x0C / R8_DIV@+0x0E`)、初始化序列同
  `UART1_DefInit()`、波特率 `DL = round(clk/(8*baud))`。
- PA 口:`PA_DIR@0x400010A0 / PA_OUT@+08 / PA_CLR@+0C`(LED/示波器打点)。
- 不碰 SAM 解锁/PLL —— 时钟树留给后续(见下"阶段一"为什么先不碰)。

## 自检例程(`examples/board_check_ch57x.rs`)

**阶段一**:按 8/16/24/32/48/60/100 MHz 逐个假设各打一行标记——**哪行可读,复位默认主频
就是那个值**(不配 PLL 时主频未知,只能这样测;这也顺手回答了 env 里的频率假设)。
**阶段二**(把 `CLK_HZ` 改成测出的值后重烧)打印:
- 启动头:`_bootvec` 地址 + **魔数回读**(符号地址即它在 flash 的位置),期望 `F3F9BDA9`;
- `STK_CTLR`(期望 ch583 `0x2F` / ch572 `0x0F`)、`STK_SR`、`PFIC_IENR[0]` bit12;
- **INTSYSCR(自定义 CSR `0x804`)回读**——非 0 说明硬件压栈/嵌套没关,36 字帧前提不成立;
- `mcycle` 前后差(0 = 无 Zicntr;本口 `delay_us` 已改用 SysTick,不依赖它);
- **软中断自检**:`yield_now()` 前后读 `PFIC ISR[0]` bit14——pending 被硬件取走即
  `SWI_IRQn=14` 通路成立,残留则可疑;
- **活性测试**:两个同优先级任务各自周期打印计数器与 `tick()`——两者都涨 =
  时基、上下文切换、同优先级时间片在真机上成立。

## 验证(本机无硬件,能做的都做了)

- 例程在 **ch583(riscv32imac)** 与 **ch572(riscv32imc)** 两种目标下都编译+链接通过,
  启动头产物校验 PASS(三道:ch583-imac/ch583-imc/ch572-imc 里含新增的两个 board_check 构建)。
- `bash ci/gate.sh` 全绿(host 159 / ISR 向量 / 启动头 ×3 / 乒乓 / kernel_tests 24-24 ×3 / smp 9-9);
  门禁新增两条 board_check 构建步骤,防止 BSP 腐烂。
- ⚠️ 例程的**输出**只能在真机上看到——本机没有硬件,故"阶段一测出的主频、阶段二的各项读数"
  仍是待验项(这正是本 PR 的目的:让有板子的人 5 分钟拿到答案)。

Refs #14
第 4 项:**esp32c3 可刷写镜像**——不做手搓格式,而是把"用官方工具把本口 ELF 变成 esp 镜像"
这条正路**验证出来并写进文档**。

## 做法与验证(本机无硬件 → 只能到格式级,这正是本项的边界)

1. 装官方工具:`python -m venv … && pip install esptool` → **esptool 5.4.0**。
2. 用本口的 **imc(真 ISA)产物**跑官方转换:
   `esptool --chip esp32c3 elf2image <target/riscv32imc-.../examples/multitask_esp32c3>`
   → **直接成功**("Creating ESP32-C3 image… Successfully created ESP32-C3 image.",合并 1 个 ELF 段)。
   说明本口 `memory.x` 的映射(FLASH `0x42000000` IROM / RAM `0x3FC88000` DRAM)正是 C3 期望的形态。
3. 用官方解析器**复核产物**:`esptool --chip esp32c3 image_info <out.bin>` →
   `Image version 1`、**magic 0xE9**、**3 段**、**entry 0x42000000**、`Chip ID 5 (ESP32-C3)`、
   WP pin disabled、扩展头正常。产物 103,696 B。
4. 两条上板路径写进文档:`(a) direct boot` = 把该镜像直接烧到 flash `0x0`(ROM 读 0x0 的镜像头跳 entry);
   `(b) 常规` = 配合 esp-idf 的 bootloader + 分区表把 app 烧到 `0x10000`。
   ⚠️ 如实标注:**走 (b) 时 IDF bootloader 还会校验 app 描述符**(`esp_app_desc_t` / `.flash.appdesc` 段),
   本口还没提供——上板前要么补它,要么走 (a)。这条"缺口"是本轮唯一没有闭环的点,已写进
   `src/chip/esp32c3/mod.rs` 的核对清单。

## 改动

- `src/chip/esp32c3/mod.rs` 头注:核对点①由"常规路径本口未做"改成两条路径 + 已做的格式级验证 + (b) 的 app 描述符缺口。
- `README.md` 的 ESP32C3 条目:补刷写配方与验证结论。

## 验证

- 完整 `bash ci/gate.sh` 全绿(见下,与文档一致);esp32c3 按 imc 的构建步骤仍在门禁里。

Refs #14
@gqf2008
gqf2008 merged commit 64a5153 into master Sep 19, 2026
2 checks passed
@gqf2008
gqf2008 deleted the docs/esp32c3-flash-recipe branch September 19, 2026 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant