A2:HAL 接口(i2c/gpio/pwm/time)+ sim 与 ESP 两套实现
接口在 components/phonerail_hal/include/,宿主机链 sim/、ESP32-S3 链 esp/ (IDF v5.4 新版 i2c_master / gpio / LEDC / esp_timer)。 sim 提供 A3 起要用的假板子控制面:假 I²C 器件(寄存器表 + 大端 + 指针自增)、 可注入 NAK / 器件失联、GPIO 外部驱动与写计数、虚拟时钟。 组件名不叫 hal —— ESP-IDF 自己有 components/hal(driver 依赖它),同名会盖掉。 验收:bash host/test.sh → 3 条 ctest 全过;build_idf.ps1 → 编过且零警告。 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QYuExfgyYa6DzRRcUso8M8
这个提交包含在:
+36
-33
@@ -1,50 +1,53 @@
|
||||
# 交接
|
||||
更新:2026-09-06 完成任务包 **A1**(工程骨架)
|
||||
更新:2026-09-06 完成任务包 **A2**(HAL 接口 + sim 实现)
|
||||
|
||||
## 一句话现状
|
||||
`firmware/` 骨架立起来了:同一份 `main/` 源码在**宿主机(cygwin gcc + CTest + Unity)**
|
||||
和 **ESP-IDF v5.4 / esp32s3** 两个目标下都编得过,两条验收命令都是绿的。
|
||||
四路 HAL(i2c / gpio / pwm / time)的接口定死了,两套实现都在:
|
||||
宿主机链 `sim/`(假 I²C 器件 + 虚拟时钟 + 故障注入),ESP32-S3 链 `esp/`(IDF v5.4 新版
|
||||
`i2c_master` / gpio / LEDC / esp_timer)。3 条 ctest(16 个用例)全绿,`idf.py build` 零警告。
|
||||
|
||||
## 下一步
|
||||
**A2**:HAL 接口(i2c / gpio / pwm / time)+ `sim` 实现。
|
||||
新增的 `.c` 要**同时**登记到 `main/CMakeLists.txt` 的 `SRCS` 和
|
||||
`host/CMakeLists.txt` 的 `PHONERAIL_CORE_SRCS`(两处,漏一处就是「宿主机绿了但上板编不过」)。
|
||||
**A3**:INA226 驱动 + 六片地址表(`0x40/41/44/45/42/43`,设计文档 §8.2)。
|
||||
驱动只准通过 `hal_i2c_*` 访问总线;测试用 `sim_i2c_add(addr, 2)` 挂假器件、
|
||||
`sim_i2c_set_reg()` 预置值。**16 位寄存器是大端**,sim 已按大端实现。
|
||||
|
||||
## 本次新增/修改的文件
|
||||
- `CMakeLists.txt`、`sdkconfig.defaults` — IDF 工程根,目标 esp32s3 / 8 MB flash
|
||||
- `main/phonerail.h`、`main/version.c` — 版本号与通道数,两个目标共享
|
||||
- `main/app_main.c` — ESP 专用入口(宿主机构建**不含**此文件)
|
||||
- `main/CMakeLists.txt` — IDF main 组件
|
||||
- `host/CMakeLists.txt` — 宿主机根工程:`phonerail_core` + `unity` + `test/test_*.c` 自动成 ctest
|
||||
- `host/test.sh` — 宿主机验收一条命令
|
||||
- `build_idf.ps1` — 目标验收一条命令(钉死 v5.4、关 ccache)
|
||||
- `test/test_version.c` — A1 的假测试(A2 起有真逻辑后可删)
|
||||
- `third_party/unity/` — 从 IDF v5.4 原样复制的 Unity(上板测试同一套框架)
|
||||
- `../固件开发计划.md` §10 — 钉死了 IDF 版本与测试框架两个待定项
|
||||
- `components/phonerail_hal/include/hal_{err,i2c,gpio,pwm,time}.h` — 接口(唯一的对外契约)
|
||||
- `components/phonerail_hal/hal_err.c` — 两个目标共用的错误码字符串
|
||||
- `components/phonerail_hal/esp/hal_{i2c,gpio,pwm,time}_esp.c` — ESP-IDF 实现
|
||||
- `components/phonerail_hal/sim/sim_hal.h` — **假板子的控制面**(应用代码不许包含)
|
||||
- `components/phonerail_hal/sim/{sim_hal,hal_i2c_sim,hal_gpio_sim,hal_pwm_sim,hal_time_sim}.c`
|
||||
- `components/phonerail_hal/CMakeLists.txt` — IDF 组件(只收 `esp/`,不收 `sim/`)
|
||||
- `test/test_hal_i2c_sim.c`、`test/test_hal_sim.c` — 本包的测试
|
||||
- `host/CMakeLists.txt` — 加 `PHONERAIL_HAL_SIM_SRCS` 与两个 include 目录
|
||||
- `main/CMakeLists.txt` — `REQUIRES phonerail_hal`;`main/app_main.c` 调一次 HAL 保证链接
|
||||
- `../固件开发计划.md` §4.1 — 记下组件重名那个坑
|
||||
|
||||
## 验收命令与结果
|
||||
```
|
||||
$ bash host/test.sh
|
||||
100% tests passed, 0 tests failed out of 1
|
||||
100% tests passed, 0 tests failed out of 3 # test_hal_i2c_sim / test_hal_sim / test_version
|
||||
|
||||
$ .\build_idf.ps1 # PowerShell
|
||||
phonerail.bin binary size 0x32520 bytes. ... 0xcdae0 bytes (80%) free.
|
||||
phonerail.bin binary size 0x32550 bytes. ... 0xcdab0 bytes (80%) free.
|
||||
Project build complete.
|
||||
```
|
||||
|
||||
## 踩到的坑(只写会再犯的)
|
||||
- **宿主机必须用 cygwin 那套 cmake/ctest/gcc**(`/c/cygwin64/bin/`)。
|
||||
Windows 版 CMake(`C:\Program Files\CMake`)配 cygwin gcc 会认错平台。
|
||||
- **cygwin cmake 只认 `/cygdrive/...`**:喂它 `D:/...` 会报
|
||||
`Found relative path while evaluating include directories`。
|
||||
所以 `host/test.sh` 先 `cd` 再全用相对路径,不传绝对路径。
|
||||
同理 `-DCMAKE_C_COMPILER=/c/...` 会被 Git Bash 的路径转换搞坏,改用 `export CC=gcc`。
|
||||
- **`IDF_CCACHE_ENABLE=0`**:开着 ccache 时 IDF 自带的 `esp_lcd_panel_rgb.c`
|
||||
编出过一次编译器 segfault(ICE),关掉就过。已写进 `build_idf.ps1`。
|
||||
- **PowerShell 5.1 + `$ErrorActionPreference="Stop"` 会把 `export.ps1` 的正常 stderr
|
||||
当成终止错误**("Activating ESP-IDF 5.4" 就报红)。`build_idf.ps1` 已去掉它,改用 `exit $LASTEXITCODE`。
|
||||
- 机器上有四个 IDF(v5.3.1 / **v5.4** / v5.5 / v5.5.1 / v6.0-rc1)。
|
||||
PATH 上的是 `D:\Users\35138\esp\v5.4`,本工程就钉这个。
|
||||
- **git 仓库已建**(`D:\DCDC`,分支 `main`,初始提交 `7a85df9`)。
|
||||
`.gitattributes` 默认 `* -text`(不重写行尾),只有 `*.sh` 强制 LF。
|
||||
`build/`、`host/build/`、`sdkconfig` 已被忽略,别硬 `git add -f` 进去。
|
||||
- **组件名不能叫 `hal`**:ESP-IDF 自己有 `components/hal`(`driver` 依赖它),
|
||||
工程里同名会把它盖掉。所以叫 `phonerail_hal`。头文件名 `hal_*.h` 不冲突。
|
||||
- **新增 HAL 实现要改两处 CMake**:`components/phonerail_hal/CMakeLists.txt`(esp 那份)
|
||||
和 `host/CMakeLists.txt` 的 `PHONERAIL_HAL_SIM_SRCS`(sim 那份)。漏一处 =
|
||||
「宿主机绿了但上板编不过」,反之亦然。`main/` 里的 .c 仍是老规矩的另外两处。
|
||||
- **IDF 组件的 `SRCS` 是显式列举**,所以 `sim/` 放在组件目录里也不会被 IDF 编到。
|
||||
|
||||
## HAL 的几条约定(写驱动前看一眼,省得回头改)
|
||||
- 16 位 I²C 寄存器一律**大端**;写事务的第一个字节是寄存器指针,指针**跨事务保持**并自增。
|
||||
- 读写长度不是 `reg_width` 整数倍 → `HAL_ERR_ARG`(真器件上是未定义行为,不许悄悄凑合)。
|
||||
- 器件不在 / `present=false` / 注入 NAK → `HAL_ERR_NAK`;**没 `hal_i2c_init()` 就用 → `HAL_ERR_STATE`**。
|
||||
- **写一个没配成输出的 GPIO 返回 `HAL_ERR_ARG`**(板子上 `gpio_set_level()` 是静默无效的)。
|
||||
`HAL_GPIO_INPUT_PULLUP` 配完默认读回 **1** —— 五路 FLT/PG 是开漏 + 上拉,默认 0 会被当成一直有故障。
|
||||
- PWM 占空比单位是**千分比 0~1000**,应用层不需要知道 LEDC 是几位。
|
||||
- 时刻比较一律用 `hal_time_elapsed_ms()`,不要写 `now - then > x`(32 位毫秒 49.7 天回绕)。
|
||||
- sim 的时钟是虚拟的:`hal_time_delay_ms()` 只把时间往前拨,测试零耗时。
|
||||
每个测试 `setUp()` 里调 `sim_hal_reset()`。
|
||||
|
||||
在新工单中引用
屏蔽一个用户