# NTC 电池温度保护
本版为 ATS3089P 开发板增加充电和放电温度保护,开机自动运行,无需启动命令。
主控通过 GPIO20/J3 的 NTC 电路测温,外置 CW6305 负责执行停止、恢复充电。
## 默认保护规则
| 状态 | 条件 | 动作 |
| --- | --- | --- |
| 充电供电状态 | 温度 ≤ 0℃ | 停止充电 |
| 充电供电状态 | 温度 ≥ 45℃ | 停止充电 |
| 已因温度停止充电 | 温度恢复到 3~42℃,含端点 | 允许恢复原充电电流 |
| 放电状态 | 温度 < -14℃ 或 > 60℃ | 发送正常关机事件 |
| 充电供电状态 | NTC 开路、短路或 ADC 采样失败 | 停止充电 |
| 放电状态 | NTC 开路、短路或 ADC 采样失败 | 发送正常关机事件 |
保护和恢复默认要求 **连续 5 次**满足相应条件,采样间隔约 1 秒,确认过程约 5 秒。
中间出现正常值会重新累计异常次数;中间出现异常值会重新累计恢复次数。
截图中的“保持 30 min”是温箱验收时的稳定测试条件,不表示软件等待 30 分钟才保护。
开机后先禁止充电,连续取得 5 次有效且处于 3~42℃的读数后,才允许充电。
温度处于 0~3℃或 42~45℃之间时保持已有充电保护状态,避免在边界反复启停。
供电状态发生变化时重新确认,不沿用切换前累计的次数。
**放电默认值 -14℃、60℃是根据已有 SDK 温度曲线两端推定的可配置值,
不是原工程已有的放电保护标准。** 产品实际要求不同,应修改下面的配置。
放电保护关机后不会自动开机;温度恢复后由用户重新启动设备。
## 接线与采样原理
用户已确认 NTC 两处均已连接:主控 GPIO20/J3 接口和 CW6305 的 BAT_NTC 接口。
本版以主控采样值作为软件保护依据,CW6305 的硬件 NTC 功能仍保持原配置
`NTC_Func_Enable=NO`,不额外启用其 NTC 上拉。
两处连接的实物电路仍会影响 ADC 值,调试时应核对外部上拉、NTC 阻值和参考电压。
| 信号 | 当前用途 |
| --- | --- |
| GPIO20 / J3 第 1 脚 | NTC 分压采样,LRADC2,PMU ADC 通道 7 |
| J3 第 2 脚 | GND |
| GPIO23 | 同一 LRADC2 的参考电压采样,分时切换 |
| PMUADCDIG_CTL bit 5 | 打开/关闭 GPIO20 的内部 100K 上拉 |
| CW6305 | 通过 I2C 控制充电使能,读取输入供电状态 |
GPIO21 保留给显示屏供电控制,NTC 采样不占用该引脚。开启 NTC 后 UART1 已关闭,
显示驱动继续负责 GPIO21 的上电、关闭,以及休眠后的供电恢复。
2026-10-13 修正版恢复了 GPIO21 的屏幕供电配置。此前 NTC 版本误将该配置禁用,
可能出现界面日志正常刷新但屏幕没有显示的情况;本次只修复此处显示供电配置。
**GPIO23 必须按原图“悬空参考采样”方式使用,不能带 ETA7027 EN 或其 1M 下拉负载。**
如果实际板上已装这部分电路,需要先断开相应负载,或重新设计并标定参考采样方案。
不能同时把 GPIO23 当电源开关输出和本版的参考采样输入。
一次测量按以下顺序执行:
1. GPIO20 切换为 NTC 输入,GPIO23 保持高阻;打开内部 100K 上拉,等待约 50 ms 后读 ADC。
2. 关闭内部上拉,将 GPIO20 置高阻;GPIO23 切换为参考采样,等待约 5 ms 后读 ADC。
3. 计算 `scale = NTC_ADC × 1000 / REF_ADC`,抵消上拉电源变化造成的部分误差。
4. 根据 SDK 曲线计算近似温度,交给保护状态机。
5. 无论采样成功还是失败,最终关闭内部上拉,并将 GPIO20、GPIO23 都恢复高阻。
本版占用 GPIO20,原 GPIO20/21 的 UART1 测试和开机 `hello word` 输出停用。
`app gpio_uart on`、写入和回环接口会返回 `-EBUSY`,避免重新占用 NTC 引脚。
原 UART0 控制台和 USB CDC 命令方式继续使用;USB CDC 的开启方法见
[USB_SERIAL.md](USB_SERIAL.md)。
## SDK 曲线与温度精度
用户选择使用已有参数,因此本版沿用
`battery_leopard_internal/bat_charge_private.h` 中 `BAT_NTC_RANGE_0..4` 的归一化边界:
| scale(NTC_ADC / REF_ADC × 1000) | 近似温度 |
| --- | --- |
| 183 | 60℃ |
| 234 | 52℃ |
| 318 | 42℃ |
| 633 | 14℃ |
| 788 | 0℃ |
| 895 | -14℃ |
相邻点之间使用分段线性插值。超过表格上下端时,使用端点相邻线段外推,
仅用于识别温度越界,不把外推值当作可靠的温度测量结果。
`scale ≤ 20`、`scale ≥ 980` 或参考 ADC 值过低会判为无效读数,
避免开路、短路或参考电路异常被误认为正常温度。
这些参数来自 SDK 的区域边界,**不是当前实物 NTC 的完整 R-T 曲线**。
当前没有确认 NTC 物料型号、R25 和 B 值,也没有套用 B3950 等额外假设。
`temperature_decic` 表示近似温度,单位为 0.1℃;有一位小数不等于具有 0.1℃的测量精度。
本版不能据此宣称满足截图中的 ±2℃要求,必须用实际电池 NTC 和板上电路做温箱标定。
如需提高精度,可把 `ntc_policy.c` 的曲线替换为实际物料数据或实测标定点。
应重点校准 0℃、3℃、42℃、45℃以及实际放电保护点,并保留上拉电源参考采样。
## 停止和恢复充电的实现
充电供电状态根据 **CW6305 当前输入电源**判断:读取状态寄存器 `0x0E` 的 PG 位。
不使用 USB CDC 是否连接,也不使用主控 PMU 的 DC5V 电平替代外置充电芯片状态。
停止充电后芯片可能报告 DISCHARGE/NORMAL,仍按输入电源存在执行充电恢复规则。
读取供电状态失败时保持禁止充电,不把未知状态当作有效放电状态。
温度异常时清除 CW6305 `CHG_EN`,使充电停止,效果相当于充电电流为 0。
**不把 CC 电流配置写成 0**:该芯片电流配置编码 `0x00` 对应 10 mA,并非 0 mA。
停止期间保存正常充电请求和原有电流配置,恢复时使用原配置。
温度保护拦截所有充电开启路径,包括插入电源后的延迟开启、正常充电、
测量真实电池电压后的恢复、满电后的再充电以及低电量 mini charge。
原始寄存器调试写入同样不能在温度禁止期间重新打开 `CHG_EN`。
温度恢复只是解除温度限制。满电、正在测压、无电池、无输入电源以及其他原有
充电状态条件仍会阻止启动,避免温度恢复直接绕过原充电管理。
I2C 写入或读回失败会记录错误并在后续监测中重试;硬件执行成功须以寄存器读回
及实际充电电流验证为准。
放电保护通过电池事件发送给 main,在主线程再次确认保护状态和当前 PG 后,
进入原有正常关机流程,完成应用退出、参数保存和电源关闭。
## 调度与待机功耗
NTC 使用独立 workqueue,栈 1536 字节、优先级 4,避免被原 mini charge 中的
约 10 秒等待阻塞。CW6305 的中断处理也使用独立 workqueue,栈 1536 字节、
优先级 8,避免共用默认队列导致供电状态更新滞后。
监测期间持续持有 `PARTIAL_WAKE_LOCK`,防止进入 S3 后普通采样任务暂停。
它允许屏幕关闭,但 CPU 保持普通运行,因此会增加待机功耗。
正常关机、重启退出监测时取消任务并释放锁。
本版优先保证持续温度监测;后续如需低功耗运行,可增加 T1 定期唤醒采样方案。
## 查看日志
在 UART0 或已开启的 USB CDC shell 执行:
```text
app ntc status
```
命令和周期日志会直接显示摄氏温度,例如:
```text
ntc: temp=27.6 C temp_decic=276 valid=1 adc=7226 ref=15006 scale=481 dc5v=0 block=1 bad=0 poweroff=0
```
`temp=27.6 C` 表示约 27.6℃,负温度会显示为 `temp=-0.5 C` 等格式。
无效采样显示 `temp=invalid`,不能用此时的 `temp_decic` 判断实际温度。
| 字段 | 含义 |
| --- | --- |
| `temp` | 摄氏温度,直接显示小数和 C 单位;采样无效时显示 invalid |
| `temp_decic` | 近似温度,0.1℃,例如 250 表示约 25℃ |
| `valid` | 1 表示本次温度采样有效;0 时不要使用温度字段判断实际温度 |
| `adc` / `ref` | NTC 和参考的原始 ADC 值 |
| `scale` | NTC/参考的归一化比例,乘以 1000 |
| `dc5v` | CW6305 输入供电状态,0 无输入、1 有输入;其他值为未知/读取失败 |
| `block` | 1 表示温度充电禁止门已设置,不等于已经实测到 0 mA |
| `bad` | 连续异常样本次数 |
| `poweroff` | 1 表示已满足放电保护关机条件 |
主要动作日志:
```text
[ntc] CHARGE_STOP
[ntc] CHARGE_RESUME_ALLOWED
[ntc] DISCHARGE_PROTECT: shutdown
```
前两条充电日志表示软件保护状态变化,正常采样日志还会显示温度、ADC、比例和供电。
本版只提供状态查询,不提供绕过保护的强制充电或伪造温度命令。
## 修改保护阈值
配置位于 `zephyr/drivers/power_supply/Kconfig`,可以在应用配置中覆盖。
温度配置单位均为 **0.1℃**:
```text
CONFIG_BATTERY_NTC_PROTECTION=y
CONFIG_BATTERY_NTC_CHARGE_LOW_STOP=0
CONFIG_BATTERY_NTC_CHARGE_LOW_RESUME=30
CONFIG_BATTERY_NTC_CHARGE_HIGH_RESUME=420
CONFIG_BATTERY_NTC_CHARGE_HIGH_STOP=450
CONFIG_BATTERY_NTC_DISCHARGE_LOW=-140
CONFIG_BATTERY_NTC_DISCHARGE_HIGH=600
CONFIG_BATTERY_NTC_CONFIRM_SAMPLES=5
```
必须保持低温停止 < 低温恢复 < 高温恢复 < 高温停止,放电下限 < 放电上限。
修改配置或曲线后需要重新编译和打包。
## 实板验证方法
本次完整固件编译及打包已通过,51 项自动化场景全部通过:温度曲线与保护策略
21 项、ADC/监控与错误处理 12 项、真实固件 ELF 中的 CW6305 驱动 18 项。
执行方法见 [测试说明](tests/ntc/README.md)。尚未进行温箱与实际充电电流验证。
软件模拟测试用于验证状态机和充电控制,实际温度精度、接线及充电电流需要以下实板验证:
1. 检查 NTC、GPIO20/J3 和参考 GPIO23 的实物接线;断开 GPIO20/21 上的 UART1 工具。
2. 在常温执行 `app ntc status`,确认 `valid=1`,ADC/参考/比例稳定,温度与外部温度计接近。
3. 用电阻箱替代主控采样支路的 NTC,验证边界和开路/短路动作。若两个接口接同一支路,
不要在未断开原 NTC 时并联电阻箱;按实际电路连接,避免改变等效阻值。
4. 有充电输入时降到 0℃或升到 45℃,确认连续异常后停止充电,并测量充电电流。
分别升到 3℃、降到 42℃,确认连续正常后恢复原电流。
5. 拔掉充电输入,在实际放电上下限外确认正常关机;温度恢复后手动重新开机。
6. 在低电量 mini charge、正常充电、满电、测压和电源插拔场景重复验证,确认没有提前恢复。
7. 使用温箱在截图规定的温度条件下保持 30 分钟,记录外部温度、ADC、保护动作和实测电流;
根据测量结果调整曲线,验证所需的 ±2℃范围。
## 源码与固件包
| 文件 | 作用 |
| --- | --- |
| `zephyr/drivers/power_supply/battery_ntc/ntc_protection.c` | ADC 采样、参考归一、独立队列、休眠锁和关机通知 |
| `zephyr/drivers/power_supply/battery_ntc/ntc_policy.c` | SDK 温度曲线、充放电阈值、滞回和连续样本确认 |
| `zephyr/drivers/power_supply/battery_leopard_external/bat_charge_cw6305.c` | PG 读取、充电门控、寄存器保护和充电控制 |
| `application/bt_watch/src/main/system_app_main.c` | 开机启动和主线程放电保护关机 |
| `application/bt_watch/src/main/system_app_shell.c` | `app ntc status` |
| `zephyr/boards/arm/ats3089p_dev_watch/board.c` | GPIO20/23 分时复用 |
在仓库的 `zephyr` 目录先编译,再打包:
```powershell
ninja -C ..\application\bt_watch\outdir\ats3089p_dev_watch
python build.py -n -p -b ats3089p_dev_watch -a bt_watch
```
本次固件位于 `application/bt_watch/outdir/ats3089p_dev_watch/_firmware/`:
- `ats3089p_dev_watch_261013_ntc_temp_log.fw`
- `ats3089p_dev_watch_261013_ntc_temp_log_debug.fw`
此版本包含 GPIO21 屏幕供电修复,并增加温度的直接显示;温度换算、保护阈值和动作不变。
烧录后应先通过常温状态、输入电源 PG 和 ADC 读数核对板级连接,再进行温度边界测试。