就绪屏障与配置引擎重构,新增串口助手、V0.0网表分析报告及芯片手册,同步更新文档
This commit is contained in:
@@ -1,185 +1,99 @@
|
|||||||
# STM32F4-Base
|
# STM32F4-Base
|
||||||
|
|
||||||
> **编译验证:所有代码修改后必须执行 `@build` 验证编译通过(0 错误 0 警告),否则不要提交。**
|
STM32F407ZGTx @168MHz(HSE 8MHz → PLL M=4/N=168/P=2);**仅 Keil MDK-ARM v5 (ARMCC, C99) 工具链**;FreeRTOS V10.3.1 / CMSIS-RTOS2;192KB SRAM / 1MB Flash。
|
||||||
|
|
||||||
## 构建
|
**任何代码修改后必须先 `@build` 验证(0 错误 0 警告)再提交;硬件闭环用 `@test`。**
|
||||||
|
|
||||||
- **仅支持 Keil MDK-ARM v5 (ARMCC)**,无其他工具链
|
## 铁律:源码编辑与编码
|
||||||
- 命令行编译:`@build`(执行 `MDK-ARM/build.bat`,从仓库根目录用**相对路径**调用)
|
|
||||||
- `build.bat` 硬编码 Keil 路径 `C:\Keil_v5\UV4\UV4.exe`(本机已验证存在;换机器需改)
|
|
||||||
- 退出码:0 = 0 错误 0 警告 | 1 = 有警告或错误(查看 `MDK-ARM/build_log.txt`)
|
|
||||||
- ⚠️ **旧绝对路径陷阱**:仓库曾位于 `D:\Code\DTU 程序\STM32F4-Base`,`.opencode/command/*.md` 与 `test/run_boot_test.ps1` 中若出现该路径一律视为失效,改用仓库相对路径(如 `& "MDK-ARM\build.bat"`)
|
|
||||||
|
|
||||||
## Python 环境(跑脚本用)
|
- 改代码**只用 Edit 工具**(精确子串替换);批量替换用 Edit 的 replaceAll。**绝不用 `Get-Content`/`Set-Content`/`cmd` 重写含中文的文件**——整文件重写会按系统默认编码重解码 → `U+FFFD` 乱码且不可逆
|
||||||
|
- **字符串字面量必须纯 ASCII**(2026-09-15 实测):本机 ARMCC 对**无 BOM** 源文件按 CP936 解读,字符串内含**奇数个**汉字时末尾高字节吞掉结束引号 → 编译错(偶数个汉字侥幸通过);中文只写注释(注释不参与解析)。带 BOM 的 UI 系文件(`Drivers/BSP/UI/*`、`App/task/ui_task.c`、`Lib/lv_conf.h`)经 BOM 按 UTF-8 解码,不受此条限制
|
||||||
|
- 确需脚本级重写:工程源码为 UTF-8(多数文件无 BOM,UI 系带 BOM),按原样同编码回写、保持 BOM 状态;拿不准就别碰
|
||||||
|
- 发现乱码:先统计 `EF BF BD` 字节数确认真损坏(勿信终端/Read 渲染);**不要急著 `git checkout`**(会丢弃全部未提交工作)——先用 Edit 只修坏行
|
||||||
|
|
||||||
- **统一入口:仓库内 `.venv\Scripts\python.exe`**(Python 3.12.4,fontTools + Pillow 已装),所有依赖第三方库的脚本一律用它;依赖清单 `requirements.txt`(仓库根目录)
|
## 构建与验证
|
||||||
- 重建/换机:`& 'C:\ProgramData\anaconda3\python.exe' -m venv .venv; & '.venv\Scripts\python.exe' -m pip install -r requirements.txt`(种子解释器可用任意带 venv 的 python ≥3.10;`.venv/` 已 gitignore,不入库)
|
|
||||||
- `requirements.txt` 必须**纯 ASCII**:Windows 下 pip 按系统代码页(GBK)解码该文件,中文注释会 UnicodeDecodeError(2026-09-09 实测)
|
|
||||||
- PATH 默认 `python` 是 msys64 的(`C:\msys64\ucrt64\bin\python.exe`),**不要用它**跑依赖第三方库的脚本;纯标准库脚本(回归测试、`extract_cn.py`、`gen_menu.py`)任意 python3 均可
|
|
||||||
- 字体生成:`& '.venv\Scripts\python.exe' tools/font_gen/make_font.py`
|
|
||||||
|
|
||||||
## 硬件
|
- `@build` = `& "MDK-ARM\build.bat"`(仓库根目录用**相对路径**);退出码 0 = 0 错误 0 警告,1 = 有警告或错误(查 `MDK-ARM/build_log.txt`);`build.bat` 硬编码本机 Keil 路径 `C:\Keil_v5\UV4\UV4.exe`(换机需改)
|
||||||
|
- `@test` / `test/run_boot_test.ps1` 一键闭环:开串口+清日志 → 烧录(`MDK-ARM/download.bat`,下载后 Reset&Run)→ wait-idle(等 RX 静默 8s,超时 30s)→ `test/verify_log.ps1` 标记校验;退出码 0=PASS / 1=FAIL / 2=采集或烧录错误 / 3=用法/预检错误
|
||||||
|
- 默认校验标记:Required `App init OK` / `Network Init` / `net init: OK`;Forbidden `FAIL` / `ERROR` / `HardFault`;按模块定制标记(网络/存储/RTC/ADC/RS485/UI)见 `docs/测试说明/自动化测试流程.md`
|
||||||
|
- ⚠️ 旧绝对路径 `D:\Code\DTU 程序\...` 出现即失效(仓库已搬迁),一律改用仓库相对路径
|
||||||
|
|
||||||
|
## Python 环境
|
||||||
|
|
||||||
|
- 统一入口 `& '.venv\Scripts\python.exe'`(3.12,fontTools/Pillow 已装);PATH 默认 `python` 是 msys64 的,**不要用它**跑依赖第三方库的脚本;纯标准库脚本任意 python3 均可
|
||||||
|
- 重建/换机:`& 'C:\ProgramData\anaconda3\python.exe' -m venv .venv` + `pip install -r requirements.txt`(`.venv/` 已 gitignore)
|
||||||
|
- `requirements.txt` 必须**纯 ASCII**(Windows 下 pip 按 GBK 代码页解码,中文注释会 UnicodeDecodeError)
|
||||||
|
|
||||||
|
## 提交门禁(pre-commit)
|
||||||
|
|
||||||
|
- 任一失败即拦截:cppcheck(warning/performance/portability/style)+ C 代码规范机械检查 + U+FFFD 乱码检查 + gitlint;范围仅项目代码(第三方 `Lib/`/`Middlewares/`/CMSIS/HAL/`lftpd`/`dhara`/`MDK-ARM`/`test/` 排除;规范检查另排除 CubeMX 生成的 `Src/`/`Inc/`)
|
||||||
|
- 提交信息:**单行中文标题 <100 字符**(gitlint),UTF-8 无 BOM + `git commit -F <文件>`(防终端转码破坏)
|
||||||
|
- 代码规范 V1.0:小写下划线命名(`g_`/`s_`/`p_`/`a_` 前缀)、头文件保护宏 `XXX_H`、常量在右、文件头模块注释块 → `docs/代码规范/`
|
||||||
|
- 全库扫描 `pre-commit run --all-files`;详见 `docs/代码规范/pre-commit使用说明.md`
|
||||||
|
|
||||||
|
## 平台约束
|
||||||
|
|
||||||
|
- `Inc/`/`Src/` 中 CubeMX 生成文件带 `USER CODE BEGIN/END` 标记:自定义代码**只写标记区之间**;`Drivers/BSP/` 为纯手工代码
|
||||||
|
- FreeRTOS V10.3.1(CMSIS-RTOS V2);HAL 时基 = TIM7(非 SysTick),tick = 1ms;NVIC 4 位优先级分组,外设中断优先级 ≥ 5
|
||||||
|
- CH395F SPI:每次事务须 `ch395f_spi_begin()/end()` 包裹;分频系数**必须为 8**(PCB 约束,勿"优化")
|
||||||
|
- **内存预算紧张**:新增任何任务/缓冲/栈前必须先核算 RAM 余量(`docs/内存管理/`、`待处理内容.md`)
|
||||||
|
|
||||||
|
| Task | 栈 (words) | 优先级 |
|
||||||
|
|---|---|---|
|
||||||
|
| defaultTask | 512 | Normal |
|
||||||
|
| netTask | 1024 | Normal |
|
||||||
|
| ftpTask | 1024 | Normal |
|
||||||
|
| testTask | 1024 | BelowNormal |
|
||||||
|
| uiTask | 4096 | BelowNormal |
|
||||||
|
| timeSyncTask | 512 | Normal |
|
||||||
|
|
||||||
|
(实际值以 `Src/freertos.c` 为准,六任务栈合计 32KB;改动栈/缓冲前先核对此表与实测)
|
||||||
|
|
||||||
|
## 架构要点
|
||||||
|
|
||||||
|
`Src/main.c`(CubeMX 初始化)→ `app_main_init` → `osKernelStart` → 6 任务
|
||||||
|
|
||||||
|
- `app_main_init`(时间子系统优先,使后续日志带时间戳):`sd2506_init` → `sys_clock_init`(墙钟;RTC 故障时降级默认时间基准并返回 -1 触发"时钟芯片异常"自检;`sys_clock_get` 每 30 天惰性再基准化防 49.7 天 tick 回绕)→ `rs485_init` → `gd5f2gq5ue_init` → `tpafe5160_init` → SD2506 诊断 → `tpafe5160_start_conv_irq`
|
||||||
|
- **就绪屏障**(`App/sys_events.h` Event Flags,取代魔法延时):`SYS_EVT_NET_READY`(netTask 置位)/ `STORAGE_READY`(defaultTask:卷挂载 + 网络配置加载完成)/ `FTP_READY` / `TIMESYNC_READY`;消费者用 `osEventFlagsWait` 阻塞等待
|
||||||
|
- netTask:`net_stack_bring_up`(配置已由 defaultTask 在屏障前加载,本任务只读 RAM 副本 → `net_init` + PHY 强制 100M 全双工 → 递增网络代次号)→ 置 NET_READY → 循环 `net_poll` + `net_process_messages`;消费 `SYS_EVT_NET_RECONFIG` → 立即重建网络(新 IP 免重启生效,各 TCP 服务据代次号重建监听)
|
||||||
|
- defaultTask:`f_mount` forced(无卷自动 `f_mkfs` FAT32)→ 网络配置加载(`net_cfg_load`,首启含旧档迁移)→ STORAGE_READY → LED 闪烁;同时是 syslog(`/log/run.log`·`selftest.log`,定长 64B 记录)的**唯一写者**与**配置引擎属主**(`cfg_file` 静态态单任务收敛于此:UI 保存请求执行 `net_cfg_save_run` + 2s `cfg_file_poll`,经 `SYS_EVT_CFG_SAVE` 事件唤醒;netTask/uiTask 不得直接触碰配置引擎,见 P1-3)
|
||||||
|
- 全景 `docs/项目架构总览.md`(六层分层 / 启动时序 / 存储·网络·UI 栈 / 目录组织)
|
||||||
|
|
||||||
|
## 硬件引脚
|
||||||
|
|
||||||
| 外设 | 接口 | 引脚 |
|
| 外设 | 接口 | 引脚 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| CH395F 以太网 | SPI2 | PB12 CS, PB13 SCK, PB14 SDO, PB15 SDI |
|
| CH395F 以太网 | SPI2 | PB12 CS, PB13 SCK, PB14 SDO, PB15 SDI |
|
||||||
| GD5F2GQ5UE NAND | SPI1 | PE0 CS, PB3 SCK, PB4 MISO, PB5 MOSI, PB8 WP, PE1 HOLD |
|
| GD5F2GQ5UE NAND | SPI1 | PE0 CS, PB3 SCK, PB4 MISO, PB5 MOSI, PB8 WP, PE1 HOLD |
|
||||||
| TPAFE5160 ADC | 并行16位 | PG0-PG15 数据, PD3 RD, PD4 CONVST, PD7 BUSY |
|
| TPAFE5160 ADC | 并行16位 | PG0-PG15 数据, PD3 RD, PD4 CONVST, PD7 BUSY |
|
||||||
| USART1 | 串口 | PA9 TX, PA10 RX (115200bps) |
|
| USART1 调试串口 | UART | PA9 TX, PA10 RX (115200) |
|
||||||
| RS-485 | UART5 | PC12 TX, PD2 RX, PD0 DE(半双工) |
|
| RS-485 | UART5 | PC12 TX, PD2 RX, PD0 DE(半双工) |
|
||||||
| 6x LED | GPIO | PC4, PC5, PB1, PB2, PF11, PF12(低电平点亮) |
|
| 6x LED | GPIO | PC4, PC5, PB1, PB2, PF11, PF12(低电平点亮) |
|
||||||
|
|
||||||
MCU: STM32F407ZGTx @ 168MHz (HSE 8MHz → PLL M=4/N=168/P=2,见 `*.ioc`/`stm32f4xx_hal_conf.h`)
|
## 模块约定
|
||||||
|
|
||||||
## 架构
|
- **CH395F 单连接 socket**:监听与数据通道复用同一 Socket(CONNECT 后转数据通道,DISCONNECT/TIMEOUT 后重开 → LISTEN);所有 CH395F 中断在 `net_poll()` 内经 `GET_GLOB_INT_STATUS` 集中读取并清除,**不得**在 ISR 或其他地方单独处理
|
||||||
|
- 所有 `net_*` socket 操作经 `netMsgQueue` 消息队列在 netTask 串行执行(线程安全);非 netTask 任务直接调 `net_*` API,勿直接碰 CH395F 驱动
|
||||||
|
- 网口配置:`/config.ini` [network] 段(工厂默认 192.168.1.100/24、gw .1;MAC 全零 = 芯片内置;UI 保存立即生效;旧档 `/cfg/netcfg.bin` 首启自动迁移)→ `docs/网络配置说明.md`
|
||||||
|
- **新 .c 文件必须手动注册到两处**才能双端编译:`MDK-ARM/STM32F407-Demo.uvprojx` + `simulator/CMakeLists.txt`(用 `new-source-file` skill)
|
||||||
|
- 测试构建:`test/test_config.h` 的 `TEST_SUITE_CH395F/STORAGE/GD5F/RTC` **互斥**(一次只能启用一个,`#error`);全部注释 = 产品构建;CH395F 套件 `test/ch395f_test.h`:硬件层 Phase 1~5 与 NET 层 Phase 6~11 互斥;CH395F 硬件层模式下 netTask(基础线程:无条件创建、全构建唯一实例)入口自挂起(不运行),testTask 独占 CH395F
|
||||||
|
- **改驱动前先读对应 `docs/问题记录/*_Trap_Records.md`**(CH395F / GD5F2GQ5UE / SD2506);各模块测试指南见 `docs/测试说明/`
|
||||||
|
|
||||||
```
|
## 串口助手 serial_tool
|
||||||
Src/main.c → CubeMX 外设初始化 → app_main_init → osKernelStart
|
|
||||||
→ [FreeRTOS tasks: defaultTask, netTask, ftpTask, testTask, uiTask, timeSyncTask]
|
|
||||||
```
|
|
||||||
|
|
||||||
- **app_main_init 顺序**(时间子系统优先,使后续日志带时间戳):`sd2506_init` → `sys_clock_init`(墙钟基准)→ `rs485_init` → `gd5f2gq5ue_init` → `tpafe5160_init` → SD2506 诊断 → `tpafe5160_start_conv_irq`
|
- 入口:`& '.venv\Scripts\python.exe' tools/serial_tool/serial_tool.py <命令>`(daemon 自动拉起;全部命令 5s 超时、JSON 输出、exit 0/1/2/3)
|
||||||
- **就绪屏障**(`App/sys_events.h` Event Flags,取代魔法延时/全局轮询):`SYS_EVT_NET_READY`(bit0, netTask 置位) / `SYS_EVT_STORAGE_READY`(bit1, defaultTask 置位) / `SYS_EVT_FTP_READY`(bit2) / `SYS_EVT_TIMESYNC_READY`(bit3);消费者用 `osEventFlagsWait` 阻塞等待
|
- 全量历史 = 日志文件 `tools/serial_tool/state/serial.log`(RX/TX/SYS 时间戳行);agent 直接 Read/Grep 文件,**无采集窗口仪式**;20MB 上限自动截头保尾 10MB
|
||||||
- **defaultTask**:FatFS 挂载(`f_mount` forced,无卷自动 `f_mkfs` FAT32)→ 置 `SYS_EVT_STORAGE_READY` → LED 闪烁循环
|
- 常用:`open`(幂等)/ `send <文本>`(或 `--hex 0D0A`)/ `log --tail N --grep P` / `clear`(代际+1)/ `wait-idle --settle-ms 8000 --max-ms 30000` / `status` / `close`
|
||||||
- **netTask**:等 `SYS_EVT_STORAGE_READY`(≤10s)→ `net_stack_bring_up()`(`net_cfg_load` 读网口配置(`/config.ini` [network] 段,首启自动迁旧档 NCFG)→ `net_init(ip,mask,gw,mac)` + PHY 强制 100M 全双工 + 等链路 ≤3s → 回写芯片实际 MAC 影子 → 递增网络代次号)→ 置 `SYS_EVT_NET_READY` → 循环 `net_poll()` + `net_process_messages()` + `osDelay(1)`(tick=1ms);循环内消费 `SYS_EVT_NET_RECONFIG`(UI 保存网口配置后请求)→ 立即重建网络(新 IP 生效,无需重启;各 TCP 服务据代次号重建监听)
|
- 串口端口单一配置源:`.opencode/serial_config.json`(当前 COM6);端口变化**只改这个文件**
|
||||||
- **ftpTask**:`osEventFlagsWait(NET_READY | STORAGE_READY, WaitAll)` 后 `lftpd_start("/", 21, &ftp)`(已无 7s 魔法延时)
|
- 命令/工作流/故障排查 `docs/测试说明/串口助手使用指南.md`;契约/daemon 行为/陷阱 `docs/测试说明/串口助手设计说明.md`
|
||||||
- **testTask**:测试套件入口(`test/test_config.h` 选择;产品构建下空转)
|
|
||||||
- **uiTask**:等 `SYS_EVT_NET_READY` 后 `ui_port_init` → `ui_menu_init` → 启动 UI net sink
|
|
||||||
- **timeSyncTask**:TCP 墙钟时间同步(PC 推送)
|
|
||||||
- 功能编译开关:`App/app_cfg.h`(`APP_NET_ENABLE` / `APP_ADC_ENABLE` / `APP_RS485_ENABLE`)
|
|
||||||
- **全景架构图**:`docs/项目架构总览.md`(六层分层 / 任务与就绪屏障 / 启动时序 / 存储·网络·UI 栈 / 目录组织)
|
|
||||||
|
|
||||||
### 任务栈
|
|
||||||
|
|
||||||
| Task | 栈大小(words) | 优先级 |
|
|
||||||
|---|---|---|
|
|
||||||
| defaultTask | 2048 | Normal |
|
|
||||||
| netTask | 4096 | Normal |
|
|
||||||
| ftpTask | 4096 | Normal |
|
|
||||||
| testTask | 4096 | BelowNormal |
|
|
||||||
| uiTask | 16384 | BelowNormal |
|
|
||||||
| timeSyncTask | 2048 | Normal |
|
|
||||||
|
|
||||||
## CH395F 设计原则
|
|
||||||
|
|
||||||
- **单连接 socket**:Socket 0 复用监听和数据通道,收到 CONNECT 后切换为数据通道,DISCONNECT/TIMEOUT 后重新 OPEN → LISTEN
|
|
||||||
- **中断统一处理**:所有 CH395F 中断在 `net_poll()` 中通过 `GET_GLOB_INT_STATUS` 集中读取并清除,不得在 ISR 或其他地方单独处理
|
|
||||||
|
|
||||||
## NET 网络层
|
|
||||||
|
|
||||||
- `net_socket.h/c` — BSD Socket API;**单连接模式**(`ch395f_set_fun_para(0x09)`:多 Socket + TCP Server 单连接 + 手动关闭),连接停留在 Socket 0
|
|
||||||
- `net_select.h/c` — select/poll I/O 多路复用
|
|
||||||
- 线程安全通过消息队列(`netMsgQueue`)实现,所有 CH395F 操作在 netTask 中串行处理
|
|
||||||
- `net_init` 顺序:check_exist → reset → `set_fun_para(0x09)` → MSS/重传/KeepAlive → IP → `ch395f_init()` → `ch395f_set_mac_addr()`(mac 非空且非全零时)→ Socket 0~7 缓冲分配 → ping 使能
|
|
||||||
- 网口参数(IP/掩码/网关/MAC)取自通用配置文件 `/config.ini` 的 [network] 段(`Drivers/BSP/NETCFG/` + `App/cfg_file` 引擎:工厂默认 192.168.1.100/24、gw .1,MAC 全零 = 芯片内置),保存后**立即生效**(网络重建)或下次上电生效;旧版 `/cfg/netcfg.bin`(NCFG)首启自动迁移;PHY 强制 100M 全双工
|
|
||||||
- **新文件需手动添加到 Keil MDK 工程**才能编译
|
|
||||||
|
|
||||||
## 测试构建模式
|
|
||||||
|
|
||||||
- `test/test_config.h`:`TEST_SUITE_CH395F` / `TEST_SUITE_STORAGE` / `TEST_SUITE_GD5F` / `TEST_SUITE_RTC` **互斥**(一次构建只能启用一个,`#error`);全部注释 = 正常产品构建
|
|
||||||
- CH395F 套件沿用 `test/ch395f_test.h` 阶段宏:硬件层 Phase 1~5 与 NET 层 Phase 6~11 **互斥**(`#error`);硬件层模式下 netTask 不创建,testTask 独占 CH395F
|
|
||||||
- 各模块测试指南见 `docs/测试说明/`(CH395F / GD5F / SD2506 / FTP)
|
|
||||||
|
|
||||||
## 关键文件
|
|
||||||
|
|
||||||
| 路径 | 说明 |
|
|
||||||
|---|---|
|
|
||||||
| `Src/main.c` | 入口,CubeMX 生成 + USER CODE 区域 |
|
|
||||||
| `Src/freertos.c` | FreeRTOS task 创建,CubeMX 生成 + USER CODE 区域 |
|
|
||||||
| `App/app_main.c` | 应用初始化流程编排 |
|
|
||||||
| `App/sys_events.h` | 系统就绪事件(Event Flags 就绪屏障) |
|
|
||||||
| `App/app_cfg.h` | 功能模块编译开关 |
|
|
||||||
| `App/task/net_task.c` | netTask 主循环(网络初始化 + 轮询) |
|
|
||||||
| `test/test_config.h` | 测试套件选择(互斥开关) |
|
|
||||||
| `Drivers/BSP/NET/` | BSD Socket API 网络抽象层 + lftpd |
|
|
||||||
| `Drivers/BSP/NETCFG/` | 网口配置(通用配置文件 `/config.ini` [network] 段 + 旧档 NCFG 迁移;网口设置内容页数据源) |
|
|
||||||
| `App/cfg_file.*` + `App/cfg_file_store*` | 通用配置文件引擎(双端共享核心 + 平台存储后端:INI 解析/校验/外科保存/模板/沉降轮询) |
|
|
||||||
| `App/log/sys_log.h` + `sys_log_mcu.c` | 运行/自检记录引擎(定长 64B 文本记录,落盘 `/log/run.log`·`selftest.log`,defaultTask 唯一写者;UI 页与 FTP 数据源) |
|
|
||||||
| `Drivers/BSP/CH395F/` | CH395F SPI 驱动 |
|
|
||||||
| `Drivers/BSP/GD5F2GQ5UE/` | NAND Flash 驱动 + dhara FTL + FatFS diskio |
|
|
||||||
| `Drivers/BSP/TPAFE5160/` | ADC 并行接口驱动 |
|
|
||||||
| `Drivers/BSP/SD2506/` | RTC 驱动 |
|
|
||||||
| `Drivers/BSP/RS485/` | RS-485 通信(UART5 + PD0 DE) |
|
|
||||||
| `Drivers/BSP/UI/` | LVGL UI 组件(与 PC 模拟器共用源码) |
|
|
||||||
|
|
||||||
## 驱动关键点
|
|
||||||
|
|
||||||
详见 `docs/` 目录:
|
|
||||||
- `docs/项目架构总览.md` — 六层全景架构(分层/任务/启动时序/存储·网络·UI 栈)
|
|
||||||
- `docs/配置文件设计说明.md` — 通用配置文件(INI `/config.ini`:设计决策 D1–D15 / 双端支持 / 阶段规划 P1–P8 / 测试与风险)
|
|
||||||
- `docs/网络配置说明.md` — 网口设置页配置(UI 可改的 IP/掩码/网关/MAC:持久化 / 立即生效 / 页面操作)
|
|
||||||
- `docs/问题记录/CH395F_Trap_Records.md` — CH395F 已知陷阱
|
|
||||||
- `docs/问题记录/GD5F2GQ5UE_Trap_Records.md` — GD5F2GQ5UE 已知陷阱
|
|
||||||
- `docs/问题记录/SD2506_Trap_Records.md` — SD2506 RTC 已知陷阱
|
|
||||||
- `docs/测试说明/CH395F_Test_Guide.md` — 网络测试说明(含构建模式与执行顺序)
|
|
||||||
|
|
||||||
## 串口调试(Python 串口助手 serial_tool)
|
|
||||||
|
|
||||||
通过仓库内置 **Python 串口助手**(`tools/serial_tool/serial_tool.py`,常驻 daemon + 薄 CLI)自主读取/控制 **USART1 串口**(PA9 TX / PA10 RX,115200bps)的打印流。
|
|
||||||
|
|
||||||
- **统一入口**:`& '.venv\Scripts\python.exe' 'tools/serial_tool/serial_tool.py' <命令> [参数]`(daemon 未运行自动拉起;全部命令带硬超时 5s,JSON 输出,exit 0/1/2/3)
|
|
||||||
- **全量历史 = 日志文件** `tools/serial_tool/state/serial.log`(RX/TX/SYS 时间戳行;Agent 直接 Read/Grep 读文件,无采集窗口仪式);20MB 上限自动截头保尾 10MB
|
|
||||||
- **常用命令**:`ports`(枚举+配置口标注)/ `open`(幂等,不存在/占用 ≤1s 报错)/ `send`(位置参数文本 或 `--hex 0D0A`,`--nl` 加 CRLF)/ `status`(全状态)/ `log --tail N --grep P` / `clear`(代际+1)/ `wait-idle --settle-ms 8000 --max-ms 30000` / `close` / `start|stop|restart` / `selftest`(无头自检)
|
|
||||||
- **串口端口单一配置源:`.opencode/serial_config.json`**(当前本机为 `COM6`)。端口变化只改这个文件。
|
|
||||||
- 命令契约、日志行格式、daemon 行为、已知陷阱详见 **`docs/测试说明/串口助手设计说明.md`**
|
|
||||||
|
|
||||||
## 自动化测试(AI 迭代闭环)
|
|
||||||
|
|
||||||
改完代码后运行 **`@test`** 可自动执行完整闭环:**构建验证 → 开串口 + 清空日志(serial_tool,daemon 常驻,全程不关端口)→ 烧录(`MDK-ARM/download.bat`,下载后 Reset & Run)→ `wait-idle`(等 RX 静默 8s 或超时 30s)→ 提取 `[RX]` 行 → `test/verify_log.ps1` 标记校验 → PASS/FAIL 判定并迭代**。
|
|
||||||
|
|
||||||
- **推荐一键命令**:`test/run_boot_test.ps1` = open → clear → 烧录 → wait-idle → 提取日志 → verify 全流程,退出码 0=PASS / 1=FAIL / 2=采集或烧录错误 / 3=用法/预检错误
|
|
||||||
- 判定标准:`@test` 内部先 `@build`(0 错误 0 警告),再 `@download`(退出码 0),日志用 `verify_log.ps1` 校验(默认 Required:`App init OK`/`Network Init`/`net init: OK`;Forbidden:`FAIL`/`ERROR`/`HardFault`)
|
|
||||||
- daemon 常驻全量日志文件:开串口 + clear 必须在烧录**前**完成(`run_boot_test.ps1` 已保证顺序);旧 serial-mcp-server 的"采集窗口/first-byte/EOF 重试"仪式已整体移除
|
|
||||||
- 每次按模块定制标记(网络/存储/RTC/ADC/RS485)见 `docs/测试说明/自动化测试流程.md`
|
|
||||||
- UI 已有 DBG 打印(`UI port init: OK` / `UI menu init: OK` / `UI net sink: started`),可用 `-Required "UI port init: OK;UI menu init: OK"` 自动回归 UI 初始化;屏幕内容仍需人工目检
|
|
||||||
|
|
||||||
## 代码规范与 pre-commit
|
|
||||||
|
|
||||||
- **提交被 pre-commit 钩子门禁**,任一失败即拦截:cppcheck 静态分析(warning/performance/portability/style)+ 代码规范机械检查 + U+FFFD 乱码检查 + gitlint commit message
|
|
||||||
- 代码规范 V1.0(`docs/代码规范/嵌入式C语言代码规范(V1.0).md`):命名小写下划线(`g_`/`s_`/`p_`/`a_` 前缀)、头文件保护宏 `XXX_H`、常量在右、文件头模块注释块等;可机械校验项由 `scripts/check_coding_standard.py` 强制
|
|
||||||
- 检查范围仅项目自有代码;第三方(`Lib/`、`Middlewares/`、CMSIS/HAL、`lftpd`、`Drivers/BSP/UI`、`test/`)被排除
|
|
||||||
- 新机器启用:`pre-commit install`;全库扫描:`pre-commit run --all-files`
|
|
||||||
- 详见 `docs/代码规范/pre-commit使用说明.md`、`docs/代码规范/cppcheck使用说明.md`
|
|
||||||
|
|
||||||
## LVGL PC 模拟器
|
## LVGL PC 模拟器
|
||||||
|
|
||||||
`simulator/`(CMake + SDL2 2.32.10 预编译库)可在 PC 上开发调试 UI,**与 MCU 端共用 UI 源码**(`Drivers/BSP/UI/ui_menu.c`、`ui_font_cn_12.c`),无需烧录:
|
- `simulator/`(CMake + SDL2 预编译库)与 MCU 端共用 UI 源码(`ui_menu.c`、`ui_font_cn_12.c`),免烧录开发 UI:`cmake -B build -G "Visual Studio 16 2019" -A x64; cmake --build build --config Debug` → 运行 `simulator\build\Debug\lvgl_sim.exe`
|
||||||
|
- 自检:`--cfgtest`(配置闭环)/ `--logtest`(日志引擎)/ `--standby shot.bin`(待机屏截图)/ `--idle <秒>`
|
||||||
|
- UI 改动一律走 **`ui-verify` skill 五步门禁**;含新汉字的 UI 文案提交前先跑 **`font-regen` skill** 重生成中文字体
|
||||||
|
|
||||||
```powershell
|
## 文档与图形
|
||||||
cd simulator
|
|
||||||
cmake -B build -G "Visual Studio 16 2019" -A x64
|
|
||||||
cmake --build build --config Debug
|
|
||||||
# 运行 simulator\build\Debug\lvgl_sim.exe
|
|
||||||
```
|
|
||||||
|
|
||||||
- 详见 `docs/UI 设计/LVGL模拟器部署与使用说明.md`
|
- 配置文件 `docs/配置文件设计说明.md`;墙钟 `docs/系统墙钟时间维护说明.md`;代码规范 `docs/代码规范/`;测试说明 `docs/测试说明/`;审计发现 `docs/项目审计改进清单.md`;已知待办 `待处理内容.md`(内存预算)
|
||||||
- 中文字体:`ui_cn_chars.txt`(字符集)+ `tools/font_gen/` 生成 `Drivers/BSP/UI/ui_font_cn_12.c`,见 `docs/UI 设计/UI_中文字体生成与配置.md`
|
- 图形走 **`draw-diagram` skill**:精确布局图(协议帧/分层/屏障)用 `tools/arch_diagram/gen_*.py` 生成器(产物放 `docs/images/`,脚本与 .svg 一并提交);拓扑图(流程/时序/状态机)用 Mermaid;**勿手绘 ASCII 框图**
|
||||||
- 配置自检:`simulator\build\Debug\lvgl_sim.exe --cfgtest`(无头、进程内闭环:加载/旧档迁移 → 2s 轮询沉降 → 重载断言 + 外科保存无损回环;0=PASS,详见 `simulator/README.md` §3.7)
|
|
||||||
- 日志引擎自检:`lvgl_sim.exe --logtest`(post N 条 → count/get 回读断言 + 宿主文件字节级校验;0=PASS);待机屏截图:`--standby shot.bin`;窗口模式空闲超时覆盖 `--idle <秒>`
|
|
||||||
|
|
||||||
## 图形绘制(文档配图)
|
|
||||||
|
|
||||||
文档里的技术图形统一用 **SVG 生成器**(`tools/arch_diagram/`,纯标准库)或 **Mermaid**,**勿手绘 ASCII 框图**:
|
|
||||||
- **精确布局图**(协议帧 / 分层架构 / 依赖 / 就绪屏障)→ `tools/arch_diagram/gen_*.py`:改脚本顶部数据 → `& '.venv\Scripts\python.exe' tools/arch_diagram/gen_xxx.py` 重新生成 `docs/images/*.svg`(脚本内置 XML 自检)。
|
|
||||||
- **拓扑类图**(流程 / 时序 / 状态机)→ Markdown 内嵌 `mermaid` 代码块。
|
|
||||||
- 全流程 / 选型 / 约定 / 检查清单见 **`docs/图形绘制流程.md`**(已沉淀为 `draw-diagram` skill);产物统一放 **`docs/images/`** 专门目录;脚本与生成的 `.svg` 一并提交。
|
|
||||||
|
|
||||||
## 注意
|
|
||||||
|
|
||||||
- `Inc/` 和 `Src/` 中 CubeMX 生成的文件带有 `USER CODE BEGIN`/`END` 标记,自定义代码写在这些区域之间
|
|
||||||
- `Drivers/BSP/` 下的驱动文件为纯手工代码,不受 CubeMX 保护
|
|
||||||
- CH395F 每次 SPI 事务需用 `ch395f_spi_begin()` / `ch395f_spi_end()` 包裹
|
|
||||||
- CH395F SPI PCB 设计问题,分频系数必须为 8,速度相对较低
|
|
||||||
- FreeRTOS V10.3.1 via CMSIS-RTOS V2,HAL 时基用 TIM7(非 SysTick),tick = 1ms
|
|
||||||
- NVIC 优先级分组 4 位,外设中断优先级 ≥ 5(`configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY`)
|
|
||||||
- **内存预算紧张**:任务栈目前普遍偏大(见 `待处理内容.md`),新增任务/缓冲/栈前必须先核算 RAM 余量
|
|
||||||
|
|
||||||
## 源码编辑与编码安全(铁律)
|
|
||||||
|
|
||||||
本工程源码含大量中文注释,曾因错误的文本重写方式导致整文件乱码(`U+FFFD` 替换符,不可逆)。以下规则必须遵守:
|
|
||||||
|
|
||||||
- **绝不用 `Get-Content` / `Set-Content` / `cmd` 文本重写含中文的源码文件**。这类"整文件重写"会按系统默认编码重新解码再写回,多字节中文必被 `U+FFFD` 替换且不可逆。
|
|
||||||
- **改代码只用 Edit 工具**(精确子串替换,不重新编解码整个文件,安全);批量替换用 Edit 的 `replaceAll`。
|
|
||||||
- 必须脚本级替换时,使用显式且一致的编码(**工程源码为 UTF-8**:多数文件无 BOM,但 UI 相关文件 `Drivers/BSP/UI/*`、`App/task/ui_task.c`、`Lib/lv_conf.h` 为 UTF-8 **带 BOM**——如 Python `open(p, encoding="utf-8"/"utf-8-sig")` 按原样同编码回写,保持 BOM 状态不变)——但**最稳的是别碰**,只用 Edit / git。
|
|
||||||
- **发现乱码先别急着 `git checkout`**:`git checkout` 会丢弃所有未提交工作,使损失扩大。先评估能否用 Edit 仅改坏掉的那几行。
|
|
||||||
- 验证是否真损坏用字节级检查(统计 `EF BF BD` 出现次数),不要依赖终端/Read 渲染判断。
|
|
||||||
|
|||||||
+3
-1
@@ -8,6 +8,7 @@
|
|||||||
* 创建日期:2026-09-14
|
* 创建日期:2026-09-14
|
||||||
* 修改记录:
|
* 修改记录:
|
||||||
* v1.0 2026-09-14 王建锋 创建初始版本(P3:段键表引擎 + net_cfg 集成)
|
* v1.0 2026-09-14 王建锋 创建初始版本(P3:段键表引擎 + net_cfg 集成)
|
||||||
|
* v1.1 2026-09-15 王建锋 属主任务由 netTask 改为 defaultTask(配置引擎单一属主,P1-3)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CFG_FILE_H
|
#ifndef CFG_FILE_H
|
||||||
@@ -103,7 +104,8 @@ int cfg_file_save(void);
|
|||||||
* 函数功能:配置文件变更轮询(沉降去抖 + 重载 + 分段变更回调)
|
* 函数功能:配置文件变更轮询(沉降去抖 + 重载 + 分段变更回调)
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:无
|
* 返回值:无
|
||||||
* 限定条件:由单一任务周期调用(建议 2s,收敛于 netTask)
|
* 限定条件:由配置引擎属主任务周期调用(建议 2s;MCU = defaultTask,
|
||||||
|
* 模拟器 = 主循环);引擎静态状态无跨任务保护,属主唯一即无竞态
|
||||||
* 函数说明:(size, mtime 变更令牌) 相对基线变化且连续 CFG_FILE_SETTLE_CNT
|
* 函数说明:(size, mtime 变更令牌) 相对基线变化且连续 CFG_FILE_SETTLE_CNT
|
||||||
* 次轮询稳定 → 重载全部段(各段复位工厂默认后解析);挂回调段
|
* 次轮询稳定 → 重载全部段(各段复位工厂默认后解析);挂回调段
|
||||||
* 有差异 → 调用其回调(如触发网络重建);重载后刷新基线
|
* 有差异 → 调用其回调(如触发网络重建);重载后刷新基线
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ extern osEventFlagsId_t sys_evtHandle;
|
|||||||
#define SYS_EVT_FTP_READY (1u << 2) /* ftpTask:lftpd_start 完成 */
|
#define SYS_EVT_FTP_READY (1u << 2) /* ftpTask:lftpd_start 完成 */
|
||||||
#define SYS_EVT_TIMESYNC_READY (1u << 3) /* timeSyncTask:首次时间同步完成 */
|
#define SYS_EVT_TIMESYNC_READY (1u << 3) /* timeSyncTask:首次时间同步完成 */
|
||||||
#define SYS_EVT_NET_RECONFIG (1u << 4) /* UI:请求立即应用新网口配置(netTask 消费后重建网络) */
|
#define SYS_EVT_NET_RECONFIG (1u << 4) /* UI:请求立即应用新网口配置(netTask 消费后重建网络) */
|
||||||
|
#define SYS_EVT_CFG_SAVE (1u << 5) /* UI:网口配置保存请求(defaultTask = 配置引擎属主,消费并写盘) */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-9
@@ -11,6 +11,11 @@
|
|||||||
* v1.2 2026-07-21 王建锋 网络初始化移入本任务(net_init + TCP 监听)
|
* v1.2 2026-07-21 王建锋 网络初始化移入本任务(net_init + TCP 监听)
|
||||||
* v1.3 2026-07-22 王建锋 单连接模式重构,增加大文件/边界/KeepAlive 测试
|
* v1.3 2026-07-22 王建锋 单连接模式重构,增加大文件/边界/KeepAlive 测试
|
||||||
* v1.4 2026-09-14 王建锋 新增自检埋点:PHY 链路 3s 未建立 → sys_log "通讯异常"
|
* v1.4 2026-09-14 王建锋 新增自检埋点:PHY 链路 3s 未建立 → sys_log "通讯异常"
|
||||||
|
* v1.5 2026-09-15 王建锋 配置加载移交 defaultTask(配置引擎属主,P1-3);
|
||||||
|
* 本任务只读 RAM 副本
|
||||||
|
* v1.6 2026-09-15 王建锋 P1-6:入口加 CH395F 硬件层测试模式自挂起守卫
|
||||||
|
* (基础线程无条件创建,该模式下不运行);
|
||||||
|
* freertos.c USER CODE 区重复创建已删除
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -22,6 +27,7 @@
|
|||||||
#include "ch395f.h"
|
#include "ch395f.h"
|
||||||
#include "sys_events.h"
|
#include "sys_events.h"
|
||||||
#include "sys_log.h"
|
#include "sys_log.h"
|
||||||
|
#include "test_config.h" /* 测试模式宏(ENABLE_HW_LAYER_TESTS);产品构建全未定义,无作用 */
|
||||||
|
|
||||||
#define DBG_TAG "[NET_TASK]"
|
#define DBG_TAG "[NET_TASK]"
|
||||||
#include "dbg_log.h"
|
#include "dbg_log.h"
|
||||||
@@ -30,7 +36,8 @@
|
|||||||
* 函数功能:"立即应用网口配置"平台回调(注册给 net_cfg)
|
* 函数功能:"立即应用网口配置"平台回调(注册给 net_cfg)
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:无
|
* 返回值:无
|
||||||
* 限定条件:UI 保存成功后经 net_cfg_request_apply() 调用(任意任务上下文)
|
* 限定条件:保存写盘成功后经 net_cfg_request_apply() 调用(MCU 上由
|
||||||
|
* defaultTask 上下文调用;任意任务上下文均安全)
|
||||||
* 函数说明:只置事件位;真正的重建在主循环内完成(CH395F SPI 归 netTask 独占,
|
* 函数说明:只置事件位;真正的重建在主循环内完成(CH395F SPI 归 netTask 独占,
|
||||||
* UI 不得直接操作)
|
* UI 不得直接操作)
|
||||||
*/
|
*/
|
||||||
@@ -44,7 +51,9 @@ static void net_reconfig_request_cb(void) {
|
|||||||
* 函数功能:CH395F 协议栈一次性初始化(两种构建模式共用)
|
* 函数功能:CH395F 协议栈一次性初始化(两种构建模式共用)
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返 回 值:0 - 成功,-1 - 失败
|
* 返 回 值:0 - 成功,-1 - 失败
|
||||||
* 函数说明:net_cfg 加载(首启/无文件 = 工厂默认)→ net_init → MAC 回写
|
* 函数说明:net_cfg 已由 defaultTask 在就绪屏障前加载进 RAM 副本(配置引擎
|
||||||
|
* 属主 = defaultTask,本任务不触碰配置文件引擎)→ 只读副本组网 →
|
||||||
|
* net_init → MAC 回写
|
||||||
* 配置模块 → MAC 打印 → PHY 强制 100M 全双工 → 广播网络就绪事件。
|
* 配置模块 → MAC 打印 → PHY 强制 100M 全双工 → 广播网络就绪事件。
|
||||||
* NET 层模式由 netTask 调用;硬件层模式(阶段 1~5)netTask 不创建,
|
* NET 层模式由 netTask 调用;硬件层模式(阶段 1~5)netTask 不创建,
|
||||||
* 由 testTask 调用后独占 CH395F。
|
* 由 testTask 调用后独占 CH395F。
|
||||||
@@ -57,9 +66,9 @@ int net_stack_bring_up(void) {
|
|||||||
|
|
||||||
DBG_INFO("=== Network Init ===");
|
DBG_INFO("=== Network Init ===");
|
||||||
|
|
||||||
/* 加载网络配置(存储后端:NAND 上 FatFS 文件 /cfg/netcfg.bin;
|
/* 网络配置:defaultTask 已在 SYS_EVT_STORAGE_READY 屏障前置入 RAM 副本
|
||||||
* 首启/存储未就绪 = 工厂默认,与既有硬编码组网值一致) */
|
* (首启/文件缺失/损坏 = 工厂默认,与既有硬编码组网值一致);
|
||||||
(void)net_cfg_load();
|
* 此处只读副本,不触碰配置文件引擎 */
|
||||||
cfg = net_cfg_get();
|
cfg = net_cfg_get();
|
||||||
|
|
||||||
net_cfg_fmt_ipv4(cfg->ip, ip, sizeof(ip));
|
net_cfg_fmt_ipv4(cfg->ip, ip, sizeof(ip));
|
||||||
@@ -140,15 +149,27 @@ int net_task_init(void) {
|
|||||||
* 函数功能:网络任务主函数
|
* 函数功能:网络任务主函数
|
||||||
* 入口参数:arg - FreeRTOS 传入参数(未使用)
|
* 入口参数:arg - FreeRTOS 传入参数(未使用)
|
||||||
* 返 回 值:无
|
* 返 回 值:无
|
||||||
* 函数说明:等待存储就绪(就绪屏障,10s 超时回退工厂默认,存储故障
|
* 函数说明:等待存储就绪(就绪屏障 = 卷挂载 + 网络配置加载完成,10s 超时
|
||||||
* 不阻塞组网)→ net_stack_bring_up() 初始化 CH395F 协议栈,
|
* 回退工厂默认,存储故障不阻塞组网)→ net_stack_bring_up() 初始化
|
||||||
|
* CH395F 协议栈,
|
||||||
* 再进入轮询循环处理网络事件。
|
* 再进入轮询循环处理网络事件。
|
||||||
* 仅 NET 层测试模式(阶段 6~10)会创建本任务;
|
* 本任务 = 基础线程:CubeMX 生成区无条件创建(全构建唯一实例);
|
||||||
* 硬件层模式下 netTask 不创建,CH395F 由 testTask 独占。
|
* CH395F 硬件层测试模式(阶段 1~5)下入口自挂起(不 bring_up、
|
||||||
|
* 不轮询、不广播 NET_READY),由 testTask 独占 CH395F。
|
||||||
*/
|
*/
|
||||||
void net_task_func(void const *arg) {
|
void net_task_func(void const *arg) {
|
||||||
(void)arg;
|
(void)arg;
|
||||||
|
|
||||||
|
/* 硬件层测试模式:testTask 独占 CH395F,本任务自挂起(基础线程恒创建,
|
||||||
|
* 该模式下"不运行"):不 bring_up、不 net_poll、不广播 NET_READY;
|
||||||
|
* ftpTask/timeSyncTask 将永久阻塞于屏障 = 预期行为(见《项目启动顺序管理》) */
|
||||||
|
#if defined(ENABLE_HW_LAYER_TESTS)
|
||||||
|
DBG_INFO("netTask parked: HW-layer test mode, CH395F owned by testTask");
|
||||||
|
for (;;) {
|
||||||
|
osDelay(1000);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* 配置在 NAND 的 FatFS 卷上:等存储就绪再读(取代原 2s 魔法延时);
|
/* 配置在 NAND 的 FatFS 卷上:等存储就绪再读(取代原 2s 魔法延时);
|
||||||
* 超时(存储异常)继续以工厂默认组网,不卡网络启动 */
|
* 超时(存储异常)继续以工厂默认组网,不卡网络启动 */
|
||||||
if (sys_evtHandle != NULL) {
|
if (sys_evtHandle != NULL) {
|
||||||
|
|||||||
+5
-3
@@ -7,6 +7,8 @@
|
|||||||
* 修改记录:
|
* 修改记录:
|
||||||
* v1.0 2026-07-19 王建锋 创建初始版本
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
* v1.1 2026-08-24 王建锋 提取 net_stack_bring_up() 供硬件层/NET 层两种测试模式共用
|
* v1.1 2026-08-24 王建锋 提取 net_stack_bring_up() 供硬件层/NET 层两种测试模式共用
|
||||||
|
* v1.2 2026-09-15 王建锋 硬件层模式描述修正:netTask 恒创建(基础线程),
|
||||||
|
* 该模式下自挂起不运行(P1-6 守卫)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NET_TASK_H
|
#ifndef NET_TASK_H
|
||||||
@@ -16,9 +18,9 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* CH395F 协议栈一次性初始化(net_init + MAC 打印 + PHY 配置 + 广播网络就绪事件)。
|
/* CH395F 协议栈一次性初始化(net_init + MAC 打印 + PHY 配置 + 广播网络就绪事件)。
|
||||||
* 返回 0 成功 / -1 失败。NET 层模式由 netTask 调用;硬件层模式(阶段 1~5)
|
* 返回 0 成功 / -1 失败。产品 / NET 层模式由 netTask 调用;硬件层模式(阶段 1~5)
|
||||||
* netTask 不创建,由 testTask 调用后独占 CH395F。 */
|
* netTask 自挂起(创建但不运行),由 testTask 调用后独占 CH395F。 */
|
||||||
int net_stack_bring_up(void);
|
int net_stack_bring_up(void);
|
||||||
|
|
||||||
int net_task_init(void);
|
int net_task_init(void);
|
||||||
|
|||||||
+97
-14
@@ -8,12 +8,18 @@
|
|||||||
* v1.0 2026-07-19 王建锋 创建初始版本
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
* v1.1 2026-09-13 王建锋 新增 sys_clock_get_time()(日历时间获取器,供 FatFs 时间钩子等使用)
|
* v1.1 2026-09-13 王建锋 新增 sys_clock_get_time()(日历时间获取器,供 FatFs 时间钩子等使用)
|
||||||
* v1.2 2026-09-13 王建锋 文件移入 App/util/(改归 ④中间件层:通用平台时间服务,多服务共用)
|
* v1.2 2026-09-13 王建锋 文件移入 App/util/(改归 ④中间件层:通用平台时间服务,多服务共用)
|
||||||
|
* v1.3 2026-09-15 王建锋 修复 49.7 天墙钟回绕:sys_clock_get 每 30 天惰性再基准
|
||||||
|
* (自我参照、无损、零 I2C);修正"未初始化"哨兵判断;
|
||||||
|
* sys_clock_init 检查 RTC 读返回值/写回复验,失败时降级为
|
||||||
|
* 编译期默认时间基准并返回 -1(激活 app_main 时钟芯片自检)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sys_clock.h"
|
#include "sys_clock.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "FreeRTOS.h" /* taskENTER_CRITICAL:惰性再基准化的并发保护 */
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
#define DBG_TAG "[CLK]"
|
#define DBG_TAG "[CLK]"
|
||||||
#include "dbg_log.h"
|
#include "dbg_log.h"
|
||||||
@@ -42,6 +48,13 @@
|
|||||||
static volatile uint32_t s_base_tick = 0; /* HAL_GetTick() 基准 */
|
static volatile uint32_t s_base_tick = 0; /* HAL_GetTick() 基准 */
|
||||||
static volatile uint32_t s_base_unix_secs = UINT32_MAX;
|
static volatile uint32_t s_base_unix_secs = UINT32_MAX;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 再基准化周期(惰性再基准化,见 sys_clock_get 说明):
|
||||||
|
* 32 位 tick 差值窗口必须恒 < 一整圈(2^32 ms ≈ 49.7 天),否则差值混叠、
|
||||||
|
* 墙钟"倒退"一圈。30 天 = 2,592,000,000 ms < 2^32,为惰性触发延迟留 19.7 天余量。
|
||||||
|
*/
|
||||||
|
#define SYS_CLOCK_REBASE_MS (30u * 24u * 3600u * 1000u)
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* 内部辅助函数:Unix time ↔ sd2506_time_t 转换
|
* 内部辅助函数:Unix time ↔ sd2506_time_t 转换
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
@@ -155,12 +168,17 @@ static void unix_to_sd2506(uint32_t unix_secs, sd2506_time_t *p_sd_time) {
|
|||||||
/*
|
/*
|
||||||
* 函数功能:初始化系统墙钟时间基准
|
* 函数功能:初始化系统墙钟时间基准
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:0 - 成功(始终返回 0)
|
* 返回值:0 - 成功;-1 - RTC 不可用(启用编译期默认值时降级为编译期默认时间
|
||||||
|
* 基准:墙钟仍可用,返回值报告芯片故障;否则不建基准,墙钟保持"未初始化")
|
||||||
* 限定条件:CubeMX 外设初始化完成、SD2506 RTC 驱动已初始化
|
* 限定条件:CubeMX 外设初始化完成、SD2506 RTC 驱动已初始化
|
||||||
* 函数说明:1. 从 SD2506 读取初始时间,必要时按编译期默认宏校时(RTC_DEFAULT_INIT_*)
|
* 函数说明:1. 从 SD2506 读取初始时间(检查返回值:I2C 读失败 → 判 RTC 异常),
|
||||||
* 2. 将 RTC 时间换算为 Unix epoch 秒数
|
* 必要时按编译期默认宏校时(RTC_DEFAULT_INIT_*),写回后复验范围
|
||||||
|
* 2. 将 RTC 时间换算为 Unix epoch 秒数(仅合法值进入换算,防垃圾月份在
|
||||||
|
* i < month - 1 处下溢空转约 40 亿次)
|
||||||
* 3. 记录当前 HAL Tick 与 Unix 秒数为基准,供 sys_clock_get() 后续推算
|
* 3. 记录当前 HAL Tick 与 Unix 秒数为基准,供 sys_clock_get() 后续推算
|
||||||
* 4. 注意:sd2506_get_time() 返回的 year 已是完整年份(驱动内 +2000),
|
* 4. RTC 不可用时:启用编译期默认值则以默认时间建基准(仅 RAM、不依赖芯片)
|
||||||
|
* 并返回 -1;否则不建基准,返回 -1
|
||||||
|
* 5. 注意:sd2506_get_time() 返回的 year 已是完整年份(驱动内 +2000),
|
||||||
* 换算时不得再加 2000,否则年份虚增导致 Unix 秒数超 uint32 回绕
|
* 换算时不得再加 2000,否则年份虚增导致 Unix 秒数超 uint32 回绕
|
||||||
*/
|
*/
|
||||||
int sys_clock_init(void) {
|
int sys_clock_init(void) {
|
||||||
@@ -168,14 +186,17 @@ int sys_clock_init(void) {
|
|||||||
uint32_t year, month, day, hour, minute, second;
|
uint32_t year, month, day, hour, minute, second;
|
||||||
int64_t unix_secs = 0;
|
int64_t unix_secs = 0;
|
||||||
int i;
|
int i;
|
||||||
|
int rtc_ok; /* RTC 读取可用(1)/不可用(0) */
|
||||||
|
int degraded = 0; /* 1 = 以编译期默认时间建基准(RTC 故障,返回值报 -1) */
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Step 1:从 SD2506 硬件 RTC 读取初始时间
|
* Step 1:从 SD2506 硬件 RTC 读取初始时间
|
||||||
* ============================================================
|
* ============================================================
|
||||||
* 注意:sd2506_get_time() 返回的 year 已是完整年份(如 2026,
|
* 注意:sd2506_get_time() 返回的 year 已是完整年份(如 2026,
|
||||||
* 驱动内部已 +2000)。此处【禁止】再 +2000,否则年份虚增到 4026,
|
* 驱动内部已 +2000)。此处【禁止】再 +2000,否则年份虚增到 4026,
|
||||||
* 换算出的 Unix 秒数远超 uint32_t 上限被截断回绕,时间彻底错乱。 */
|
* 换算出的 Unix 秒数远超 uint32_t 上限被截断回绕,时间彻底错乱。
|
||||||
sd2506_get_time(&sd_time);
|
* 返回值必须检查:I2C 失败时字段为垃圾,不得用于建立基准。 */
|
||||||
|
rtc_ok = (sd2506_get_time(&sd_time) == SD2506_OK) ? 1 : 0;
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Step 1.1:开发期校时(可选,由 RTC_DEFAULT_INIT_* 宏控制)
|
* Step 1.1:开发期校时(可选,由 RTC_DEFAULT_INIT_* 宏控制)
|
||||||
@@ -185,7 +206,8 @@ int sys_clock_init(void) {
|
|||||||
* 判定"时间无效":年份越界、月/日越界(仅粗判,不细校 2 月 29 日等)。 */
|
* 判定"时间无效":年份越界、月/日越界(仅粗判,不细校 2 月 29 日等)。 */
|
||||||
#if defined(RTC_DEFAULT_INIT_ENABLE)
|
#if defined(RTC_DEFAULT_INIT_ENABLE)
|
||||||
{
|
{
|
||||||
int rtc_invalid = (sd_time.year < 2000 || sd_time.year > 2099 ||
|
int rtc_invalid = (rtc_ok == 0) ||
|
||||||
|
(sd_time.year < 2000 || sd_time.year > 2099 ||
|
||||||
sd_time.month < 1 || sd_time.month > 12 ||
|
sd_time.month < 1 || sd_time.month > 12 ||
|
||||||
sd_time.day < 1 || sd_time.day > 31);
|
sd_time.day < 1 || sd_time.day > 31);
|
||||||
#if (RTC_DEFAULT_INIT_FORCE == 1)
|
#if (RTC_DEFAULT_INIT_FORCE == 1)
|
||||||
@@ -207,7 +229,7 @@ int sys_clock_init(void) {
|
|||||||
DBG_INFO("sys_clock_init: RTC set %04d-%02d-%02d %02d:%02d:%02d",
|
DBG_INFO("sys_clock_init: RTC set %04d-%02d-%02d %02d:%02d:%02d",
|
||||||
init_t.year, init_t.month, init_t.day,
|
init_t.year, init_t.month, init_t.day,
|
||||||
init_t.hour, init_t.minute, init_t.second);
|
init_t.hour, init_t.minute, init_t.second);
|
||||||
sd2506_get_time(&sd_time); /* 重新读取校准后的值,确保后续换算用真实 RTC 数据 */
|
rtc_ok = (sd2506_get_time(&sd_time) == SD2506_OK) ? 1 : 0; /* 重新读取校准后的值(同样检查返回值) */
|
||||||
} else {
|
} else {
|
||||||
DBG_ERROR("sys_clock_init: RTC default write FAIL");
|
DBG_ERROR("sys_clock_init: RTC default write FAIL");
|
||||||
}
|
}
|
||||||
@@ -215,6 +237,39 @@ int sys_clock_init(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 写回后复验范围:能写入但读回仍越界的芯片同样判故障;
|
||||||
|
* 同时保证进入 Step 2 换算循环的必为合法值(见函数说明第 2 条)。
|
||||||
|
*/
|
||||||
|
if (rtc_ok != 0 &&
|
||||||
|
(sd_time.year < 2000 || sd_time.year > 2099 ||
|
||||||
|
sd_time.month < 1 || sd_time.month > 12 ||
|
||||||
|
sd_time.day < 1 || sd_time.day > 31)) {
|
||||||
|
rtc_ok = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtc_ok == 0) {
|
||||||
|
#if (RTC_DEFAULT_INIT_ENABLE == 1)
|
||||||
|
/*
|
||||||
|
* 降级基准:以编译期默认时间建立基准(仅 RAM、不依赖芯片)。
|
||||||
|
* 墙钟保持可用(日志时间戳为默认时间);返回值报告芯片故障,
|
||||||
|
* 触发 app_main 的"时钟芯片异常"自检。
|
||||||
|
*/
|
||||||
|
DBG_ERROR("sys_clock_init: RTC abnormal, fallback to default time");
|
||||||
|
sd_time.year = RTC_DEFAULT_YEAR;
|
||||||
|
sd_time.month = RTC_DEFAULT_MONTH;
|
||||||
|
sd_time.day = RTC_DEFAULT_DAY;
|
||||||
|
sd_time.hour = RTC_DEFAULT_HOUR;
|
||||||
|
sd_time.minute = RTC_DEFAULT_MINUTE;
|
||||||
|
sd_time.second = RTC_DEFAULT_SECOND;
|
||||||
|
sd_time.week = rtc_calc_week(sd_time.year, sd_time.month, sd_time.day);
|
||||||
|
degraded = 1;
|
||||||
|
#else
|
||||||
|
DBG_ERROR("sys_clock_init: RTC read FAIL, wall clock uninitialized");
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* 取出各时间字段(year 已是完整年份,直接用于下文 Unix 换算) */
|
/* 取出各时间字段(year 已是完整年份,直接用于下文 Unix 换算) */
|
||||||
year = (uint32_t)sd_time.year;
|
year = (uint32_t)sd_time.year;
|
||||||
month = (uint32_t)sd_time.month;
|
month = (uint32_t)sd_time.month;
|
||||||
@@ -275,24 +330,52 @@ int sys_clock_init(void) {
|
|||||||
DBG_INFO("sys_clock_init: wall clock base = unix %lu, base_tick=%lu",
|
DBG_INFO("sys_clock_init: wall clock base = unix %lu, base_tick=%lu",
|
||||||
(unsigned long)s_base_unix_secs, (unsigned long)s_base_tick);
|
(unsigned long)s_base_unix_secs, (unsigned long)s_base_tick);
|
||||||
|
|
||||||
return 0;
|
return (degraded != 0) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:获取当前系统墙钟时间(Unix 时间戳)
|
* 函数功能:获取当前系统墙钟时间(Unix 时间戳)
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:当前 Unix 秒数 uint32_t 未初始化时返回 UINT32_MAX
|
* 返回值:当前 Unix 秒数 uint32_t 未初始化时返回 UINT32_MAX
|
||||||
* 限定条件:sys_clock_init() 已成功调用
|
* 限定条件:sys_clock_init() 已调用
|
||||||
* 函数说明:1. 以基准 Tick 与基准 Unix 秒数为起点,按当前 HAL Tick 与 1000ms
|
* 函数说明:1. 以基准 Tick 与基准 Unix 秒数为起点,按当前 HAL Tick 与 1000ms
|
||||||
* 的整除差推算流逝秒数(避免每毫秒累加,减少漂移与溢出风险)
|
* 的整除差推算流逝秒数(避免每毫秒累加,减少漂移与溢出风险);
|
||||||
* 2. 若推算结果为负(基准未建立),返回 UINT32_MAX 表示无效
|
* 32 位无符号模减对 Tick 回绕天然无缝
|
||||||
|
* 2. 差值窗口达到 SYS_CLOCK_REBASE_MS(30 天)时触发"惰性再基准化":
|
||||||
|
* 基准前移流逝秒数(墙钟值不变)、差值窗口清零,亚秒余数结转入
|
||||||
|
* 新窗(base_tick = now − 余数)故无损,保证差值永不因一整圈
|
||||||
|
* 2^32 ms(≈49.7 天)而混叠
|
||||||
|
* 3. 再基准化为自我参照:纯内存操作、零 I2C、非阻塞——不重读 RTC
|
||||||
|
* 重锚(RTC 精度远逊 CPU Tick,重锚反而吸收其漂移);临界区 +
|
||||||
|
* 区内复核防多任务并发重复累加
|
||||||
|
* 4. 若基准未建立(init 失败),返回 UINT32_MAX 表示无效
|
||||||
*/
|
*/
|
||||||
uint32_t sys_clock_get(void) {
|
uint32_t sys_clock_get(void) {
|
||||||
uint32_t now_tick = HAL_GetTick();
|
uint32_t now_tick = HAL_GetTick();
|
||||||
int64_t unix_secs = (int64_t)s_base_unix_secs + (int64_t)((uint32_t)(now_tick - s_base_tick) / 1000uL);
|
uint32_t diff = now_tick - s_base_tick; /* 32 位模减,跨 Tick 回绕无缝 */
|
||||||
|
int64_t unix_secs;
|
||||||
|
|
||||||
|
if (s_base_unix_secs != UINT32_MAX && diff > SYS_CLOCK_REBASE_MS) {
|
||||||
|
uint32_t secs = diff / 1000u;
|
||||||
|
uint32_t rem = diff - secs * 1000u; /* 亚秒余数,结转入新窗 → 无损 */
|
||||||
|
|
||||||
|
taskENTER_CRITICAL();
|
||||||
|
diff = now_tick - s_base_tick; /* 临界区内复核:另一任务可能已先再基准化 */
|
||||||
|
if (diff > SYS_CLOCK_REBASE_MS) {
|
||||||
|
s_base_unix_secs += secs; /* 基准前移:墙钟值本身不变 */
|
||||||
|
s_base_tick = now_tick - rem; /* 新窗自 (now − 余数) 起算,余数续计 */
|
||||||
|
diff = rem;
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_base_unix_secs == UINT32_MAX) {
|
||||||
|
return UINT32_MAX; /* 未初始化(显式哨兵判断) */
|
||||||
|
}
|
||||||
|
|
||||||
|
unix_secs = (int64_t)s_base_unix_secs + (int64_t)(diff / 1000u);
|
||||||
if (unix_secs < 0) {
|
if (unix_secs < 0) {
|
||||||
return UINT32_MAX; /* 未初始化 */
|
return UINT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (uint32_t)unix_secs;
|
return (uint32_t)unix_secs;
|
||||||
|
|||||||
@@ -133,9 +133,12 @@ int lftpd_inet_write_string(int socket, const char *message)
|
|||||||
|
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
int write_len = net_send(socket, p, length, 0);
|
int write_len = net_send(socket, p, length, 0);
|
||||||
if (write_len < 0) {
|
/* write_len == 0:发送超时且零进展(对端未消费数据);不判为致命则
|
||||||
DBG_ERROR("write error");
|
* length 永不减少,将在此空转(任务死锁)。返回错误交会话层拆除
|
||||||
return write_len;
|
* 连接(lftpd.c handle_control_channel 的 cleanup 路径)。 */
|
||||||
|
if (write_len <= 0) {
|
||||||
|
DBG_ERROR("write error, ret=%d", write_len);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
p += write_len;
|
p += write_len;
|
||||||
length -= write_len;
|
length -= write_len;
|
||||||
@@ -151,8 +154,12 @@ int lftpd_inet_write(int socket, const void *buf, int len)
|
|||||||
|
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
int n = net_send(socket, p, remaining, 0);
|
int n = net_send(socket, p, remaining, 0);
|
||||||
if (n < 0) {
|
/* n == 0:发送超时且零进展(对端停滞/断链),判为致命:否则 remaining
|
||||||
return n;
|
* 永不减少 → 死循环。调用方(lftpd.c send_file)收到 < 0 后终止传输
|
||||||
|
* 并向上报 450 错误,会话保持可用。 */
|
||||||
|
if (n <= 0) {
|
||||||
|
DBG_ERROR("write error, ret=%d", n);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
p += n;
|
p += n;
|
||||||
remaining -= n;
|
remaining -= n;
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
* 修改记录:
|
* 修改记录:
|
||||||
* v1.0 2026-09-10 王建锋 创建初始版本
|
* v1.0 2026-09-10 王建锋 创建初始版本
|
||||||
* v1.1 2026-09-14 王建锋 存储迁移至 cfg_file 引擎(INI);旧 NCFG 代码移至 net_cfg_legacy
|
* v1.1 2026-09-14 王建锋 存储迁移至 cfg_file 引擎(INI);旧 NCFG 代码移至 net_cfg_legacy
|
||||||
|
* v1.2 2026-09-15 王建锋 保存改跨任务交接(request/state/run + 通知回调);
|
||||||
|
* 引擎属主 = defaultTask(P1-3 竞态修复)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 头文件包含区 */
|
/* 头文件包含区 */
|
||||||
@@ -49,6 +51,9 @@ static net_cfg_t s_cfg = {
|
|||||||
static uint8_t s_active_mac[6]; /* 芯片实际 MAC 影子(netTask 回写) */
|
static uint8_t s_active_mac[6]; /* 芯片实际 MAC 影子(netTask 回写) */
|
||||||
static uint8_t s_active_valid; /* 影子有效标志(0 = 尚未回写) */
|
static uint8_t s_active_valid; /* 影子有效标志(0 = 尚未回写) */
|
||||||
static net_cfg_apply_cb_t s_apply_cb; /* "立即应用"平台回调(未注册 = 空操作) */
|
static net_cfg_apply_cb_t s_apply_cb; /* "立即应用"平台回调(未注册 = 空操作) */
|
||||||
|
static volatile uint8_t s_save_pending; /* 1 = 有待执行保存请求(UI 投递/属主执行) */
|
||||||
|
static volatile uint8_t s_save_result; /* 最近一次保存结果:0 = 无;1 = 成功;2 = 失败 */
|
||||||
|
static net_cfg_save_req_cb_t s_save_req_cb; /* "保存请求"平台通知(未注册 = 空操作) */
|
||||||
|
|
||||||
/* 工厂默认(引擎注册 p_defaults 指向;与 s_cfg 初值共用宏单一来源) */
|
/* 工厂默认(引擎注册 p_defaults 指向;与 s_cfg 初值共用宏单一来源) */
|
||||||
static const net_cfg_t s_defaults = {
|
static const net_cfg_t s_defaults = {
|
||||||
@@ -127,7 +132,9 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
|
|||||||
* 函数功能:从存储加载网络配置到 RAM 副本
|
* 函数功能:从存储加载网络配置到 RAM 副本
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:恒 0(RAM 恒有效:文件缺失/CRC 错回退工厂默认) int
|
* 返回值:恒 0(RAM 恒有效:文件缺失/CRC 错回退工厂默认) int
|
||||||
* 限定条件:MCU 端应在存储就绪后调用;未就绪时文件读失败自动回退
|
* 限定条件:由配置引擎属主任务调用(MCU = defaultTask,置位
|
||||||
|
* SYS_EVT_STORAGE_READY 前;模拟器 = 主循环启动期);文件读失败
|
||||||
|
* 自动回退工厂默认(不阻塞网络启动)
|
||||||
* 函数说明:见 net_cfg.h 同名函数说明
|
* 函数说明:见 net_cfg.h 同名函数说明
|
||||||
*/
|
*/
|
||||||
int net_cfg_load(void) {
|
int net_cfg_load(void) {
|
||||||
@@ -151,10 +158,9 @@ int net_cfg_load(void) {
|
|||||||
* 函数功能:保存当前 RAM 配置到存储
|
* 函数功能:保存当前 RAM 配置到存储
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:0 - 成功;-1 - 写失败 int
|
* 返回值:0 - 成功;-1 - 写失败 int
|
||||||
* 限定条件:MCU 端应在存储就绪后调用
|
* 限定条件:仅配置引擎属主任务上下文调用(MCU = defaultTask;模拟器 = 主循环)
|
||||||
* 函数说明:经 cfg_file 引擎写盘(外科手术式保存:保留注释/未知内容,
|
* 函数说明:经 cfg_file 引擎写盘(外科手术式保存:保留注释/未知内容,
|
||||||
* 临时文件 + 原子改名);下次上电(netTask 在 net_init 前加载)
|
* 临时文件 + 原子改名);跨任务场景请投递 net_cfg_save_request
|
||||||
* 或 poll 4s 沉降后生效
|
|
||||||
*/
|
*/
|
||||||
int net_cfg_save(void) {
|
int net_cfg_save(void) {
|
||||||
int r;
|
int r;
|
||||||
@@ -193,6 +199,84 @@ void net_cfg_request_apply(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:投递"保存网络配置"请求(跨任务交接的投递端)
|
||||||
|
* 入口参数:无
|
||||||
|
* 返回值:恒 0 int
|
||||||
|
* 限定条件:任意任务上下文(UI 保存行);新值须已落 RAM 副本
|
||||||
|
* 函数说明:置"待保存"标志后经平台回调唤醒属主任务(MCU:置
|
||||||
|
* SYS_EVT_CFG_SAVE 事件);写盘与"立即应用"由属主任务执行
|
||||||
|
* (net_cfg_save_run),本函数不触碰配置文件引擎
|
||||||
|
*/
|
||||||
|
int net_cfg_save_request(void) {
|
||||||
|
s_save_pending = 1u;
|
||||||
|
|
||||||
|
if (s_save_req_cb != NULL) {
|
||||||
|
s_save_req_cb();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:取保存请求交接状态(UI 保存行显示)
|
||||||
|
* 入口参数:无
|
||||||
|
* 返回值:NET_CFG_SAVE_ST_IDLE / _WAIT / _OK / _FAIL int
|
||||||
|
* 限定条件:任意任务上下文(单字节读取,无撕裂)
|
||||||
|
* 函数说明:见 net_cfg.h 同名函数说明
|
||||||
|
*/
|
||||||
|
int net_cfg_save_state(void) {
|
||||||
|
if (s_save_pending != 0u) {
|
||||||
|
return (int)NET_CFG_SAVE_ST_WAIT;
|
||||||
|
}
|
||||||
|
if (s_save_result == 1u) {
|
||||||
|
return (int)NET_CFG_SAVE_ST_OK;
|
||||||
|
}
|
||||||
|
if (s_save_result == 2u) {
|
||||||
|
return (int)NET_CFG_SAVE_ST_FAIL;
|
||||||
|
}
|
||||||
|
return (int)NET_CFG_SAVE_ST_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:执行待处理的保存请求(配置文件引擎属主任务)
|
||||||
|
* 入口参数:无
|
||||||
|
* 返回值:0 - 无待处理请求或保存成功;-1 - 写盘失败 int
|
||||||
|
* 限定条件:仅配置引擎属主任务上下文(MCU = defaultTask;模拟器 = 主循环)
|
||||||
|
* 函数说明:先清"待保存"标志(写盘期间的新请求重位置位,下轮再执行,
|
||||||
|
* 不丢失);写盘成功 → 置 OK 并触发"立即应用"(netTask 重建
|
||||||
|
* 网络,无需重启);失败 → 置 FAIL,不触发应用(网络保持)
|
||||||
|
*/
|
||||||
|
int net_cfg_save_run(void) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (s_save_pending == 0u) {
|
||||||
|
return 0; /* 无待处理请求(空醒/周期轮询) */
|
||||||
|
}
|
||||||
|
s_save_pending = 0u;
|
||||||
|
|
||||||
|
r = net_cfg_save();
|
||||||
|
if (r == 0) {
|
||||||
|
s_save_result = 1u;
|
||||||
|
net_cfg_request_apply();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s_save_result = 2u;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:注册"保存请求"通知回调
|
||||||
|
* 入口参数:cb - 回调函数(NULL = 注销) net_cfg_save_req_cb_t
|
||||||
|
* 返回值:无
|
||||||
|
* 限定条件:应用启动早期注册一次即可
|
||||||
|
* 函数说明:MCU 端 defaultTask 注册(置 SYS_EVT_CFG_SAVE 事件立即唤醒);
|
||||||
|
* 模拟器不注册(主循环每轮查状态,无需唤醒)
|
||||||
|
*/
|
||||||
|
void net_cfg_set_save_req_cb(net_cfg_save_req_cb_t cb) {
|
||||||
|
s_save_req_cb = cb;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:取 RAM 配置副本(只读指针)
|
* 函数功能:取 RAM 配置副本(只读指针)
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* 模块名称:Network Configuration (NET CFG)
|
* 模块名称:Network Configuration (NET CFG)
|
||||||
* 模块功能:网络参数配置(IP/掩码/网关/MAC)——双端共享核心:RAM 配置副本 +
|
* 模块功能:网络参数配置(IP/掩码/网关/MAC)——双端共享核心:RAM 配置副本 +
|
||||||
* 工厂默认 + 加载/保存编排 + 实际 MAC 影子;存储经 cfg_file 通用
|
* 工厂默认 + 加载/保存编排 + 实际 MAC 影子 + 跨任务保存请求交接;
|
||||||
* 配置文件引擎(INI [network] 段:ip/mask/gw/mac;MCU = NAND 上
|
* 存储经 cfg_file 通用配置文件引擎(INI [network] 段:ip/mask/gw/mac;
|
||||||
* /config.ini,模拟器 = sim_config.ini);MAC 全零哨兵 = 不覆盖芯片
|
* MCU = NAND 上 /config.ini,模拟器 = sim_config.ini);MAC 全零哨兵
|
||||||
* 内置 MAC;保存后下次上电生效(每次上电 netTask 在 net_init 前
|
* = 不覆盖芯片内置 MAC。cfg_file 引擎为静态单任务设计,调用收敛于
|
||||||
* 加载)或 poll 4s 沉降后生效
|
* 单一属主任务(MCU = defaultTask:就绪屏障前加载 / 保存执行 / 2s
|
||||||
|
* poll;模拟器 = 主循环);UI 保存只投递请求,netTask 只读 RAM 副本
|
||||||
* 函数说明:旧版 NCFG 二进制格式(magic+ver+CRC-16+18B 字段)归 net_cfg_legacy,
|
* 函数说明:旧版 NCFG 二进制格式(magic+ver+CRC-16+18B 字段)归 net_cfg_legacy,
|
||||||
* 首启一次性迁移进通用配置文件
|
* 首启一次性迁移进通用配置文件
|
||||||
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用)
|
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用)
|
||||||
@@ -14,6 +15,8 @@
|
|||||||
* 修改记录:
|
* 修改记录:
|
||||||
* v1.0 2026-09-10 王建锋 创建初始版本
|
* v1.0 2026-09-10 王建锋 创建初始版本
|
||||||
* v1.1 2026-09-14 王建锋 存储迁移至 cfg_file 引擎(INI [network] 段)
|
* v1.1 2026-09-14 王建锋 存储迁移至 cfg_file 引擎(INI [network] 段)
|
||||||
|
* v1.2 2026-09-15 王建锋 保存改跨任务交接(request/state/run + 通知回调);
|
||||||
|
* 引擎属主明确为 defaultTask(P1-3 竞态修复)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NET_CFG_H
|
#ifndef NET_CFG_H
|
||||||
@@ -42,8 +45,9 @@ typedef struct {
|
|||||||
* 函数功能:从存储加载网络配置到 RAM 副本
|
* 函数功能:从存储加载网络配置到 RAM 副本
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:恒 0(RAM 恒有效:文件缺失/损坏回退工厂默认) int
|
* 返回值:恒 0(RAM 恒有效:文件缺失/损坏回退工厂默认) int
|
||||||
* 限定条件:MCU 端应在存储就绪(SYS_EVT_STORAGE_READY)后调用;
|
* 限定条件:由配置引擎属主任务调用(MCU = defaultTask,置位
|
||||||
* 未就绪时文件读失败,自动回退工厂默认(不阻塞网络启动)
|
* SYS_EVT_STORAGE_READY 前;模拟器 = 主循环启动期);文件读失败
|
||||||
|
* 自动回退工厂默认(不阻塞网络启动)
|
||||||
* 函数说明: 1. 注册 [network] 段(幂等)
|
* 函数说明: 1. 注册 [network] 段(幂等)
|
||||||
* 2. 文件缺失 → 先迁旧档 NCFG(有效 → 旧值物化进新文件),否则
|
* 2. 文件缺失 → 先迁旧档 NCFG(有效 → 旧值物化进新文件),否则
|
||||||
* 生成出厂模板
|
* 生成出厂模板
|
||||||
@@ -56,10 +60,10 @@ int net_cfg_load(void);
|
|||||||
* 函数功能:保存当前 RAM 配置到存储(Flash 持久化)
|
* 函数功能:保存当前 RAM 配置到存储(Flash 持久化)
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:0 - 成功;-1 - 写失败 int
|
* 返回值:0 - 成功;-1 - 写失败 int
|
||||||
* 限定条件:MCU 端应在存储就绪后调用
|
* 限定条件:仅配置引擎属主任务上下文调用(MCU = defaultTask;模拟器 = 主循环);
|
||||||
|
* 跨任务保存请用 net_cfg_save_request 投递
|
||||||
* 函数说明:经 cfg_file 引擎写盘(外科手术式保存:保留注释/未知内容,
|
* 函数说明:经 cfg_file 引擎写盘(外科手术式保存:保留注释/未知内容,
|
||||||
* 临时文件 + 原子改名);下次上电(netTask 在 net_init 前加载)
|
* 临时文件 + 原子改名);属主任务执行,成功后触发"立即应用"
|
||||||
* 或 poll 4s 沉降后生效
|
|
||||||
*/
|
*/
|
||||||
int net_cfg_save(void);
|
int net_cfg_save(void);
|
||||||
|
|
||||||
@@ -87,11 +91,73 @@ void net_cfg_set_apply_cb(net_cfg_apply_cb_t cb);
|
|||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:无
|
* 返回值:无
|
||||||
* 限定条件:无(未注册回调时空操作)
|
* 限定条件:无(未注册回调时空操作)
|
||||||
* 函数说明:UI"网口设置"页保存行写盘成功后调用;真正生效由平台回调完成
|
* 函数说明:保存写盘成功后由属主任务调用(MCU:defaultTask);真正生效
|
||||||
* (MCU:netTask 重建网络,无需重启)
|
* 由平台回调完成(MCU:netTask 重建网络,无需重启)
|
||||||
*/
|
*/
|
||||||
void net_cfg_request_apply(void);
|
void net_cfg_request_apply(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 保存请求交接状态(UI 保存行显示)
|
||||||
|
* IDLE - 尚无保存(显示 ENTER)
|
||||||
|
* WAIT - 保存进行中:请求已投递未执行 / 属主任务写盘中(显示 WAIT)
|
||||||
|
* OK - 最近一次保存成功(显示 OK)
|
||||||
|
* FAIL - 最近一次保存失败(显示 ERR)
|
||||||
|
*/
|
||||||
|
#define NET_CFG_SAVE_ST_IDLE 0u
|
||||||
|
#define NET_CFG_SAVE_ST_WAIT 1u
|
||||||
|
#define NET_CFG_SAVE_ST_OK 2u
|
||||||
|
#define NET_CFG_SAVE_ST_FAIL 3u
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:投递"保存网络配置"请求(跨任务交接的投递端)
|
||||||
|
* 入口参数:无
|
||||||
|
* 返回值:恒 0 int
|
||||||
|
* 限定条件:任意任务上下文(UI 保存行);新值须已落 RAM 副本(net_cfg_set)
|
||||||
|
* 函数说明:只置"待保存"标志 + 经平台回调唤醒属主任务(MCU:置
|
||||||
|
* SYS_EVT_CFG_SAVE 事件);写盘与"立即应用"由属主任务执行
|
||||||
|
* (net_cfg_save_run),UI 不直接触碰配置文件引擎
|
||||||
|
*/
|
||||||
|
int net_cfg_save_request(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:取保存请求交接状态(供 UI 保存行显示)
|
||||||
|
* 入口参数:无
|
||||||
|
* 返回值:NET_CFG_SAVE_ST_IDLE / _WAIT / _OK / _FAIL int
|
||||||
|
* 限定条件:任意任务上下文(单字节读取,无撕裂)
|
||||||
|
*/
|
||||||
|
int net_cfg_save_state(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:执行待处理的保存请求(配置文件引擎属主任务)
|
||||||
|
* 入口参数:无
|
||||||
|
* 返回值:0 - 无待处理请求或保存成功;-1 - 写盘失败 int
|
||||||
|
* 限定条件:仅配置引擎属主任务上下文(MCU = defaultTask;模拟器 = 主循环)
|
||||||
|
* 函数说明:有待处理请求 → 先清标志(写盘期间的新请求重位置位,下轮再
|
||||||
|
* 执行,不丢失)→ net_cfg_save() 写盘 → 成功置 OK 并触发"立即
|
||||||
|
* 应用"(netTask 重建网络);失败置 FAIL(不触发应用,网络保持
|
||||||
|
* 原配置)
|
||||||
|
*/
|
||||||
|
int net_cfg_save_run(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "保存请求"通知回调类型:平台挂钩(可选)
|
||||||
|
* 入口参数:无
|
||||||
|
* 返回值:无
|
||||||
|
* 函数说明:MCU 端由 defaultTask 注册——置 SYS_EVT_CFG_SAVE 事件立即唤醒
|
||||||
|
* 属主任务执行写盘;模拟器单线程无需唤醒,不注册(空操作)。
|
||||||
|
* 经回调而非直接调用,避免 NETCFG(驱动层)反向依赖 App 层。
|
||||||
|
*/
|
||||||
|
typedef void (*net_cfg_save_req_cb_t)(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:注册"保存请求"通知回调
|
||||||
|
* 入口参数:cb - 回调函数(NULL = 注销) net_cfg_save_req_cb_t
|
||||||
|
* 返回值:无
|
||||||
|
* 限定条件:应用启动早期注册一次即可
|
||||||
|
* 函数说明:见 net_cfg_save_req_cb_t
|
||||||
|
*/
|
||||||
|
void net_cfg_set_save_req_cb(net_cfg_save_req_cb_t cb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:取 RAM 配置副本(只读指针)
|
* 函数功能:取 RAM 配置副本(只读指针)
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
|
|||||||
@@ -3,19 +3,24 @@
|
|||||||
* 模块功能:网口设置叶子节点的内容页数据 + 行为——5 行地址列表(IP 地址/子网
|
* 模块功能:网口设置叶子节点的内容页数据 + 行为——5 行地址列表(IP 地址/子网
|
||||||
* 掩码/默认网关/MAC 地址 + 保存行,5 行每页共 1 页);
|
* 掩码/默认网关/MAC 地址 + 保存行,5 行每页共 1 页);
|
||||||
* 行槽顶 = 24+14i、选中白带 x=2..156 高 13、名 x=4 / 值 x=54;
|
* 行槽顶 = 24+14i、选中白带 x=2..156 高 13、名 x=4 / 值 x=54;
|
||||||
* 值取自 net_cfg RAM 副本(netTask 上电自 Flash 加载并回写实际 MAC);
|
* 值取自 net_cfg RAM 副本(defaultTask 上电自 Flash 加载;
|
||||||
|
* netTask 回写实际 MAC 影子);
|
||||||
* 编辑模式:ENTER 进选中地址行(字节光标 = 活动字节,反显标记),
|
* 编辑模式:ENTER 进选中地址行(字节光标 = 活动字节,反显标记),
|
||||||
* ↑↓调字节 0..255(环绕、值列实时刷新)、←→移字节光标(首↔末环绕)、
|
* ↑↓调字节 0..255(环绕、值列实时刷新)、←→移字节光标(首↔末环绕)、
|
||||||
* ENTER 确认退出编辑;
|
* ENTER 确认退出编辑;
|
||||||
* 权限:edit_capable=1——查看密码 → 只读(编辑/保存键无效),
|
* 权限:edit_capable=1——查看密码 → 只读(编辑/保存键无效),
|
||||||
* 修改密码 → 可编辑;保存行 ENTER → net_cfg_save() 写盘 +
|
* 修改密码 → 可编辑;保存行 ENTER → 投递保存请求
|
||||||
* net_cfg_request_apply() 通知 netTask 立即重建网络(无需重启);
|
* (net_cfg_save_request;属主任务 defaultTask 写盘并立即应用
|
||||||
|
* 重建网络,无需重启);保存行值随交接状态显示
|
||||||
|
* ENTER/WAIT/OK/ERR;
|
||||||
* 向框架 ui_content_page 提供页面描述符(零 LVGL 对象)
|
* 向框架 ui_content_page 提供页面描述符(零 LVGL 对象)
|
||||||
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用)
|
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用)
|
||||||
* 作者:王建锋
|
* 作者:王建锋
|
||||||
* 创建日期:2026-09-10
|
* 创建日期:2026-09-10
|
||||||
* 修改记录:
|
* 修改记录:
|
||||||
* v1.0 2026-09-10 王建锋 创建初始版本
|
* v1.0 2026-09-10 王建锋 创建初始版本
|
||||||
|
* v1.1 2026-09-15 王建锋 保存改异步交接:投递请求 → 属主任务写盘/应用;
|
||||||
|
* 保存行随交接状态显示 ENTER/WAIT/OK/ERR
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 头文件包含区 */
|
/* 头文件包含区 */
|
||||||
@@ -46,10 +51,9 @@
|
|||||||
|
|
||||||
/* 静态变量定义区 */
|
/* 静态变量定义区 */
|
||||||
|
|
||||||
/* 页面运行态(每次开页经 init_cb 重置;约 3 B) */
|
/* 页面运行态(每次开页经 init_cb 重置;约 2 B) */
|
||||||
static uint8_t s_editing; /* 1 = 编辑中(被编辑行 = 当前选中行) */
|
static uint8_t s_editing; /* 1 = 编辑中(被编辑行 = 当前选中行) */
|
||||||
static uint8_t s_cursor; /* 编辑模式活动字节(IP/掩码/网关 0..3,MAC 0..5) */
|
static uint8_t s_cursor; /* 编辑模式活动字节(IP/掩码/网关 0..3,MAC 0..5) */
|
||||||
static uint8_t s_saved; /* 保存行值:0 = "ENTER",1 = "OK",2 = "ERR" */
|
|
||||||
|
|
||||||
/* 函数定义区 */
|
/* 函数定义区 */
|
||||||
|
|
||||||
@@ -117,7 +121,8 @@ static void nc_fmt_value(uint16_t row, char *p_buf) {
|
|||||||
* 返回值:无
|
* 返回值:无
|
||||||
* 限定条件:页面打开(框架绘制链内逐行调用)
|
* 限定条件:页面打开(框架绘制链内逐行调用)
|
||||||
* 函数说明:地址行值取 net_cfg RAM 副本(MAC 全零时显示芯片实际 MAC 影子);
|
* 函数说明:地址行值取 net_cfg RAM 副本(MAC 全零时显示芯片实际 MAC 影子);
|
||||||
* 保存行值随 s_saved 态显示 ENTER/OK/ERR
|
* 保存行值随保存交接状态(net_cfg_save_state)显示
|
||||||
|
* ENTER/WAIT/OK/ERR
|
||||||
*/
|
*/
|
||||||
static void nc_refresh(uint16_t row, char *name, char *value) {
|
static void nc_refresh(uint16_t row, char *name, char *value) {
|
||||||
const net_cfg_t *cfg = net_cfg_get();
|
const net_cfg_t *cfg = net_cfg_get();
|
||||||
@@ -144,12 +149,19 @@ static void nc_refresh(uint16_t row, char *name, char *value) {
|
|||||||
break;
|
break;
|
||||||
case 4u:
|
case 4u:
|
||||||
(void)memcpy(name, "保存", sizeof("保存"));
|
(void)memcpy(name, "保存", sizeof("保存"));
|
||||||
if (s_saved == 0u) {
|
switch (net_cfg_save_state()) {
|
||||||
(void)memcpy(value, "ENTER", sizeof("ENTER"));
|
case NET_CFG_SAVE_ST_WAIT:
|
||||||
} else if (s_saved == 1u) {
|
(void)memcpy(value, "WAIT", sizeof("WAIT"));
|
||||||
(void)memcpy(value, "OK", sizeof("OK"));
|
break;
|
||||||
} else {
|
case NET_CFG_SAVE_ST_OK:
|
||||||
(void)memcpy(value, "ERR", sizeof("ERR"));
|
(void)memcpy(value, "OK", sizeof("OK"));
|
||||||
|
break;
|
||||||
|
case NET_CFG_SAVE_ST_FAIL:
|
||||||
|
(void)memcpy(value, "ERR", sizeof("ERR"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
(void)memcpy(value, "ENTER", sizeof("ENTER"));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -163,7 +175,7 @@ static void nc_refresh(uint16_t row, char *name, char *value) {
|
|||||||
* delta - 调整方向(>0 = +1,<0 = -1) int8_t
|
* delta - 调整方向(>0 = +1,<0 = -1) int8_t
|
||||||
* 返回值:无
|
* 返回值:无
|
||||||
* 限定条件:编辑模式(s_cursor 有效)
|
* 限定条件:编辑模式(s_cursor 有效)
|
||||||
* 函数说明:只改 RAM 副本;写盘须显式经保存行 net_cfg_save
|
* 函数说明:只改 RAM 副本;写盘须显式经保存行投递 net_cfg_save_request
|
||||||
*/
|
*/
|
||||||
static void nc_adjust_octet(uint16_t row, int8_t delta) {
|
static void nc_adjust_octet(uint16_t row, int8_t delta) {
|
||||||
net_cfg_t cfg = *net_cfg_get();
|
net_cfg_t cfg = *net_cfg_get();
|
||||||
@@ -260,8 +272,10 @@ static void nc_draw_cb(lv_layer_t *layer, const lv_area_t *clip) {
|
|||||||
* (值已实时落 RAM 副本);ESC 恒关页(框架保证,未保存调整留在
|
* (值已实时落 RAM 副本);ESC 恒关页(框架保证,未保存调整留在
|
||||||
* RAM,下次开页重显、不写盘、重启失效)
|
* RAM,下次开页重显、不写盘、重启失效)
|
||||||
* 2. 正常模式:ENTER 地址行 → 进编辑模式(需可编辑权限);ENTER
|
* 2. 正常模式:ENTER 地址行 → 进编辑模式(需可编辑权限);ENTER
|
||||||
* 保存行 → net_cfg_save(需可编辑权限);↑↓ 落框架移选、
|
* 保存行 → 投递保存请求 net_cfg_save_request(需可编辑权限;
|
||||||
* ← 落框架关页;只读态 ENTER 一律忽略
|
* 写盘与"立即应用"由属主任务 defaultTask 执行,保存行随交接
|
||||||
|
* 状态显示 WAIT/OK/ERR);↑↓ 落框架移选、← 落框架关页;
|
||||||
|
* 只读态 ENTER 一律忽略
|
||||||
*/
|
*/
|
||||||
static bool nc_key_cb(lv_key_t key) {
|
static bool nc_key_cb(lv_key_t key) {
|
||||||
uint16_t sel = ui_content_page_selected_row();
|
uint16_t sel = ui_content_page_selected_row();
|
||||||
@@ -309,10 +323,7 @@ static bool nc_key_cb(lv_key_t key) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (sel == NC_SAVE_ROW) {
|
if (sel == NC_SAVE_ROW) {
|
||||||
s_saved = (net_cfg_save() == 0) ? 1u : 2u;
|
(void)net_cfg_save_request(); /* 投递保存请求:属主任务写盘并立即应用 */
|
||||||
if (s_saved == 1u) {
|
|
||||||
net_cfg_request_apply(); /* 立即应用:通知 netTask 重建网络(无需重启) */
|
|
||||||
}
|
|
||||||
ui_content_page_invalidate();
|
ui_content_page_invalidate();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -332,7 +343,6 @@ static bool nc_key_cb(lv_key_t key) {
|
|||||||
static void nc_init_cb(void) {
|
static void nc_init_cb(void) {
|
||||||
s_editing = 0u;
|
s_editing = 0u;
|
||||||
s_cursor = 0u;
|
s_cursor = 0u;
|
||||||
s_saved = 0u;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ powershell -ExecutionPolicy Bypass -File test\run_boot_test.ps1
|
|||||||
通过仓库内置 Python 串口助手(`tools/serial_tool/`)自主读取 USART1 串口打印:
|
通过仓库内置 Python 串口助手(`tools/serial_tool/`)自主读取 USART1 串口打印:
|
||||||
|
|
||||||
- 端口配置:`.opencode/serial_config.json`(单一配置源)
|
- 端口配置:`.opencode/serial_config.json`(单一配置源)
|
||||||
- 详见 `docs/测试说明/串口助手设计说明.md`
|
- 用法详见 `docs/测试说明/串口助手使用指南.md`,设计见 `docs/测试说明/串口助手设计说明.md`
|
||||||
|
|
||||||
## 开发规范
|
## 开发规范
|
||||||
|
|
||||||
|
|||||||
+40
-7
@@ -39,6 +39,8 @@
|
|||||||
#include "time_sync.h"
|
#include "time_sync.h"
|
||||||
#include "sys_events.h"
|
#include "sys_events.h"
|
||||||
#include "sys_log.h"
|
#include "sys_log.h"
|
||||||
|
#include "net_cfg.h"
|
||||||
|
#include "cfg_file.h"
|
||||||
/* USER CODE END Includes */
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
/* Private typedef -----------------------------------------------------------*/
|
/* Private typedef -----------------------------------------------------------*/
|
||||||
@@ -114,6 +116,7 @@ const osEventFlagsAttr_t sys_evt_attributes = {
|
|||||||
/* Private function prototypes -----------------------------------------------*/
|
/* Private function prototypes -----------------------------------------------*/
|
||||||
/* USER CODE BEGIN FunctionPrototypes */
|
/* USER CODE BEGIN FunctionPrototypes */
|
||||||
void ui_task_func(void *argument);
|
void ui_task_func(void *argument);
|
||||||
|
static void default_task_net_cfg_save_notify(void);
|
||||||
/* USER CODE END FunctionPrototypes */
|
/* USER CODE END FunctionPrototypes */
|
||||||
|
|
||||||
void StartDefaultTask(void *argument);
|
void StartDefaultTask(void *argument);
|
||||||
@@ -171,10 +174,10 @@ void MX_FREERTOS_Init(void) {
|
|||||||
uiTaskHandle = osThreadNew(StartUiTask, NULL, &uiTask_attributes);
|
uiTaskHandle = osThreadNew(StartUiTask, NULL, &uiTask_attributes);
|
||||||
|
|
||||||
/* USER CODE BEGIN RTOS_THREADS */
|
/* USER CODE BEGIN RTOS_THREADS */
|
||||||
#ifdef ENABLE_NET_LAYER_TESTS
|
/* netTask = 基础线程:上方生成区的实例是全构建唯一实例(P1-6:旧
|
||||||
/* NET 层测试模式(阶段 6~10):完整网络栈,netTask 负责轮询与消息处理 */
|
* #ifdef ENABLE_NET_LAYER_TESTS 的重复创建已删除)。
|
||||||
netTaskHandle = osThreadNew(StartNetTask, NULL, &netTask_attributes);
|
* - 产品 / NET 层测试模式:正常运行 bring_up + net_poll
|
||||||
#endif
|
* - CH395F 硬件层测试模式:net_task_func 入口自挂起(testTask 独占 CH395F) */
|
||||||
|
|
||||||
/* 本地时间同步任务(PC 推送 TCP):依赖 netTask 处理消息队列 */
|
/* 本地时间同步任务(PC 推送 TCP):依赖 netTask 处理消息队列 */
|
||||||
timeSyncTaskHandle = osThreadNew(time_sync_task, NULL, &timeSyncTask_attributes);
|
timeSyncTaskHandle = osThreadNew(time_sync_task, NULL, &timeSyncTask_attributes);
|
||||||
@@ -225,7 +228,11 @@ void StartDefaultTask(void *argument)
|
|||||||
DBG_INFO("[FS] FATFS mounted");
|
DBG_INFO("[FS] FATFS mounted");
|
||||||
/* 日志引擎挂载后处理:建 /log 目录 + 写"上电/重启"分类记录(唯一写者) */
|
/* 日志引擎挂载后处理:建 /log 目录 + 写"上电/重启"分类记录(唯一写者) */
|
||||||
syslog_mcu_mounted();
|
syslog_mcu_mounted();
|
||||||
/* 广播"存储就绪",唤醒依赖文件系统的任务 */
|
/* 加载网络配置进 RAM 副本(配置引擎属主 = 本任务;首启含旧档迁移;
|
||||||
|
* 文件缺失/损坏 = 工厂默认,不阻塞组网)。须在置位 STORAGE_READY 前,
|
||||||
|
* 使"存储就绪"屏障蕴含"配置已就绪",netTask 组网时配置恒有效 */
|
||||||
|
(void)net_cfg_load();
|
||||||
|
/* 广播"存储就绪"(= 卷挂载 + 配置加载完成),唤醒依赖文件系统的任务 */
|
||||||
if (sys_evtHandle != NULL) {
|
if (sys_evtHandle != NULL) {
|
||||||
osEventFlagsSet(sys_evtHandle, SYS_EVT_STORAGE_READY);
|
osEventFlagsSet(sys_evtHandle, SYS_EVT_STORAGE_READY);
|
||||||
}
|
}
|
||||||
@@ -235,13 +242,30 @@ void StartDefaultTask(void *argument)
|
|||||||
syslog_post(SYSLOG_SELFTEST, "文件系统异常");
|
syslog_post(SYSLOG_SELFTEST, "文件系统异常");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 注册"保存网络配置"请求通知:UI(uiTask)投递 → 置事件 → 本任务立即执行写盘
|
||||||
|
* (配置引擎属主 = 本任务;UI 保存不再直接触碰配置文件引擎,P1-3) */
|
||||||
|
net_cfg_set_save_req_cb(default_task_net_cfg_save_notify);
|
||||||
|
|
||||||
|
/* 配置 poll 周期计数(每 4 次循环 = 2s 轮询一次,与引擎文档/模拟器一致) */
|
||||||
|
uint32_t cfg_poll_cnt = 0u;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
/* 等待"保存网络配置"请求:有请求立即唤醒;无请求 500ms 后返回
|
||||||
|
* (取代原 osDelay(500):循环节奏不变,保存响应零空转) */
|
||||||
|
if (sys_evtHandle != NULL) {
|
||||||
|
(void)osEventFlagsWait(sys_evtHandle, SYS_EVT_CFG_SAVE, osFlagsWaitAny, 500u);
|
||||||
|
}
|
||||||
|
/* 执行待处理保存(配置引擎属主:写盘 + 成功后立即应用);无请求 = 空操作 */
|
||||||
|
net_cfg_save_run();
|
||||||
|
/* 配置文件变更轮询(2s 周期;沉降去抖在引擎内) */
|
||||||
|
if ((cfg_poll_cnt++ & 3u) == 0u) {
|
||||||
|
cfg_file_poll();
|
||||||
|
}
|
||||||
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
|
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
|
||||||
HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
|
HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
|
||||||
HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin);
|
HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin);
|
||||||
/* 排空运行期日志(上电/重启分类与自检故障落盘) */
|
/* 排空运行期日志(上电/重启分类与自检故障落盘) */
|
||||||
syslog_drain();
|
syslog_drain();
|
||||||
osDelay(500);
|
|
||||||
}
|
}
|
||||||
/* USER CODE END StartDefaultTask */
|
/* USER CODE END StartDefaultTask */
|
||||||
}
|
}
|
||||||
@@ -325,5 +349,14 @@ void StartUiTask(void *argument)
|
|||||||
|
|
||||||
/* Private application code --------------------------------------------------*/
|
/* Private application code --------------------------------------------------*/
|
||||||
/* USER CODE BEGIN Application */
|
/* USER CODE BEGIN Application */
|
||||||
|
/*
|
||||||
|
* "保存网络配置"请求通知(注册给 net_cfg 的保存交接):
|
||||||
|
* uiTask 投递保存请求 → 置 SYS_EVT_CFG_SAVE → defaultTask 循环立即唤醒执行写盘
|
||||||
|
*/
|
||||||
|
static void default_task_net_cfg_save_notify(void)
|
||||||
|
{
|
||||||
|
if (sys_evtHandle != NULL) {
|
||||||
|
(void)osEventFlagsSet(sys_evtHandle, SYS_EVT_CFG_SAVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
/* USER CODE END Application */
|
/* USER CODE END Application */
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ PC 模拟器(`simulator/`,CMake + SDL2)与 MCU 端共用同一份上层网
|
|||||||
| 错误码 | CH395F 状态码映射 | `WSAGetLastError()` 映射(`WSAEWOULDBLOCK` → `NET_ERR_WOULDBLOCK`) |
|
| 错误码 | CH395F 状态码映射 | `WSAGetLastError()` 映射(`WSAEWOULDBLOCK` → `NET_ERR_WOULDBLOCK`) |
|
||||||
| select/poll | `net_select.c` 参与编译 | 未编译(上层不依赖) |
|
| select/poll | `net_select.c` 参与编译 | 未编译(上层不依赖) |
|
||||||
|
|
||||||
> **模拟器端网络启动**(镜像 MCU 端 netTask 上电流程,见 `simulator/main.c`):`WSAStartup` → `net_cfg_load()`(网口配置 RAM 副本)→ `ui_net_sink_start(7003)`(RemoDispBus TCP 监听,与 MCU 端同端口)→ 主循环 `ui_net_sink_poll()`(非阻塞协议收发)。不调用 `net_init()`——WSA 初始化由 `net_socket_sim.c` 内部 `ensure_wsa()` 幂等保证,`net_init()` 仅为对齐 API 而保留(上层代码双端统一调用)。
|
> **模拟器端网络启动**(镜像 MCU 端上电流程:defaultTask 在就绪屏障前加载 `net_cfg`,见 `simulator/main.c`):`WSAStartup` → `net_cfg_load()`(网口配置 RAM 副本,失败回退工厂默认)→ `ui_net_sink_start(7003)`(RemoDispBus TCP 监听,与 MCU 端同端口)→ 主循环 `ui_net_sink_poll()`(非阻塞协议收发)+ `net_cfg_save_run()`(执行 UI 保存请求,主循环 = 配置引擎属主)。不调用 `net_init()`——WSA 初始化由 `net_socket_sim.c` 内部 `ensure_wsa()` 幂等保证,`net_init()` 仅为对齐 API 而保留(上层代码双端统一调用)。
|
||||||
|
|
||||||
### 2.4 Socket 状态机
|
### 2.4 Socket 状态机
|
||||||
|
|
||||||
@@ -193,7 +193,8 @@ int main(void)
|
|||||||
/* 初始化网络子系统
|
/* 初始化网络子系统
|
||||||
* 参数:IP地址, 子网掩码, 网关, MAC(NULL 或全零 = 芯片内置 MAC)
|
* 参数:IP地址, 子网掩码, 网关, MAC(NULL 或全零 = 芯片内置 MAC)
|
||||||
* 传入 NULL 使用 DHCP 自动获取
|
* 传入 NULL 使用 DHCP 自动获取
|
||||||
* 本项目中由 netTask 在加载 net_cfg(Flash 网口配置)后调用
|
* 本项目中由 netTask 调用(网口配置已由 defaultTask 在就绪屏障前
|
||||||
|
* 加载进 RAM 副本,netTask 只读副本组网)
|
||||||
*/
|
*/
|
||||||
int ret = net_init("192.168.1.100", "255.255.255.0", "192.168.1.1", NULL);
|
int ret = net_init("192.168.1.100", "255.255.255.0", "192.168.1.1", NULL);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
@@ -1229,6 +1230,7 @@ CH395F 底层驱动返回的状态码(`ch395f_get_cmd_status()` 或 `ch395f_po
|
|||||||
|
|
||||||
| 日期 | 变更 |
|
| 日期 | 变更 |
|
||||||
|------|------|
|
|------|------|
|
||||||
|
| 2026-09-15 | 同步配置引擎属主变更(P1-3):`net_init` 调用方说明改为"netTask 只读 RAM 副本"(网口配置由 defaultTask 在就绪屏障前加载);模拟器端启动序列补 `net_cfg_save_run()`(主循环 = 模拟器侧配置引擎属主,执行 UI 保存请求) |
|
||||||
| 2026-09-13 | 从 git 历史恢复(`4e9ac0d` 2026-08-28 误删);同步当前代码:`net_init` 4 参数(新增 `mac`)、`net_socket` 2 参数(移除 `protocol`)、新增 `net_get_generation` / `net_generation_inc` / `net_listen_locked`、`NET_NO_OS` 双端构建、netTask 周期 10ms → 1ms |
|
| 2026-09-13 | 从 git 历史恢复(`4e9ac0d` 2026-08-28 误删);同步当前代码:`net_init` 4 参数(新增 `mac`)、`net_socket` 2 参数(移除 `protocol`)、新增 `net_get_generation` / `net_generation_inc` / `net_listen_locked`、`NET_NO_OS` 双端构建、netTask 周期 10ms → 1ms |
|
||||||
| 2026-09-13 | 配图:§2.1 分层架构改 SVG 生成器产物(`tools/arch_diagram/gen_net_stack_svg.py` → `docs/images/BSD网络栈分层.svg`);§2.4 状态机、§3.2 消息队列时序改 Mermaid(状态名对齐代码 `net_sock_state_t`,补 `UDP_OPEN` / `auto_relisten` 迁移,修正旧 ASCII 图不准处) |
|
| 2026-09-13 | 配图:§2.1 分层架构改 SVG 生成器产物(`tools/arch_diagram/gen_net_stack_svg.py` → `docs/images/BSD网络栈分层.svg`);§2.4 状态机、§3.2 消息队列时序改 Mermaid(状态名对齐代码 `net_sock_state_t`,补 `UDP_OPEN` / `auto_relisten` 迁移,修正旧 ASCII 图不准处) |
|
||||||
| 2026-09-13 | 新增 §2.3「PC 模拟器端:net_socket_sim」(Winsock 后端、`NET_NO_OS` 裁剪清单、MCU/模拟器行为差异表、模拟器端启动序列);§2.2 文件表补模拟器后端行 |
|
| 2026-09-13 | 新增 §2.3「PC 模拟器端:net_socket_sim」(Winsock 后端、`NET_NO_OS` 裁剪清单、MCU/模拟器行为差异表、模拟器端启动序列);§2.2 文件表补模拟器后端行 |
|
||||||
|
|||||||
+2
-1
@@ -18,7 +18,7 @@
|
|||||||
| 装置信息 | node 1 | 静态信息页(6 行 + 副标题,不分页) | Flash 表 | `ui_page_device_info_desc` |
|
| 装置信息 | node 1 | 静态信息页(6 行 + 副标题,不分页) | Flash 表 | `ui_page_device_info_desc` |
|
||||||
| 交流量 | node 3 | 列表页(24 项,8 项/页,共 3 页) | Flash 表(第 1 页实测,2/3 页占位) | `ui_page_ac_desc` |
|
| 交流量 | node 3 | 列表页(24 项,8 项/页,共 3 页) | Flash 表(第 1 页实测,2/3 页占位) | `ui_page_ac_desc` |
|
||||||
| 直流量 | node 4 | 列表页(3 项,单页) | Flash 表 | `ui_page_dc_desc` |
|
| 直流量 | node 4 | 列表页(3 项,单页) | Flash 表 | `ui_page_dc_desc` |
|
||||||
| 网口设置 | node 30(通讯参数子项) | 列表页(5 行 1 页,动态值)+ 可编辑(`edit_capable`,↑↓调字节/←→移光标/ENTER 确认;保存行 ENTER → 写 Flash,下次上电生效) | `net_cfg` RAM 副本(netTask 上电自 Flash 加载) | `ui_page_net_cfg_desc` |
|
| 网口设置 | node 30(通讯参数子项) | 列表页(5 行 1 页,动态值)+ 可编辑(`edit_capable`,↑↓调字节/←→移光标/ENTER 确认;保存行 ENTER → 投递保存请求,属主任务 defaultTask 写盘 + 立即应用(免重启),行值随交接状态 ENTER/WAIT/OK/ERR) | `net_cfg` RAM 副本(defaultTask 上电自 Flash 加载;netTask 回写实际 MAC 影子) | `ui_page_net_cfg_desc` |
|
||||||
| 用户密钥 | 需密码叶子(如 node 8 参数) | 表单/操作页(draw_cb + key_cb;无行、无"浅 V"、无页脚) | arm 装载:完成回调(携授予权限);页面比对两个编译期密码 | `ui_page_password_desc` |
|
| 用户密钥 | 需密码叶子(如 node 8 参数) | 表单/操作页(draw_cb + key_cb;无行、无"浅 V"、无页脚) | arm 装载:完成回调(携授予权限);页面比对两个编译期密码 | `ui_page_password_desc` |
|
||||||
|
|
||||||
设计核心是 **"框架 + 页面插件"**:框架 `ui_content_page` 只持**机制**(屏/容器生命周期、焦点、
|
设计核心是 **"框架 + 页面插件"**:框架 `ui_content_page` 只持**机制**(屏/容器生命周期、焦点、
|
||||||
@@ -478,3 +478,4 @@ extern const content_page_def_t ui_page_device_info_desc; /* 描述符(Flash
|
|||||||
| 2026-09-10 | 修复网口设置页编辑态渲染 bug:光标段原传整串 `value + start`,而 `lv_draw_label` 按 `coords`(光标盒,仅段宽)折行 → 逐行向盒下方绘制、溢出到其它行与空白区("下方弹出一串字符")。改为只传**段文本**(IP/掩码/网关 3 字符、MAC 2 字符);§3.5 补"`lv_draw_label` 折行陷阱"说明 |
|
| 2026-09-10 | 修复网口设置页编辑态渲染 bug:光标段原传整串 `value + start`,而 `lv_draw_label` 按 `coords`(光标盒,仅段宽)折行 → 逐行向盒下方绘制、溢出到其它行与空白区("下方弹出一串字符")。改为只传**段文本**(IP/掩码/网关 3 字符、MAC 2 字符);§3.5 补"`lv_draw_label` 折行陷阱"说明 |
|
||||||
| 2026-09-10 | 网口设置页 MAC 值改常识格式 **`A4:94:B6:12:34:56`**(冒号分隔,17 字符 = 102px);布局调整 名 x=6→4、值 x=60→54(MAC ink 止于 155,仍在白带 2..157 内);编辑光标段偏移 MAC 2i→3i |
|
| 2026-09-10 | 网口设置页 MAC 值改常识格式 **`A4:94:B6:12:34:56`**(冒号分隔,17 字符 = 102px);布局调整 名 x=6→4、值 x=60→54(MAC ink 止于 155,仍在白带 2..157 内);编辑光标段偏移 MAC 2i→3i |
|
||||||
| 2026-09-14 | 运行记录/自检记录动态列表页(`ui_page_runlog` / `ui_page_selftest`):描述符新增 `count_cb` + `refresh`(开页/翻页时重读条数与内容,每条 2 行 = 时间戳/描述),数据源为 `App/log/sys_log` 引擎的 `/log/run.log`、`/log/selftest.log`;**框架不变量 selectable ⇒ band_h>0**——band_h=0 时选中行恒黑字无白带 → 黑底不可见(首版两页均踩中,改 band_h=13 对齐 AC/DC 约定);新坑:本 LVGL 版本 `lv_text_get_width` length≠0 时无 NUL 检查,传 -1 越串尾死循环,必须传 strlen(密码页错误提示首版触发,已修并全库排查) |
|
| 2026-09-14 | 运行记录/自检记录动态列表页(`ui_page_runlog` / `ui_page_selftest`):描述符新增 `count_cb` + `refresh`(开页/翻页时重读条数与内容,每条 2 行 = 时间戳/描述),数据源为 `App/log/sys_log` 引擎的 `/log/run.log`、`/log/selftest.log`;**框架不变量 selectable ⇒ band_h>0**——band_h=0 时选中行恒黑字无白带 → 黑底不可见(首版两页均踩中,改 band_h=13 对齐 AC/DC 约定);新坑:本 LVGL 版本 `lv_text_get_width` length≠0 时无 NUL 检查,传 -1 越串尾死循环,必须传 strlen(密码页错误提示首版触发,已修并全库排查) |
|
||||||
|
| 2026-09-15 | 网口设置页保存行改**异步交接**(P1-3 跨任务竞态修复,配置引擎属主 = defaultTask):保存行 ENTER → `net_cfg_save_request()`(置"待保存"标志 + `SYS_EVT_CFG_SAVE` 唤醒属主任务,UI 不再直接触碰 cfg_file 引擎);写盘与"立即应用"由 defaultTask 的 `net_cfg_save_run()` 执行(成功 → OK 并触发 `SYS_EVT_NET_RECONFIG` 免重启重建;失败 → ERR 不触发应用);行值改随交接状态 `net_cfg_save_state()` 显示 ENTER/WAIT/OK/ERR(原为页面局部 `s_saved` 同步结果,删除);无头自检(`--keys`)在注键后同步完成交接保持终态一致;五门禁全绿(像素/文本与改前一致,池水位不变) |
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<rect x="428" y="227" width="30" height="30" rx="7" fill="#16a34a"/>
|
<rect x="428" y="227" width="30" height="30" rx="7" fill="#16a34a"/>
|
||||||
<text x="443" y="247" font-size="14" font-weight="700" fill="#ffffff" text-anchor="middle">1</text>
|
<text x="443" y="247" font-size="14" font-weight="700" fill="#ffffff" text-anchor="middle">1</text>
|
||||||
<text x="470" y="236" font-size="14" font-weight="700" fill="#16a34a">bit1 · STORAGE_READY</text>
|
<text x="470" y="236" font-size="14" font-weight="700" fill="#16a34a">bit1 · STORAGE_READY</text>
|
||||||
<text x="470" y="258" font-size="12" fill="#64748b">defaultTask 置位 · netTask / ftpTask 等待</text>
|
<text x="470" y="258" font-size="12" fill="#64748b">defaultTask 置位(挂载+配置)· netTask / ftpTask 等待</text>
|
||||||
<rect x="414" y="310" width="392" height="84" rx="10" fill="#f0fdfa" stroke="#0d9488" stroke-opacity="0.6"/>
|
<rect x="414" y="310" width="392" height="84" rx="10" fill="#f0fdfa" stroke="#0d9488" stroke-opacity="0.6"/>
|
||||||
<rect x="428" y="337" width="30" height="30" rx="7" fill="#0d9488"/>
|
<rect x="428" y="337" width="30" height="30" rx="7" fill="#0d9488"/>
|
||||||
<text x="443" y="357" font-size="14" font-weight="700" fill="#ffffff" text-anchor="middle">0</text>
|
<text x="443" y="357" font-size="14" font-weight="700" fill="#ffffff" text-anchor="middle">0</text>
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
<text x="470" y="588" font-size="12" fill="#64748b">预留(尚未接入调度)</text>
|
<text x="470" y="588" font-size="12" fill="#64748b">预留(尚未接入调度)</text>
|
||||||
<rect x="40" y="200" width="290" height="84" rx="10" fill="#eff6ff" stroke="#2563eb" stroke-opacity="0.5"/>
|
<rect x="40" y="200" width="290" height="84" rx="10" fill="#eff6ff" stroke="#2563eb" stroke-opacity="0.5"/>
|
||||||
<text x="56" y="234" font-size="15" font-weight="700" fill="#0f172a">defaultTask</text>
|
<text x="56" y="234" font-size="15" font-weight="700" fill="#0f172a">defaultTask</text>
|
||||||
<text x="56" y="258" font-size="12" fill="#64748b">FatFS 挂载(f_mount / f_mkfs)</text>
|
<text x="56" y="258" font-size="12" fill="#64748b">卷挂载 + net_cfg_load(f_mount)</text>
|
||||||
<polyline points="330.0,242.0 400.0,242.0" fill="none" stroke="#16a34a" stroke-width="2.2" stroke-linejoin="round"/>
|
<polyline points="330.0,242.0 400.0,242.0" fill="none" stroke="#16a34a" stroke-width="2.2" stroke-linejoin="round"/>
|
||||||
<path d="M 400.0 242.0 L 389.0 247.5 L 389.0 236.5 z" fill="#16a34a"/>
|
<path d="M 400.0 242.0 L 389.0 247.5 L 389.0 236.5 z" fill="#16a34a"/>
|
||||||
<text x="365" y="234.0" font-size="11.5" fill="#16a34a" text-anchor="middle">set bit1</text>
|
<text x="365" y="234.0" font-size="11.5" fill="#16a34a" text-anchor="middle">set bit1</text>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
@@ -84,7 +84,7 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
|||||||
|
|
||||||
| 构建模式 | 启用宏 | 固件形态 |
|
| 构建模式 | 启用宏 | 固件形态 |
|
||||||
|----------|--------|----------|
|
|----------|--------|----------|
|
||||||
| **硬件层模式** | `ENABLE_PHASE1~5_TESTS` | **netTask 不创建**,CH395F 协议栈初始化由 ch395fTestTask 完成后独占芯片执行阶段 1~5(裸调 `ch395f_*` 命令) |
|
| **硬件层模式** | `ENABLE_PHASE1~5_TESTS` | netTask 自挂起(基础线程创建但不运行),CH395F 协议栈初始化由 testTask 完成后独占芯片执行阶段 1~5(裸调 `ch395f_*` 命令) |
|
||||||
| **NET 层模式** | `ENABLE_PHASE6~11_TESTS` | 完整网络栈:netTask 运行 `net_poll()` 轮询,testTask 经 `net_socket` API 执行阶段 6~11(`net_layer_test_main()` 回显、`net_layer_client_test_main()` Client 等) |
|
| **NET 层模式** | `ENABLE_PHASE6~11_TESTS` | 完整网络栈:netTask 运行 `net_poll()` 轮询,testTask 经 `net_socket` API 执行阶段 6~11(`net_layer_test_main()` 回显、`net_layer_client_test_main()` Client 等) |
|
||||||
|
|
||||||
**执行顺序严格递增**:先烧录硬件层固件完成阶段 1→2→3→4→5(全部通过),再切换为 NET 层固件执行阶段 6→7→…→11。硬件层测试期间 netTask 轮询不存在,从根上排除中断偷取与 SPI 并发问题。
|
**执行顺序严格递增**:先烧录硬件层固件完成阶段 1→2→3→4→5(全部通过),再切换为 NET 层固件执行阶段 6→7→…→11。硬件层测试期间 netTask 轮询不存在,从根上排除中断偷取与 SPI 并发问题。
|
||||||
@@ -143,7 +143,7 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
|||||||
| **入口** | `ch395fTestTask` 启动后自动运行 |
|
| **入口** | `ch395fTestTask` 启动后自动运行 |
|
||||||
| **出口** | 串口 "Phase 2 Tests Complete" 且 0 失败 |
|
| **出口** | 串口 "Phase 2 Tests Complete" 且 0 失败 |
|
||||||
|
|
||||||
**分层说明**:本阶段属于**硬件层模式**(netTask 不创建,CH395F 由 ch395fTestTask 独占),仅使用 `ch395f_*` 裸命令验证芯片 TCP Client 行为:TCP 状态机、`CH395F_SINT_STAT_CONNECT` / `CH395F_SINT_STAT_SOCK_TIMEOUT` 中断、发送/接收缓冲与 `CH395F_SOCKET_CLOSED` 状态流转。
|
**分层说明**:本阶段属于**硬件层模式**(netTask 自挂起,CH395F 由 testTask 独占),仅使用 `ch395f_*` 裸命令验证芯片 TCP Client 行为:TCP 状态机、`CH395F_SINT_STAT_CONNECT` / `CH395F_SINT_STAT_SOCK_TIMEOUT` 中断、发送/接收缓冲与 `CH395F_SOCKET_CLOSED` 状态流转。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
|||||||
| **入口** | `ENABLE_PHASE3_TESTS`,ch395fTestTask 启动后自动运行 |
|
| **入口** | `ENABLE_PHASE3_TESTS`,ch395fTestTask 启动后自动运行 |
|
||||||
| **出口** | 串口 "Phase 3 Tests Complete" 且 0 失败 |
|
| **出口** | 串口 "Phase 3 Tests Complete" 且 0 失败 |
|
||||||
|
|
||||||
**分层说明**:本阶段属于**硬件层模式**(netTask 不创建),仅用 `ch395f_*` 裸命令验证芯片 UDP 能力:UDP Socket 打开、数据报接收、**包头源地址解析**与按源地址动态回显。
|
**分层说明**:本阶段属于**硬件层模式**(netTask 自挂起),仅用 `ch395f_*` 裸命令验证芯片 UDP 能力:UDP Socket 打开、数据报接收、**包头源地址解析**与按源地址动态回显。
|
||||||
|
|
||||||
> CH395F UDP 接收帧格式(`ch395f_read_recv_buf` 返回):[0-1] 保留|[2-3] 源端口(大端)|[4-7] 源 IP|[8+] 载荷。回显前须以此源地址重设目标,且每次发送后等 `SENDBUF_FREE` 确认(Trap 04)。
|
> CH395F UDP 接收帧格式(`ch395f_read_recv_buf` 返回):[0-1] 保留|[2-3] 源端口(大端)|[4-7] 源 IP|[8+] 载荷。回显前须以此源地址重设目标,且每次发送后等 `SENDBUF_FREE` 确认(Trap 04)。
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,371 @@
|
|||||||
|
# Python 串口助手(serial_tool)使用指南
|
||||||
|
|
||||||
|
> **定位**:面向使用者的操作手册——命令怎么敲、输出怎么看、常见场景怎么组合、出问题怎么排查。
|
||||||
|
> **关联文档**:设计决策与实现细节见 `串口助手设计说明.md`;@test 自动化闭环见 `自动化测试流程.md`;`AGENTS.md`「串口调试」节有一页速查。
|
||||||
|
> **版本**:v1.1(与 `tools/serial_tool/serial_tool.py` 当前实现一致,2026-09-15)
|
||||||
|
|
||||||
|
## 1. 它是什么(60 秒版)
|
||||||
|
|
||||||
|
仓库内置的串口调试工具,三个组成部分:
|
||||||
|
|
||||||
|
| 组成 | 是什么 | 你要知道的 |
|
||||||
|
|---|---|---|
|
||||||
|
| **常驻 daemon** | 后台 Python 进程,**串口唯一持有者**,把 RX/TX 持续写进日志文件 | 不用管它——任何命令发现它没在跑会**自动拉起** |
|
||||||
|
| **薄 CLI** | `serial_tool.py <命令>`,每条命令都是带 5s 硬超时的短操作 | 你唯一直接打交道的界面 |
|
||||||
|
| **日志文件** | `tools/serial_tool/state/serial.log`,**全量历史就在这里** | 想回看任何时刻的数据 → 直接读这个文件 |
|
||||||
|
|
||||||
|
**统一入口**(仓库根目录执行,任意 cwd 均可):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
& '.venv\Scripts\python.exe' 'tools/serial_tool/serial_tool.py' <命令> [参数]
|
||||||
|
```
|
||||||
|
|
||||||
|
两条心法:
|
||||||
|
1. **所有输出都是 JSON**(stdout),退出码 0=成功 / 1=领域错误 / 2=daemon 不可达 / 3=用法错误;
|
||||||
|
2. **历史不用"采集"**——daemon 一直在写日志文件,随时 Read/Grep 就是完整历史。
|
||||||
|
|
||||||
|
## 2. 快速上手
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# ① 看本机有哪些 COM 口(不依赖 daemon;configured = 配置目标口)
|
||||||
|
& '.venv\Scripts\python.exe' 'tools/serial_tool/serial_tool.py' ports
|
||||||
|
|
||||||
|
# ② 开串口(自动拉起 daemon;端口取 .opencode/serial_config.json,也可显式指定)
|
||||||
|
& '.venv\Scripts\python.exe' 'tools/serial_tool/serial_tool.py' open
|
||||||
|
|
||||||
|
# ③ 发一条数据(文本;--hex 发字节;--nl 末尾加 CRLF)
|
||||||
|
& '.venv\Scripts\python.exe' 'tools/serial_tool/serial_tool.py' send "hello" --nl
|
||||||
|
|
||||||
|
# ④ 看最近 20 行日志(含刚发的 TX 和收到的 RX)
|
||||||
|
& '.venv\Scripts\python.exe' 'tools/serial_tool/serial_tool.py' log --tail 20
|
||||||
|
|
||||||
|
# ⑤ 不用了:关串口(daemon 继续常驻;要彻底退出用 stop)
|
||||||
|
& '.venv\Scripts\python.exe' 'tools/serial_tool/serial_tool.py' close
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 命令速查
|
||||||
|
|
||||||
|
| 命令 | 作用 | 依赖 daemon |
|
||||||
|
|---|---|---|
|
||||||
|
| `ports` | 枚举 COM 口,标注配置目标口 | 否(本地执行) |
|
||||||
|
| `open` | 开串口(**幂等**:同口已开 = 直接成功) | 是(未运行自动拉起) |
|
||||||
|
| `close` | 关串口 | 是 |
|
||||||
|
| `send` | 发 TX 字节(进日志) | 是 |
|
||||||
|
| `status` | 全状态一条 JSON | 是 |
|
||||||
|
| `log` | 读日志文件(`--tail N` / `--grep P`) | **否**(直接读文件,daemon 死了也能用) |
|
||||||
|
| `clear` | 清空日志 + 代际 +1 | 是 |
|
||||||
|
| `wait-idle` | 等 RX 静默(@test 的收尾判据) | 是 |
|
||||||
|
| `start` / `stop` / `restart` | daemon 生命周期 | — |
|
||||||
|
| `selftest` | 无头自检(行拆分/解码/截头算法,无需硬件) | 否 |
|
||||||
|
|
||||||
|
所有命令都支持 `--timeout <秒>`(默认 5)覆盖 CLI→daemon 硬超时。
|
||||||
|
|
||||||
|
### 3.1 `ports` — 枚举串口
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py ports
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"ok": true,
|
||||||
|
"ports": [{"name": "COM1", "description": "通信端口 (COM1)", "hwid": "ACPI\\PNP0501\\0"}, …],
|
||||||
|
"configured": "COM6"}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `configured` 来自 `.opencode/serial_config.json` 的 `portName`;找不到它 = 板子没接/驱动没装/口号变了。
|
||||||
|
- CH340 的 `description` 通常含"USB 串行设备"字样。
|
||||||
|
|
||||||
|
### 3.2 `open` — 开串口
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py open # 端口/波特率取配置文件
|
||||||
|
... serial_tool.py open --port COM6 --baud 115200
|
||||||
|
... serial_tool.py open --dtr 1 --rts 0 # 显式置位(默认都不翻转,见下)
|
||||||
|
```
|
||||||
|
|
||||||
|
- **幂等**:同端口同波特率已开 → 直接返回成功(`note: already open`),不会重开端口。
|
||||||
|
- **DTR/RTS 默认不翻转**——防 STM32 自动复位电路把目标板误复位;确需翻转才用 `--dtr 1` / `--rts 1`。
|
||||||
|
- 成功返回:`{"ok":true,"port":"COM6","baud":115200,"dtr":false,"rts":false,"gen":7,"since":"…ISO…"}`。
|
||||||
|
- 失败(**≤1s 快速返回**,exit 1):
|
||||||
|
|
||||||
|
| 错误 | 含义 |
|
||||||
|
|---|---|
|
||||||
|
| `port not found: COM6 (available: COM1, …)` | 该口不存在(Windows 对此常报 Access Denied,工具已按端口枚举结果纠正判定) |
|
||||||
|
| `port busy: COM1 (held by another process)` | 口被其他进程占用 |
|
||||||
|
|
||||||
|
- **重开退避**:距上次关口/daemon 启动 <1.5s 时,open 会先等待再开(CH340"释放后立即重开 → 读 0 字节"陷阱的规避)。
|
||||||
|
|
||||||
|
### 3.3 `close` — 关串口
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py close # → {"ok":true}
|
||||||
|
```
|
||||||
|
|
||||||
|
未开时返回 `{"ok":true,"note":"port not open"}`(不算错误)。daemon 继续运行。
|
||||||
|
|
||||||
|
### 3.4 `send` — 发数据
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py send "hello" # 文本(UTF-8 编码发出,精确字节,不加换行)
|
||||||
|
... serial_tool.py send "hello" --nl # 末尾追加 CRLF
|
||||||
|
... serial_tool.py send --hex 0D0A # 发字节 0x0D 0x0A(支持空格分隔:0D 0A 亦可)
|
||||||
|
... serial_tool.py send --hex 48454C4C4F # = "HELLO"
|
||||||
|
```
|
||||||
|
|
||||||
|
- 文本与 `--hex` **二选一**;都不给 = 用法错误(exit 3)。
|
||||||
|
- 成功返回:`{"ok":true,"bytes":7}`(实际发出字节数)。
|
||||||
|
- 端口未开 → `port not open (run 'open' first)`。
|
||||||
|
- 日志中的 TX 行会把控制字符转义成字面文本(`…hello\r\n`),保持日志行式完整。
|
||||||
|
|
||||||
|
### 3.5 `status` — 全状态
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py status
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"daemon": {"pid": 16816, "version": "1.0.0", "uptime_s": 31},
|
||||||
|
"port": {"ready": true, "name": "COM1", "baud": 115200, "dtr": false, "rts": false,
|
||||||
|
"since": "2026-09-15T02:30:57.739+08:00"},
|
||||||
|
"counters": {"rx_bytes": 1834, "tx_bytes": 22, "rx_lines": 57, "tx_lines": 3, "errors": 0},
|
||||||
|
"last_rx": {"ts": "…", "line": "UI menu init: OK", "age_ms": 320},
|
||||||
|
"log": {"path": "…\\tools\\serial_tool\\state\\serial.log", "size": 4523, "gen": 7},
|
||||||
|
"state": "active",
|
||||||
|
"error": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| `state` | `active`(正常收数据)/ `stopped`(口未开)/ `error`(读错/拔线,`error` 字段有详情;重开 `open` 即恢复) |
|
||||||
|
| `port.ready` | 已开 && 非 error |
|
||||||
|
| `counters` | 本 daemon 生命周期累计(daemon 重启清零) |
|
||||||
|
| `last_rx.age_ms` | 距最后一行 RX 的毫秒数——判断"还在刷/已静默" |
|
||||||
|
| `log.gen` | 当前日志代际(`clear` 会 +1) |
|
||||||
|
|
||||||
|
### 3.6 `log` — 读日志
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py log # 末 50 行
|
||||||
|
... serial_tool.py log --tail 200 # 末 200 行
|
||||||
|
... serial_tool.py log --tail 0 # 全部行
|
||||||
|
... serial_tool.py log --grep "App init OK" # 只留含子串的行
|
||||||
|
... serial_tool.py log --grep "init" --tail 100
|
||||||
|
```
|
||||||
|
|
||||||
|
- **直接读日志文件**实现——daemon 死机/被杀也不受影响;`gen` 取自 `meta.json`。
|
||||||
|
- 返回 `{"ok":true,"gen":N,"lines":["[RX] …", …]}`。
|
||||||
|
- 等价的手动读法(Agent 用 Read/Grep 工具、人用 PowerShell 均可):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Get-Content 'tools\serial_tool\state\serial.log' -Tail 20
|
||||||
|
Select-String -Path 'tools\serial_tool\state\serial.log' -Pattern 'App init OK'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.7 `clear` — 清空日志(代际 +1)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py clear # → {"ok":true,"gen":8}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 原地截断 + 写 `[SYS] … log cleared (gen=N+1)` 标记行;**不重开文件、不动串口**。
|
||||||
|
- 用途:每次烧录/实验前 clear 一下,之后日志里就只属于本轮,新旧内容按 `gen`/标记行区分。
|
||||||
|
|
||||||
|
### 3.8 `wait-idle` — 等 RX 静默
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py wait-idle # 静默 8s 或超时 30s
|
||||||
|
... serial_tool.py wait-idle --settle-ms 5000 --max-ms 60000 # 自定义
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"ok": true, "rx_bytes": 1834, "idle": true, "waited_ms": 8041, "reason": "idle"}
|
||||||
|
```
|
||||||
|
|
||||||
|
| `reason` | 含义 | `idle` |
|
||||||
|
|---|---|---|
|
||||||
|
| `idle` | 收到过数据,且已连续静默 ≥ `--settle-ms`(**正常收尾**) | true |
|
||||||
|
| `no_data` | 全程一个字节都没收到(板子没输出/口不对/没烧进去) | false |
|
||||||
|
| `timeout` | `--max-ms` 到了仍在持续吐数据 | false |
|
||||||
|
|
||||||
|
- **`--settle-ms` 默认 8000 不是随便定的**:本工程 boot 任务间有 3~4s 自然静默间隙,判据小于它会把开机日志截断。
|
||||||
|
- @test 流程(`run_boot_test.ps1`)用它作为"烧录后日志收齐"的判据。
|
||||||
|
|
||||||
|
### 3.9 `start` / `stop` / `restart` — daemon 生命周期
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py start # 拉起(已在跑 → already_running:true,不做任何事)
|
||||||
|
... serial_tool.py stop # 优雅退出:关串口 → 冲刷尾行 → 退出
|
||||||
|
... serial_tool.py restart # 停旧 + 拉新,保证新进程加载的是当前代码
|
||||||
|
```
|
||||||
|
|
||||||
|
- 日常**不需要** start(任何命令都会自动拉起)。
|
||||||
|
- **改了 `serial_tool.py` 之后**要 `restart`,否则运行中的还是旧代码。
|
||||||
|
- `stop` 后 COM 端口立即释放,可交给其他程序;daemon 死掉/被杀同理(下次命令自动拉起,但**串口不会自动重开**——需要时再 `open`)。
|
||||||
|
|
||||||
|
### 3.10 `selftest` — 无头自检
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py selftest # 10 项进程内回环测试,无需硬件
|
||||||
|
# [PASS] T1a CRLF 行 … SELFTEST PASS(exit 0)
|
||||||
|
```
|
||||||
|
|
||||||
|
新机器搭完环境先跑它:过了 = 解释器/pyserial/核心算法都正常。
|
||||||
|
|
||||||
|
## 4. 日志文件(全量历史)
|
||||||
|
|
||||||
|
### 4.1 三个文件
|
||||||
|
|
||||||
|
| 文件 | 内容 | 谁读 |
|
||||||
|
|---|---|---|
|
||||||
|
| `tools/serial_tool/state/serial.log` | RX/TX/SYS 全量日志 | 你(Read/Grep/`log` 命令) |
|
||||||
|
| `tools/serial_tool/state/meta.json` | daemon pid / 版本 / 当前 gen / 口配置快照 | 工具内部 |
|
||||||
|
| `tools/serial_tool/state/daemon.log` | daemon 自身 stderr(启动行、异常) | 排障时看 |
|
||||||
|
|
||||||
|
整个 `state/` 目录已 gitignore——纯本机运行时产物。
|
||||||
|
|
||||||
|
### 4.2 行格式
|
||||||
|
|
||||||
|
```
|
||||||
|
[SYS] 2026-09-15T02:30:57.739+08:00 port opened COM1 115200 (gen=0)
|
||||||
|
[RX] 2026-09-15T02:31:23.101+08:00 App init OK
|
||||||
|
[TX] 2026-09-15T02:31:23.986+08:00 hello_from_tool\r\n
|
||||||
|
[SYS] 2026-09-15T02:31:24.245+08:00 log cleared (gen=1)
|
||||||
|
[SYS] 2026-09-15T02:39:54.598+08:00 log truncated to 10MB (cap=20MB)
|
||||||
|
```
|
||||||
|
|
||||||
|
| 规则 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| 方向标记 | `[RX]` 串口收到 / `[TX]` 你发出 / `[SYS]` 工具事件(open/close/error/cleared/truncated) |
|
||||||
|
| 时间戳 | 本地 ISO8601 含毫秒与偏移;= **该行首字节到达时刻** |
|
||||||
|
| **只含完整行** | 残行留 daemon 内存,200ms 无后续数据才冲刷成行 → 你**永远读不到半行** |
|
||||||
|
| 解码回退 | UTF-8 → GBK → 都不行则该文本域写 `HEX:ab12…`(纯二进制流时整行转 hex) |
|
||||||
|
| TX 转义 | 发出的控制字符写成字面 `\r` `\n`(日志按行存储,真换行会把一行劈成两行) |
|
||||||
|
| flush | 每行即 flush——文件随时可读、内容即时落盘 |
|
||||||
|
|
||||||
|
### 4.3 体积上限与截头
|
||||||
|
|
||||||
|
- 单文件上限 **20MB**;超过后 daemon **原地截头**保留**尾部 10MB** 并写 `[SYS] … log truncated` 标记行。
|
||||||
|
- 截头不重开文件、不重开端口、不影响正在收的数据——但**文件头部的老内容会消失**。
|
||||||
|
- 因此:查旧数据要看**文件尾部**(`log --tail N` / `Get-Content -Tail`),别从文件头读。
|
||||||
|
- 嫌它涨得快/想立刻清空 → `clear`(代际 +1,比截头干净)。
|
||||||
|
|
||||||
|
## 5. 典型工作流
|
||||||
|
|
||||||
|
### 5.1 交互式调试(发命令看响应)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py open
|
||||||
|
... serial_tool.py send "AT+STATUS" --nl
|
||||||
|
... serial_tool.py log --tail 10 # 看响应(或直接 Read 日志文件)
|
||||||
|
# … 反复 send / log …
|
||||||
|
... serial_tool.py close
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 抓一次开机日志(手动版 @test)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py open --port COM6
|
||||||
|
... serial_tool.py clear # 代际 +1:此后内容只属于本轮
|
||||||
|
# ……此刻去烧录/复位板子(ST-Link 烧录不占 COM,串口全程保持打开)……
|
||||||
|
... serial_tool.py wait-idle --settle-ms 8000 --max-ms 30000
|
||||||
|
... serial_tool.py log --tail 0 # 取本轮全量 → 人眼/脚本检查标记
|
||||||
|
```
|
||||||
|
|
||||||
|
自动化版本 = `test/run_boot_test.ps1`(同一序列 + 烧录 + 标记校验,见 `自动化测试流程.md`)。
|
||||||
|
|
||||||
|
### 5.3 长时运行监控
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py log --grep "ERROR" --tail 50 # 随时捞特定内容
|
||||||
|
... serial_tool.py status # 看 counters.errors / last_rx.age_ms
|
||||||
|
```
|
||||||
|
|
||||||
|
daemon 常驻,日志持续累积(20MB 自动截头),几天不关也没压力。
|
||||||
|
|
||||||
|
### 5.4 排障三件套
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
... serial_tool.py status # ① state/error/counters 一眼看全
|
||||||
|
Get-Content 'tools\serial_tool\state\daemon.log' -Tail 30 # ② daemon 自身输出
|
||||||
|
... serial_tool.py restart # ③ 重建 daemon(顺带加载新代码)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 配置
|
||||||
|
|
||||||
|
唯一配置源:`.opencode/serial_config.json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"portName": "COM6",
|
||||||
|
"portHint": "USB 串行设备",
|
||||||
|
"baudRate": 115200,
|
||||||
|
"httpPort": 18765,
|
||||||
|
"note": "……"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | 用途 | 缺省 |
|
||||||
|
|---|---|---|
|
||||||
|
| `portName` | `open` 的默认端口;`ports` 的 `configured` 标注 | 无(必须给) |
|
||||||
|
| `baudRate` | 默认波特率 | 115200 |
|
||||||
|
| `httpPort` | daemon HTTP 端口(一般不动) | 18765 |
|
||||||
|
|
||||||
|
**换端口只改这个文件**(`@test` 与手动调试都读它)。`httpPort` 冲突时才需要改。
|
||||||
|
|
||||||
|
## 7. 故障排查
|
||||||
|
|
||||||
|
| 现象 | 原因 | 处理 |
|
||||||
|
|---|---|---|
|
||||||
|
| `port not found: COMx (available: …)` | 板子没接 / CH340 驱动没装 / 口号变了 | 对照 `available` 列表;装 CH340 驱动;改 `.opencode/serial_config.json` 的 `portName` |
|
||||||
|
| `port busy: COMx (held by another process)` | 别的程序占着口 | `Get-Process` 找占用者关掉;或 `… serial_tool.py close` 释放本工具占的口 |
|
||||||
|
| `daemon start timeout` / `daemon unreachable` | daemon 起不来(端口冲突/解释器问题) | 看 `state/daemon.log`;`… serial_tool.py restart`;确认 18765 未被占(改 `httpPort`) |
|
||||||
|
| `wait-idle` 返回 `no_data` | 全程无 RX | 核对 COM 号与波特率;板子供电;烧录是否成功;`status` 看 `port.ready` |
|
||||||
|
| 日志里出现 `HEX:…` 行 | 该段字节不是 UTF-8/GBK 文本(二进制流/乱码) | 正常回退行为,按 hex 对照协议解析 |
|
||||||
|
| `state: error` + `error: read: …` | 读串口出错/拔线 | daemon 仍活着;重插后 `open` 即恢复(自动 1.5s 退避) |
|
||||||
|
| 改了 `serial_tool.py` 行为没变 | 运行中的 daemon 还是旧代码 | `… serial_tool.py restart` |
|
||||||
|
| 开机日志"缺尾巴"(如缺 `Network Init`) | `--settle-ms` 太小,在 boot 自然静默间隙就收尾了 | 用默认 8000(`run_boot_test.ps1` 已内置) |
|
||||||
|
| 旧日志"丢了" | 20MB 截头丢的是**文件头** | 查旧内容要看尾部;重要轮次开始前先 `clear` 分代 |
|
||||||
|
|
||||||
|
## 8. 常见问题
|
||||||
|
|
||||||
|
- **daemon 会一直占着内存吗?** 一个 Python 进程约 20MB;不需要时 `stop` 即释放。常驻与否都不影响正确性。
|
||||||
|
- **daemon 被强杀(taskkill)会怎样?** 端口由系统自动释放;下次任何命令自动拉起新 daemon。**串口不会自动重开**,需要时再 `open`(这是设计:避免在设备异常时盲目重连)。
|
||||||
|
- **能同时开两个串口吗?** v1 单口(一个 daemon 管一个口)。多口需求见设计文档 §8 v2 候选。
|
||||||
|
- **能直接删 `serial.log` 吗?** 可以,但代际 `gen` 不会变、写句柄不变——建议用 `clear`(原子 + 代际 +1 + 标记行)。
|
||||||
|
- **为什么 TX 日志里是字面 `\r\n` 而不是真换行?** 日志按行存储;真换行会把一条 TX 劈成两行,转义后一条 TX 恒一行。
|
||||||
|
- **ST-Link 烧录会抢串口吗?** 不会(烧录走 SWD,不走 COM)——这正是"串口全程保持打开、烧录前后不重开"的设计基础,也彻底绕开了 CH340 释放/重开陷阱。
|
||||||
|
- **别的程序/Agent 能绕过 CLI 直接用吗?** 能——daemon 暴露本机 HTTP JSON 接口(§9)。
|
||||||
|
|
||||||
|
## 9. 附录:HTTP 协议(绕过 CLI)
|
||||||
|
|
||||||
|
daemon 在 `127.0.0.1:<httpPort>`(默认 18765)提供 JSON API,与 CLI 一一对应:
|
||||||
|
|
||||||
|
| 方法 路径 | 请求体(JSON,可空) | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `GET /ping` | — | `{"ok":true,"version":"1.0.0","pid":…}` |
|
||||||
|
| `GET /status` | — | 同 `status` 命令 |
|
||||||
|
| `GET /ports` | — | 同 `ports` 命令 |
|
||||||
|
| `POST /open` | `{"port":"COM6","baud":115200,"dtr":0,"rts":0}`(均可省) | 同 `open` |
|
||||||
|
| `POST /close` | — | 同 `close` |
|
||||||
|
| `POST /send` | `{"text":"hi","nl":true}` 或 `{"hex":"0D0A"}` | 同 `send` |
|
||||||
|
| `POST /clear` | — | 同 `clear` |
|
||||||
|
| `POST /wait-idle` | `{"settle_ms":8000,"max_ms":30000}` | **同步阻塞**至静默/超时才返回 |
|
||||||
|
| `POST /stop` | — | 关口后 daemon 退出(响应先于退出发出) |
|
||||||
|
|
||||||
|
响应码:`200` 成功 / `400` 领域错误(`ok:false`+`error`)/ `504` daemon 忙(命令 20s 未完成)/ `404` 未知端点。
|
||||||
|
|
||||||
|
PowerShell 示例:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Invoke-RestMethod http://127.0.0.1:18765/status
|
||||||
|
Invoke-RestMethod -Method Post http://127.0.0.1:18765/send -Body '{"text":"ping"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 变更记录
|
||||||
|
|
||||||
|
| 日期 | 变更 |
|
||||||
|
|---|---|
|
||||||
|
| 2026-09-15 | 初版:命令全参考(含实测输出)、日志规范、典型工作流、故障排查、FAQ、HTTP 附录;与 v1.1 实现(含 4 项 Windows 缺陷修复)对齐 |
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
> **版本**:v1.1(需求 + 设计 + 实施记录)
|
> **版本**:v1.1(需求 + 设计 + 实施记录)
|
||||||
> **日期**:2026-09-15
|
> **日期**:2026-09-15
|
||||||
> **状态**:**已实施**(S1–S6 完成;本机验收 A1–A5/A8 通过,A6/A7 正路径待 CH340 硬件接入后补验)
|
> **状态**:**已实施**(S1–S6 完成;本机验收 A1–A5/A8 通过,A6/A7 正路径待 CH340 硬件接入后补验)
|
||||||
> **关联文档**:`自动化测试流程.md` · `AGENTS.md`(串口调试/自动化测试节) · `.opencode/serial_config.json`(端口单一配置源,沿用)
|
> **关联文档**:`串口助手使用指南.md`(命令用法/工作流/排障) · `自动化测试流程.md` · `AGENTS.md`(串口调试/自动化测试节) · `.opencode/serial_config.json`(端口单一配置源,沿用)
|
||||||
> **取代**:`serial-mcp-server_串口调试.md`(实施时删除,工具历史并入本文 §12)
|
> **取代**:`serial-mcp-server_串口调试.md`(实施时删除,工具历史并入本文 §12)
|
||||||
|
|
||||||
## 1. 背景与目标
|
## 1. 背景与目标
|
||||||
|
|||||||
+10
-12
@@ -10,6 +10,7 @@
|
|||||||
| `docs/测试说明/自动化测试流程.md` | @test 闭环细节(命令 / 标记 / 失败模式) |
|
| `docs/测试说明/自动化测试流程.md` | @test 闭环细节(命令 / 标记 / 失败模式) |
|
||||||
| `docs/测试说明/测试文档模板规范.md` | 测试文档模板、命名规则(TM / TC / DP) |
|
| `docs/测试说明/测试文档模板规范.md` | 测试文档模板、命名规则(TM / TC / DP) |
|
||||||
| `docs/测试说明/串口助手设计说明.md` | 串口调试 / 采集工具与陷阱(Python 串口助手) |
|
| `docs/测试说明/串口助手设计说明.md` | 串口调试 / 采集工具与陷阱(Python 串口助手) |
|
||||||
|
| `docs/测试说明/串口助手使用指南.md` | 串口助手命令用法 / 工作流 / 排障 |
|
||||||
| `docs/UI 设计/UI_自动化测试流程.md` | UI 模拟器回归(ui-verify)细节 |
|
| `docs/UI 设计/UI_自动化测试流程.md` | UI 模拟器回归(ui-verify)细节 |
|
||||||
| `docs/代码规范/pre-commit使用说明.md` | pre-commit 门禁配置与范围 |
|
| `docs/代码规范/pre-commit使用说明.md` | pre-commit 门禁配置与范围 |
|
||||||
| `docs/项目部署环境要求.md` | 构建 / 测试工具链环境 |
|
| `docs/项目部署环境要求.md` | 构建 / 测试工具链环境 |
|
||||||
@@ -151,23 +152,19 @@ static void phaseN_run(void) {
|
|||||||
|
|
||||||
> 注意:`test/` 在 pre-commit 检查范围之外(工具代码豁免)——上表约定属**自律**要求,但 0 错 0 警的构建红线对测试代码同样生效。
|
> 注意:`test/` 在 pre-commit 检查范围之外(工具代码豁免)——上表约定属**自律**要求,但 0 错 0 警的构建红线对测试代码同样生效。
|
||||||
|
|
||||||
### 3.4 已知问题:测试构建下的 netTask(未来测试设计必读)
|
### 3.4 测试构建下的 netTask(2026-09-15 已修复 P1-6,未来测试设计必读)
|
||||||
|
|
||||||
代码事实(截至 2026-09):
|
代码事实(2026-09-15 修复后):
|
||||||
|
|
||||||
1. `netTask` 定义于 `.ioc`(RTOS 任务列表)→ `Src/freertos.c` 的 **CubeMX 生成区无条件创建**,其函数体 `net_task_func()` **在所有构建模式下一样运行**:等存储就绪(≤10s)→ `net_stack_bring_up()`(CH395F 初始化)→ 置 `SYS_EVT_NET_READY` → `net_poll()` 轮询循环。
|
1. `netTask` = **基础线程**:定义于 `.ioc` → `Src/freertos.c` 的 **CubeMX 生成区无条件创建**(全构建唯一实例)。产品 / NET 层测试模式下正常运行:等存储就绪(≤10s)→ `net_stack_bring_up()`(CH395F 初始化)→ 置 `SYS_EVT_NET_READY` → `net_poll()` 轮询循环。
|
||||||
2. USER CODE 区在 `ENABLE_NET_LAYER_TESTS` 下**另建一个** netTask → NET 层测试构建下**双 netTask 并存**(双重初始化;靠重初始化幂等 + 失败方永久挂起在实践中被掩盖)。
|
2. ~~USER CODE 区在 `ENABLE_NET_LAYER_TESTS` 下另建一个 netTask(双 netTask 并存)~~ → **2026-09-15 已删除**(P1-6):NET 层测试构建不再重复创建。
|
||||||
3. 硬件层 CH395F 模式下,testTask 还自行做一次 `net_stack_bring_up()` 后阻塞跑各阶段;生成版 netTask 的第二次初始化把芯片重初始化为相同状态,且 PC 配合阶段要等 PC 端就绪才启动(时延远大于初始化窗口),**实测不影响测试结果**。
|
3. **CH395F 硬件层模式下 `net_task_func` 入口自挂起**(2026-09-15 守卫,`ENABLE_HW_LAYER_TESTS`):不 bring_up、不轮询、不广播 NET_READY;testTask 自行 `net_stack_bring_up()` 后独占 CH395F 跑各阶段。任务仍被创建(基础线程策略:恒存在、该模式"不运行"),占 4KB 栈——彻底方案(`.ioc` 移除 + 条件创建)经评估未采用:网络线程是基础线程,仅测试模式"不运行"。
|
||||||
|
|
||||||
由此产生的设计约束:
|
由此产生的设计约束:
|
||||||
|
|
||||||
- 旧文档"硬件层模式 netTask 不创建、testTask 独占 CH395F、无 net_poll 并发"的说法**与代码不符**:任何构建下生成版 netTask 都存在且运行 `net_poll()`(全局中断由它消费清除)。
|
- **硬件层模式**:netTask 已挂起,**无人**消费/清除芯片全局中断标志——"中断状态寄存器全程 0x0000"类断言在该模式下**安全**(测试入口的预读清除仍须保留,用于清除 `net_stack_bring_up` 自身强制 PHY 重协商锁存的 `PHY_CHANGE` 残留)。
|
||||||
- **新增测试套件必须按"netTask 恒存在且在轮询"设计**:不得假设"无人动芯片 / 中断"。
|
- **NET 层模式 / 产品构建**:netTask 恒存在且在轮询(全局中断由它消费清除)——新增测试用例**不得**断言"无人动芯片/中断"。
|
||||||
- 若未来需要严格"测试独占外设",须先完成以下重构(尚未实施):
|
- 硬件层模式下挂起的 netTask 仍占 4KB 栈,为基础线程策略的接受成本(彻底方案可回收,暂无计划)。
|
||||||
1. 删除 `freertos.c` USER CODE 区冗余的 netTask 创建;
|
|
||||||
2. `net_task_func()` 增加编译期守卫:`ENABLE_HW_LAYER_TESTS` 下挂起(不 bring_up、不 poll);
|
|
||||||
3. (彻底方案)netTask 从 `.ioc` 移除、全部创建移入 USER CODE 区按构建模式控制——需同步验证 CubeMX 再生成流程。
|
|
||||||
- 重构完成前:**不要**新增断言"中断状态寄存器全程 0x0000"之类的用例(net_poll 会清除标志,必现竞态误报)。
|
|
||||||
|
|
||||||
### 3.5 新测试文件 / 新套件 checklist
|
### 3.5 新测试文件 / 新套件 checklist
|
||||||
|
|
||||||
@@ -357,4 +354,5 @@ flowchart LR
|
|||||||
|
|
||||||
| 日期 | 变更 |
|
| 日期 | 变更 |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
| 2026-09-15 | §3.4 更新:P1-6 修复落地(基础线程策略)——USER CODE 区冗余 netTask 创建删除 + `net_task_func` 入口 `ENABLE_HW_LAYER_TESTS` 自挂起守卫;"代码事实/设计约束"按修复后现状重写(硬件层模式中断断言恢复安全、NET 层/产品仍按"netTask 恒在轮询"设计);彻底方案(`.ioc` 移除)经评估未采用。同日构建验证发现两处**存量**测试固件缺陷(与 P1-6 无关,A/B 对照确证):① `net_test_task.c` `s_rx_buf` 使用先于声明 → NET 层配置自 2026-08(88160a5)起不可编译;② 128KB 静态 RAM 预算溢出(产品镜像 123.6KB,HW 全阶段固件超 8.7KB、NET 固件超 ~28KB)——已立 P1-9/P1-10 跟踪 |
|
||||||
| 2026-09-13 | 重写:对齐现测试架构——统一 `test_config.h` 套件(旧版仅描述 CH395F 单套件与 `ch395fTestTask` 旧入口);新增 @test 自动化闭环、pre-commit 门禁、UI 模拟器五步门禁、主机侧工具约定;新增"测试构建下 netTask"已知问题(旧版"硬件层模式 netTask 不创建"表述与代码不符,改为设计约束并给出重构路径);修正附录路径(旧版 `docs/CH395F_Test_Guide.md` 等已移入 `docs/测试说明/`);新增双端注册、内存预算、陷阱沉淀要求 |
|
| 2026-09-13 | 重写:对齐现测试架构——统一 `test_config.h` 套件(旧版仅描述 CH395F 单套件与 `ch395fTestTask` 旧入口);新增 @test 自动化闭环、pre-commit 门禁、UI 模拟器五步门禁、主机侧工具约定;新增"测试构建下 netTask"已知问题(旧版"硬件层模式 netTask 不创建"表述与代码不符,改为设计约束并给出重构路径);修正附录路径(旧版 `docs/CH395F_Test_Guide.md` 等已移入 `docs/测试说明/`);新增双端注册、内存预算、陷阱沉淀要求 |
|
||||||
|
|||||||
@@ -0,0 +1,369 @@
|
|||||||
|
$PACKAGES
|
||||||
|
C0603 ! C0603 ! '{Value}' ; C1 C2 C4 C5 C6 C7 C8 C9 C10 C16 C17 C18 C19 C20 ,
|
||||||
|
C21 C22 C29 C30 C31 C32 C34 C35 C36 C38 C40 C43 C44 C47 C48 C53 C54 ,
|
||||||
|
C57 C58 C61 C62 C63 C64 C65 C66 C67 C68 C69 C70 C71 C73 C78 C79 C93 ,
|
||||||
|
C94 C95 C96 C97 C98 C101 C102 C103 C104 C105 C106 C107 C108 C110 C111
|
||||||
|
C0603 ! C0603 ! '0.1uF' ; C74
|
||||||
|
C0603 ! C0603 ! 100nF ; C12 C14 C15 C80 C81 C82 C83 C84 C85 C86 C87 C88 C89 ,
|
||||||
|
C90 C91 C92 C100
|
||||||
|
C0603 ! C0603 ! 12pF ; C27 C28 C75 C76
|
||||||
|
C0603 ! C0603 ! 15pF ; C25 C26
|
||||||
|
C0603 ! C0603 ! 1uF ; C13 C23 C24
|
||||||
|
C0805 ! C0805 ! '{Value}' ; C33 C37 C39 C41 C42 C46 C49 C50 C51 C52 C55 C56 ,
|
||||||
|
C59 C60 C72 C77
|
||||||
|
C0805 ! C0805 ! 10uF ; C11
|
||||||
|
CAP-SMD_BD10.0-L10.3-W10.3-LS11.0 ! CAP-SMD_BD10.0-L10.3-W10.3-LS11.0 ! 470uF ,
|
||||||
|
; C99
|
||||||
|
CAP-SMD_BD6.3-L6.6-W6.6-LS7.3-FD ! CAP-SMD_BD6.3-L6.6-W6.6-LS7.3-FD ! 220uF ; ,
|
||||||
|
C3 C45
|
||||||
|
,
|
||||||
|
CAP-TH_L11.0-W4.5-P10.00-D0.6-S3.00 ! CAP-TH_L11.0-W4.5-P10.00-D0.6-S3.00 ! '4.7nF' ,
|
||||||
|
; U20 U21 U22
|
||||||
|
CONN-TH_JL15EDGKNRM-35012G01 ! CONN-TH_JL15EDGKNRM-35012G01 ! '{Value}' ; CN1
|
||||||
|
CONN-TH_WINGTAT_9001-15481C00A ! CONN-TH_WINGTAT_9001-15481C00A ! '{Value}' ; ,
|
||||||
|
U5
|
||||||
|
CRYSTAL-SMD_4P-L3.2-W2.5-BL ! CRYSTAL-SMD_4P-L3.2-W2.5-BL ! 25MHz ; X1 X2
|
||||||
|
CRYSTAL-SMD_4P-L3.2-W2.5-BL ! CRYSTAL-SMD_4P-L3.2-W2.5-BL ! 8MHz ; X3
|
||||||
|
,
|
||||||
|
DIP-6_L11.2-W11.2-P2.54-LS7.6-BL ! DIP-6_L11.2-W11.2-P2.54-LS7.6-BL ! '{Value}' ,
|
||||||
|
; U16
|
||||||
|
HDR-TH_16P-P2.54-V-F ! HDR-TH_16P-P2.54-V-F ! '{Value}' ; H1
|
||||||
|
HDR-TH_3P-P2.54-V-F ! HDR-TH_3P-P2.54-V-F ! '{Value}' ; H2
|
||||||
|
KEY-SMD_2P-L6.1-W3.6--LS7.9 ! KEY-SMD_2P-L6.1-W3.6--LS7.9 ! '{Value}' ; SW1
|
||||||
|
,
|
||||||
|
KEY-SMD_4P-L6.0-W6.0-P4.50-LS9.5-BR ! KEY-SMD_4P-L6.0-W6.0-P4.50-LS9.5-BR ! '{Value}' ,
|
||||||
|
; SW2 SW3 SW4 SW5 SW6 SW7 SW8 SW9
|
||||||
|
L0603 ! L0603 ! '{Value}' ; L1 L2 L6
|
||||||
|
L1206 ! L1206 ! '{Value}' ; L3 L4
|
||||||
|
LED_0603 ! LED_0603 ! '{Value}' ; LED1 LED2 LED3 LED4 LED5 LED6 LED7 LED8 LED9 ,
|
||||||
|
LED10
|
||||||
|
,
|
||||||
|
LQFP-144_L20.0-W20.0-P0.50-LS22.0-BL ! LQFP-144_L20.0-W20.0-P0.50-LS22.0-BL ! '{Value}' ,
|
||||||
|
; U17
|
||||||
|
,
|
||||||
|
LQFP-64_L10.0-W10.0-P0.50-LS12.0-BL ! LQFP-64_L10.0-W10.0-P0.50-LS12.0-BL ! '{Value}' ,
|
||||||
|
; U3
|
||||||
|
PWRM-TH_B0505S-1WR3 ! PWRM-TH_B0505S-1WR3 ! '{Value}' ; U4
|
||||||
|
QFN-32_L4.0-W4.0-P0.40-BL-EP2.7 ! QFN-32_L4.0-W4.0-P0.40-BL-EP2.7 ! '{Value}' ,
|
||||||
|
; U1
|
||||||
|
QFN-48_L6.0-W6.0-P0.40-TL-EP4.5 ! QFN-48_L6.0-W6.0-P0.40-TL-EP4.5 ! '{Value}' ,
|
||||||
|
; U2
|
||||||
|
R0603 ! R0603 ! '1.5k' ; R35
|
||||||
|
R0603 ! R0603 ! '1k/0603/1%' ; R5 R12 R13 R14 R15 R17 R18 R19 R20 R21 R23 R25 ,
|
||||||
|
R26 R27 R28 R30 R31 R32 R45 R46 R47 R48 R49 R51 R52
|
||||||
|
R0603 ! R0603 ! '2.49k/1%' ; R3
|
||||||
|
R0603 ! R0603 ! '4.7k' ; R24
|
||||||
|
R0603 ! R0603 ! '4.7K' ; R38 R39 R41 R42
|
||||||
|
R0603 ! R0603 ! '5.1k' ; R4
|
||||||
|
R0603 ! R0603 ! 10k ; R6 R11 R16 R22 R29 R36 R37 R43
|
||||||
|
R0603 ! R0603 ! 10K ; R40 R44 R50 R53 R54 R55 R56 R57 R58
|
||||||
|
R0603 ! R0603 ! 1k ; R9 R10 R33 R59 R60 R61 R62 R63 R64
|
||||||
|
R0603 ! R0603 ! 390 ; R34
|
||||||
|
R0603 ! R0603 ! 470 ; R1 R2 R7 R8
|
||||||
|
RJ45-TH_C2836689 ! RJ45-TH_C2836689 ! '{Value}' ; U14
|
||||||
|
RJ45-TH_HR911105A ! RJ45-TH_HR911105A ! '{Value}' ; J1 J2
|
||||||
|
SMB_L4.3-W3.6-LS5.4-BI ! SMB_L4.3-W3.6-LS5.4-BI ! '{Value}' ; D3 D4 D5 D6
|
||||||
|
SMB_L4.6-W3.6-LS5.3-RD ! SMB_L4.6-W3.6-LS5.3-RD ! '{Value}' ; D1 D2
|
||||||
|
SMD-4_L6.5-W4.6-P2.54-LS10.0-TL ! SMD-4_L6.5-W4.6-P2.54-LS10.0-TL ! '{Value}' ,
|
||||||
|
; U8
|
||||||
|
SOIC-8_L4.9-W3.9-P1.27-LS6.0-BL ! SOIC-8_L4.9-W3.9-P1.27-LS6.0-BL ! '{Value}' ,
|
||||||
|
; U9 U10 U11
|
||||||
|
SOIC-8_L5.0-W4.0-P1.27-LS6.0-BL ! SOIC-8_L5.0-W4.0-P1.27-LS6.0-BL ! '{Value}' ,
|
||||||
|
; U15
|
||||||
|
SOP-16_L9.9-W3.9-P1.27-LS6.0-BL ! SOP-16_L9.9-W3.9-P1.27-LS6.0-BL ! '{Value}' ,
|
||||||
|
; U13
|
||||||
|
,
|
||||||
|
SOT-223-4_L6.5-W3.5-P2.30-LS7.0-BR ! SOT-223-4_L6.5-W3.5-P2.30-LS7.0-BR ! '{Value}' ,
|
||||||
|
; U6 U7
|
||||||
|
SOT-23_L2.9-W1.3-P0.95-LS2.4-BR ! SOT-23_L2.9-W1.3-P0.95-LS2.4-BR ! '{Value}' ,
|
||||||
|
; Q1
|
||||||
|
,
|
||||||
|
SOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR ! SOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR ! '{Value}' ,
|
||||||
|
; U12
|
||||||
|
,
|
||||||
|
TSSOP-48_L12.5-W6.1-P0.50-LS8.1-BL ! TSSOP-48_L12.5-W6.1-P0.50-LS8.1-BL ! '{Value}' ,
|
||||||
|
; U18
|
||||||
|
WSON-8_L6.0-W8.0-P1.27-BL-EP ! WSON-8_L6.0-W8.0-P1.27-BL-EP ! '{Value}' ; U19
|
||||||
|
XFMR-SMD_H1102NLT ! XFMR-SMD_H1102NLT ! 350uH ; T1
|
||||||
|
$A_PROPERTIES
|
||||||
|
$NETS
|
||||||
|
'$1N1012' ; LED1.2 R7.2
|
||||||
|
'$1N1082' ; LED2.1 U1.18
|
||||||
|
'$1N1181' ; R4.1 U1.28
|
||||||
|
'$1N491' ; C13.1 U1.9
|
||||||
|
'$1N6544' ; Q1.1 R10.1 R11.1
|
||||||
|
'$1N6717' ; T1.14 U1.3
|
||||||
|
'$1N6719' ; C24.2 T1.15
|
||||||
|
'$1N6728' ; T1.11 U1.4
|
||||||
|
'$1N6731' ; T1.9 U1.5
|
||||||
|
'$1N6734' ; T1.16 U1.2
|
||||||
|
'$1N6924' ; C23.2 T1.10
|
||||||
|
'$1N7347' ; C22.1 T1.2 T1.7
|
||||||
|
'$1N7578' ; R3.1 U2.42
|
||||||
|
'$1N8927' ; LED2.2 R8.1
|
||||||
|
'$1N9145' ; C1.1 J1.4 J1.5
|
||||||
|
'$1N9156' ; J1.9 R1.2
|
||||||
|
'$1N9179' ; J2.9 R2.1
|
||||||
|
'$1N9181' ; C2.1 J2.4 J2.5
|
||||||
|
'$1N9187' ; LED3.1 Q1.3
|
||||||
|
'$1N9188' ; LED3.2 R9.1
|
||||||
|
'$1N986' ; LED1.1 U1.16
|
||||||
|
'$2N646' ; R24.2 U3.15
|
||||||
|
'$2N658' ; R29.1 U3.34
|
||||||
|
'$2N659' ; C37.1 U3.44 U3.45
|
||||||
|
'$2N663' ; C39.1 U3.42
|
||||||
|
'$2N664' ; C41.1 U3.39
|
||||||
|
'$2N665' ; C42.1 U3.36
|
||||||
|
'$2N742' ; R22.2 U3.6
|
||||||
|
'$3N163' ; R34.2 U8.1
|
||||||
|
'$3N166' ; LED4.2 R33.1
|
||||||
|
'$3N63' ; C50.2 L4.2 U4.2
|
||||||
|
'$3N77' ; C68.2 U13.1
|
||||||
|
'$3N78' ; C68.1 U13.3
|
||||||
|
'$3N79' ; C71.2 U13.4
|
||||||
|
'$3N80' ; C71.1 U13.5
|
||||||
|
'$3N81' ; C70.2 U13.2
|
||||||
|
'$3N82' ; C69.2 U13.6
|
||||||
|
'$4N140' ; R38.1 U18.1
|
||||||
|
'$4N154' ; R39.1 U18.48
|
||||||
|
'$4N156' ; R41.2 U18.24
|
||||||
|
'$4N158' ; R42.2 U18.25
|
||||||
|
'$4N25' ; C76.2 U17.24 X3.1
|
||||||
|
'$4N269' ; LED5.2 R59.1
|
||||||
|
'$4N272' ; LED6.2 R60.1
|
||||||
|
'$4N274' ; LED7.2 R61.1
|
||||||
|
'$4N276' ; LED8.2 R62.1
|
||||||
|
'$4N28' ; C75.2 U17.23 X3.3
|
||||||
|
'$4N283' ; LED9.2 R63.1
|
||||||
|
'$4N286' ; LED10.2 R64.1
|
||||||
|
'$4N29' ; C94.2 U17.71
|
||||||
|
'$4N31' ; C79.2 U17.106
|
||||||
|
'3.3V' ; C11.2 C12.1 C15.1 C16.1 C17.1 C18.1 C19.1 C20.1 C21.1 C31.1 C40.2 ,
|
||||||
|
C58.1 C59.1 C72.2 C73.2 C80.1 C81.1 C82.1 C83.1 C84.1 C85.1 C86.1 ,
|
||||||
|
C87.1 C88.1 C89.1 C90.1 C91.1 C92.1 C93.2 C100.1 C102.1 D2.1 H1.1 L6.1 ,
|
||||||
|
R1.1 R6.1 R7.1 R8.2 R9.2 R29.2 R33.2 R36.1 R37.1 R38.2 R40.2 R41.1 ,
|
||||||
|
R43.1 R44.2 R50.2 R53.2 R54.2 R55.2 R56.2 R57.2 R58.2 R59.2 R60.2 ,
|
||||||
|
R61.2 R62.2 R63.2 R64.2 U1.6 U1.19 U2.6 U2.8 U2.18 U2.31 U2.37 U2.38 ,
|
||||||
|
U2.48 U3.7 U3.23 U7.2 U7.4 U16.8 U17.6 U17.17 U17.30 U17.39 U17.52 ,
|
||||||
|
U17.62 U17.72 U17.84 U17.95 U17.108 U17.121 U17.131 U17.143 U17.144 ,
|
||||||
|
U18.7 U18.18 U18.31 U18.42 U19.8
|
||||||
|
'ADC1_GND' ; C29.1 R14.2 U3.50
|
||||||
|
'ADC2_GND' ; C34.1 R18.2 U3.52
|
||||||
|
'ADC3_GND' ; C35.1 R21.2 U3.54
|
||||||
|
'ADC4_GND' ; C36.1 R25.2 U3.56
|
||||||
|
'ADC5_GND' ; C38.1 R27.2 U3.58
|
||||||
|
'ADC6_GND' ; C43.1 R30.2 U3.60
|
||||||
|
'ADC7_GND' ; C44.1 R32.2 U3.62
|
||||||
|
'ADC8_GND' ; C30.1 R15.2 U3.64
|
||||||
|
'C3.3V' ; C48.1 C51.2 C64.1 C65.1 C66.1 C67.1 R35.1 U4.4 U9.8 U10.8 U11.8 ,
|
||||||
|
U13.16 U15.8
|
||||||
|
'CF_P' ; U5.A9 U14.1
|
||||||
|
'CF_Q' ; U5.B9 U14.2
|
||||||
|
'CH395F_SCK' ; U1.30 U17.74
|
||||||
|
'CH395F_SCS' ; U1.29 U17.73
|
||||||
|
'CH395F_SDI' ; U1.31 U17.76
|
||||||
|
'CH395F_SDO' ; U1.32 U17.75
|
||||||
|
'CLZ_LED' ; U5.C5 U18.20
|
||||||
|
'DIS_EEE' ; J1.10 R6.2 U2.29
|
||||||
|
'ERT_LED' ; U5.A13 U18.13
|
||||||
|
'G3.3V' ; C54.1 C55.1 C60.2 C61.1 C62.1 C63.1 D1.1 L4.1 R34.1 U6.2 U6.4 U9.1 ,
|
||||||
|
U10.1 U11.1
|
||||||
|
'GD_CS' ; R43.2 U17.141 U19.1
|
||||||
|
'GD_HOLD' ; U17.142 U19.7
|
||||||
|
'GD_SCLK' ; U17.133 U19.6
|
||||||
|
'GD_SI' ; U17.135 U19.5
|
||||||
|
'GD_SO' ; U17.134 U19.2
|
||||||
|
'GD_WP' ; U17.139 U19.3
|
||||||
|
'HT_A23' ; U5.B12 U18.19
|
||||||
|
'HT_A26' ; U5.A14 U18.9
|
||||||
|
'HT_C25' ; U5.B14 U18.11
|
||||||
|
'HT_C26' ; U5.A11 U18.22
|
||||||
|
'HT_C27' ; U5.B11 U18.23
|
||||||
|
'LCD_BK' ; H1.15 U17.28
|
||||||
|
'LCD_CD' ; H1.6 U17.27
|
||||||
|
'LCD_CS' ; H1.5 U17.26
|
||||||
|
'LCD_DB0' ; H1.7 U17.10
|
||||||
|
'LCD_DB1' ; H1.8 U17.11
|
||||||
|
'LCD_DB2' ; H1.9 U17.12
|
||||||
|
'LCD_DB3' ; H1.10 U17.13
|
||||||
|
'LCD_DB4' ; H1.11 U17.14
|
||||||
|
'LCD_DB5' ; H1.12 U17.15
|
||||||
|
'LCD_DB6' ; H1.13 U17.18
|
||||||
|
'LCD_DB7' ; H1.14 U17.19
|
||||||
|
'LCD_RD' ; H1.4 U17.22
|
||||||
|
'LCD_RST' ; H1.2 U17.20
|
||||||
|
'LCD_WR' ; H1.3 U17.21
|
||||||
|
'RELAY_STO' ; U5.A12 U18.17
|
||||||
|
'RS232_RX1' ; CN1.10 D6.2 U13.13
|
||||||
|
'RS232_RX3' ; CN1.9 D3.2 U13.8 U14.6
|
||||||
|
'RS232_TX1' ; CN1.12 D5.2 U13.14
|
||||||
|
'RS232_TX3' ; CN1.11 D4.2 U13.7 U14.3
|
||||||
|
'RS485_A' ; CN1.4 U12.2 U15.6
|
||||||
|
'RS485_B' ; CN1.2 U12.1 U15.7
|
||||||
|
'RUN_LED' ; U5.C2 U18.8
|
||||||
|
'RX_N' ; T1.8 U2.15
|
||||||
|
'RX_P' ; T1.6 U2.14
|
||||||
|
'RXA_N' ; J1.2 U2.45
|
||||||
|
'RXA_P' ; J1.1 U2.44
|
||||||
|
'RXB_N' ; J2.2 U2.3
|
||||||
|
'RXB_P' ; J2.1 U2.2
|
||||||
|
'SD_SCL' ; R36.2 U16.6 U17.136
|
||||||
|
'SD_SDA' ; R37.2 U16.5 U17.137
|
||||||
|
'SPI1_SIMO' ; U17.78 U18.35
|
||||||
|
'SPI1_SOMI' ; U17.77 U18.33
|
||||||
|
'ST_DIR4' ; U8.2 U17.114
|
||||||
|
'ST_IN_C3' ; U17.2 U18.3
|
||||||
|
'ST_IN_D4' ; U17.1 U18.2
|
||||||
|
'ST_IN_E4' ; U17.3 U18.5
|
||||||
|
'ST_RX0' ; U5.B10 U17.102
|
||||||
|
'ST_RX1' ; U9.2 U17.122
|
||||||
|
'ST_RX2' ; U5.C6 U17.70
|
||||||
|
'ST_RX3' ; U10.2 U17.112
|
||||||
|
'ST_RX4' ; U11.2 U17.116
|
||||||
|
'ST_TX0' ; U5.A10 U17.101
|
||||||
|
'ST_TX1' ; U9.3 U17.119
|
||||||
|
'ST_TX2' ; U5.C7 U17.69
|
||||||
|
'ST_TX3' ; U10.3 U17.111
|
||||||
|
'ST_TX4' ; U11.3 U17.113
|
||||||
|
'STM_VDDA' ; C77.2 C78.2 L6.2 U17.32 U17.33
|
||||||
|
'TP_BUSY' ; U3.14 U17.123
|
||||||
|
'TP_CONVST' ; U3.9 U3.10 U17.118
|
||||||
|
'TP_FRSTDATA' ; R24.1 U17.115
|
||||||
|
'TP_OS0' ; U3.3 U17.53
|
||||||
|
'TP_OS1' ; U3.4 U17.54
|
||||||
|
'TP_OS2' ; U3.5 U17.55
|
||||||
|
'TP_RD' ; U3.12 U17.117
|
||||||
|
'TRIP_LED' ; U5.C3 U18.12
|
||||||
|
'TX_N' ; T1.3 U2.16
|
||||||
|
'TX_P' ; T1.1 U2.17
|
||||||
|
'TXA_N' ; J1.6 U2.46
|
||||||
|
'TXA_P' ; J1.3 U2.47
|
||||||
|
'TXB_N' ; J2.6 U2.4
|
||||||
|
'TXB_P' ; J2.3 U2.5
|
||||||
|
'V_ZL1' ; R51.1 U5.A7
|
||||||
|
'V_ZL2' ; R52.1 U5.C11
|
||||||
|
5V ; C45.1 C49.1 C52.1 C53.1 C56.1 C57.1 L1.1 L3.2 U6.3 U7.3
|
||||||
|
ADC1 ; C29.2 R12.2 U3.49
|
||||||
|
ADC10 ; C103.2 R46.2 U17.35
|
||||||
|
ADC11 ; C104.2 R48.2 U17.36
|
||||||
|
ADC12 ; C105.2 R20.2 U17.37
|
||||||
|
ADC13 ; C106.2 R45.2 U17.40
|
||||||
|
ADC14 ; C107.2 R47.2 U17.41
|
||||||
|
ADC15 ; C108.2 R49.2 U17.42
|
||||||
|
ADC16 ; C110.2 R51.2 U17.43
|
||||||
|
ADC17 ; C111.2 R52.2 U17.46
|
||||||
|
ADC2 ; C34.2 R17.2 U3.51
|
||||||
|
ADC3 ; C35.2 R19.2 U3.53
|
||||||
|
ADC4 ; C36.2 R23.2 U3.55
|
||||||
|
ADC5 ; C38.2 R26.2 U3.57
|
||||||
|
ADC6 ; C43.2 R28.2 U3.59
|
||||||
|
ADC7 ; C44.2 R31.2 U3.61
|
||||||
|
ADC8 ; C30.2 R13.2 U3.63
|
||||||
|
ADC9 ; C101.2 R5.2 U17.34
|
||||||
|
AGND ; C32.2 C33.2 C37.2 C39.2 C41.2 C42.2 C77.1 C78.1 C95.2 C96.2 C97.2 C98.2 ,
|
||||||
|
C101.1 C103.1 C104.1 C105.1 C106.1 C107.1 C108.1 C110.1 C111.1 L2.1 ,
|
||||||
|
R14.1 R15.1 R18.1 R21.1 R25.1 R27.1 R30.1 R32.1 U3.2 U3.26 U3.35 U3.40 ,
|
||||||
|
U3.41 U3.43 U3.46 U3.47 U17.31
|
||||||
|
AIN1 ; R12.1 U5.A3
|
||||||
|
AIN10 ; R46.1 U5.C9
|
||||||
|
AIN11 ; R48.1 U5.C10
|
||||||
|
AIN12 ; R20.1 U5.B3
|
||||||
|
AIN13 ; R45.1 U5.A6
|
||||||
|
AIN14 ; R47.1 U5.C12
|
||||||
|
AIN15 ; R49.1 U5.B4
|
||||||
|
AIN2 ; R17.1 U5.B7
|
||||||
|
AIN3 ; R19.1 U5.C14
|
||||||
|
AIN4 ; R23.1 U5.A4
|
||||||
|
AIN5 ; R26.1 U5.B6
|
||||||
|
AIN6 ; R28.1 U5.C13
|
||||||
|
AIN7 ; R31.1 U5.A5
|
||||||
|
AIN8 ; R13.1 U5.B5
|
||||||
|
AIN9 ; R5.1 U5.A8
|
||||||
|
AVCC ; C32.1 C33.1 C95.1 C96.1 C97.1 C98.1 L1.2 U3.1 U3.37 U3.38 U3.48
|
||||||
|
AVDDL ; C3.1 C4.1 C5.1 C6.1 C7.1 C8.1 C9.1 C10.1 R10.2 U2.1 U2.7 U2.13 U2.23 ,
|
||||||
|
U2.24 U2.35 U2.36 U2.41 U2.43
|
||||||
|
CGND ; C48.2 C51.1 C64.2 C65.2 C66.2 C67.2 C69.1 C70.1 CN1.7 CN1.8 D3.1 D4.1 ,
|
||||||
|
D5.1 D6.1 U4.3 U8.3 U9.5 U10.5 U11.5 U12.3 U13.15 U14.4 U14.5 U15.5 ,
|
||||||
|
U22.1
|
||||||
|
CLOCK ; U5.C8 U14.7
|
||||||
|
DB0 ; U3.16 U17.56
|
||||||
|
DB1 ; U3.17 U17.57
|
||||||
|
DB10 ; U3.28 U17.125
|
||||||
|
DB11 ; U3.29 U17.126
|
||||||
|
DB12 ; U3.30 U17.127
|
||||||
|
DB13 ; U3.31 U17.128
|
||||||
|
DB14 ; U3.32 U17.129
|
||||||
|
DB15 ; U3.33 U17.132
|
||||||
|
DB2 ; U3.18 U17.87
|
||||||
|
DB3 ; U3.19 U17.88
|
||||||
|
DB4 ; U3.20 U17.89
|
||||||
|
DB5 ; U3.21 U17.90
|
||||||
|
DB6 ; U3.22 U17.91
|
||||||
|
DB7 ; U3.24 U17.92
|
||||||
|
DB8 ; U3.25 U17.93
|
||||||
|
DB9 ; U3.27 U17.124
|
||||||
|
DIR4 ; R35.2 U8.4 U15.2 U15.3
|
||||||
|
DQM0 ; U17.96 U18.32
|
||||||
|
DQM1 ; U17.98 U18.29
|
||||||
|
EXTKI1 ; U5.C1 U18.44
|
||||||
|
EXTKI2 ; U5.B16 U18.46
|
||||||
|
EXTKI3 ; U5.A16 U18.47
|
||||||
|
EXTKO1 ; U5.B13 U18.14
|
||||||
|
EXTKO2 ; U5.C4 U18.16
|
||||||
|
EXTKO3 ; U5.A15 U18.6
|
||||||
|
F3 ; U17.82 U18.38
|
||||||
|
GND ; C1.2 C2.2 C3.2 C4.2 C5.2 C6.2 C7.2 C8.2 C9.2 C10.2 C11.1 C12.2 C13.2 ,
|
||||||
|
C14.2 C15.2 C16.2 C17.2 C18.2 C19.2 C20.2 C21.2 C22.2 C23.1 C24.1 ,
|
||||||
|
C25.1 C26.1 C27.1 C28.1 C40.1 C45.2 C46.2 C47.2 C49.2 C50.1 C52.2 ,
|
||||||
|
C53.2 C54.2 C55.2 C56.2 C57.2 C58.2 C59.2 C60.1 C61.2 C62.2 C63.2 ,
|
||||||
|
C72.1 C73.1 C74.1 C75.1 C76.1 C79.1 C80.2 C81.2 C82.2 C83.2 C84.2 ,
|
||||||
|
C85.2 C86.2 C87.2 C88.2 C89.2 C90.2 C91.2 C92.2 C93.1 C94.1 C99.2 ,
|
||||||
|
C100.2 C102.2 D1.2 D2.2 H1.16 H2.3 J2.10 L2.2 LED4.1 Q1.2 R3.2 R4.2 ,
|
||||||
|
R11.2 R16.2 R22.1 R39.2 R42.1 SW1.1 SW2.1 SW2.2 SW3.1 SW3.2 SW4.1 ,
|
||||||
|
SW4.2 SW5.1 SW5.2 SW6.1 SW6.2 SW7.1 SW7.2 SW8.1 SW8.2 SW9.1 SW9.2 ,
|
||||||
|
U1.33 U2.49 U3.8 U3.13 U4.1 U5.A1 U5.B1 U5.C16 U6.1 U7.1 U9.4 U10.4 ,
|
||||||
|
U11.4 U14.8 U16.4 U17.16 U17.38 U17.51 U17.61 U17.83 U17.94 U17.107 ,
|
||||||
|
U17.120 U17.130 U17.138 U18.4 U18.10 U18.15 U18.21 U18.28 U18.34 ,
|
||||||
|
U18.39 U18.45 U19.4 U19.9 U20.1 U21.1 X1.2 X1.4 X2.2 X2.4 X3.2 X3.4
|
||||||
|
H16 ; U17.79 U18.43
|
||||||
|
HRST ; C31.2 R16.1 U3.11
|
||||||
|
INT ; U1.15 U17.4
|
||||||
|
J3 ; U17.81 U18.40
|
||||||
|
K3 ; U17.86 U18.36
|
||||||
|
KEY1 ; R44.1 SW2.3 SW2.4 U17.58
|
||||||
|
KEY2 ; R50.1 SW3.3 SW3.4 U17.59
|
||||||
|
KEY3 ; R53.1 SW4.3 SW4.4 U17.60
|
||||||
|
KEY4 ; R54.1 SW5.3 SW5.4 U17.63
|
||||||
|
KEY5 ; R55.1 SW6.3 SW6.4 U17.64
|
||||||
|
KEY6 ; R56.1 SW7.3 SW7.4 U17.65
|
||||||
|
KEY7 ; R57.1 SW8.3 SW8.4 U17.66
|
||||||
|
KEY8 ; R58.1 SW9.3 SW9.4 U17.67
|
||||||
|
LED1 ; LED5.1 U17.44
|
||||||
|
LED2 ; LED6.1 U17.45
|
||||||
|
LED3 ; LED7.1 U17.47
|
||||||
|
LED4 ; LED8.1 U17.48
|
||||||
|
LED5 ; LED9.1 U17.49
|
||||||
|
LED6 ; LED10.1 U17.50
|
||||||
|
NRST ; C14.1 C74.2 R40.1 SW1.2 U1.10 U2.27 U17.25
|
||||||
|
PBLED ; R2.2 U2.30
|
||||||
|
PGND ; J1.8 J1.SH1 J1.SH2 J2.8 J2.SH1 J2.SH2 U14.13 U20.2 U21.2 U22.2
|
||||||
|
R16 ; U17.85 U18.37
|
||||||
|
RAS ; U17.99 U18.27
|
||||||
|
RX1 ; U9.7 U13.12
|
||||||
|
RX3 ; U10.7 U13.9
|
||||||
|
RX4 ; U11.7 U15.1
|
||||||
|
RXI ; C25.2 U2.40 X1.1
|
||||||
|
RXO ; C26.2 U2.39 X1.3
|
||||||
|
SDCKE ; U17.109 U18.26
|
||||||
|
SWCLK ; H2.2 U17.104
|
||||||
|
SWDIO ; H2.1 U17.105
|
||||||
|
TX1 ; U9.6 U13.11
|
||||||
|
TX3 ; U10.6 U13.10
|
||||||
|
TX4 ; U11.6 U15.4
|
||||||
|
V15 ; U17.80 U18.41
|
||||||
|
VDD50 ; C46.1 C47.1 C99.1 L3.1 U5.A2 U5.B2 U5.C15
|
||||||
|
WAIT1 ; U17.97 U18.30
|
||||||
|
XI ; C27.2 U1.12 X2.1
|
||||||
|
XO ; C28.2 U1.13 X2.3
|
||||||
|
$SCHEDULE
|
||||||
|
$END
|
||||||
@@ -0,0 +1,407 @@
|
|||||||
|
# V0.0 硬件网表详细分析报告
|
||||||
|
|
||||||
|
> **一句话结论**:架构完整、实板在跑,网表与实板无实质性电气矛盾;**19 颗芯片料号全部确认**(其中 9 颗本次新确认,8 颗经手册逐脚核实、U4 经丝印+脚位核实);**3 处设计缺陷**(B3 可纯代码解决)、**2 项 BOM/网表清理**、**4 项待核**;最大系统性风险 = 验证全在"开机标记级",功能级"静默死亡"无法发现(§1.6、§5)。
|
||||||
|
>
|
||||||
|
> **文档结构**:§1 结论速览 → §2 总体架构 → §3 问题清单 → §4 逐芯片详解 → §5 改进方向 → §6 最优先三件事 → 附录 A 勘误记录 / 附录 B 手册清单。
|
||||||
|
|
||||||
|
- **分析对象**:`V0.0.tel`(369 行,本目录)
|
||||||
|
- **对照依据**:`docs/芯片手册/`(12 份芯片手册 + 2 份 STM32 参考件,见附录 B)、`AGENTS.md`、`STM32F407-Demo.ioc`、`Drivers/BSP/` 驱动代码、`docs/问题记录/`、`docs/测试说明/`
|
||||||
|
- **分析日期**:2026-09-15
|
||||||
|
- **核实方法**:网表逐脚对照手册 → 代码/.ioc 交叉 → 实板开机标记反推;初版误判已全部撤回,汇总见**附录 A**
|
||||||
|
|
||||||
|
## 1. 结论速览
|
||||||
|
|
||||||
|
### 1.1 状态总览
|
||||||
|
|
||||||
|
| 项 | 结论 |
|
||||||
|
|---|---|
|
||||||
|
| 架构/实板 | 完整且在跑:网络/ADC/NAND/RTC/RS485 均通过开机标记 |
|
||||||
|
| 芯片料号 | 19 颗全部确认(§1.2 总表) |
|
||||||
|
| 设计缺陷 | **3 处** B1/B2/B3(§3.1) |
|
||||||
|
| BOM/网表清理 | **2 项** A1/A2(§3.2,网表与实板不符,V0.1 更新) |
|
||||||
|
| 待核项 | **4 项**(§3.3) |
|
||||||
|
| 系统性风险 | 验证全为开机级、功能级盲区 →"静默功能死亡"(§1.6) |
|
||||||
|
|
||||||
|
### 1.2 芯片料号总表
|
||||||
|
|
||||||
|
| 芯片 | 确认料号 | 功能 | 核实方式 | 备注 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| U1 | CH395F | 以太网 MAC+PHY(SPI2 从设备) | 逐脚 | 手册在库 |
|
||||||
|
| U2 | RTL8305NBI-CG | 5 端口 10/100 交换 | 逐脚 | **B1** |
|
||||||
|
| U3 | TPAFE5160 | 8ch 16 位并行 ADC | 逐脚 | — |
|
||||||
|
| U4 | B0303S | 3.3V→3.3V 隔离 DC-DC | 丝印+脚位+手册 | 手册在库(B0303S.md);**A2** |
|
||||||
|
| U5 | WINGTAT 48pin | 子板连接器 | — | **B2**(无独立电源输入) |
|
||||||
|
| U6/U7 | SOT-223 LDO ×2 | 5V→G3.3V / 5V→3.3V | 逐脚 | **B2** |
|
||||||
|
| U8 | FOC-817SC-F | RS485 DE/RE 光耦隔离 | 逐脚 | CTR 分档待丝印核 |
|
||||||
|
| U9/U10/U11 | CA-IS3722HS ×3 | 双通道数字隔离器 | 逐脚 | U11=RS485#4、U9/U10=RS232#1/#3 |
|
||||||
|
| U12 | SuperESD-CDSOT23 | A/B 线 ESD 阵列 | 逐脚 | 无源 |
|
||||||
|
| U13 | TPT3232E | 双路 RS232 收发器 | 逐脚 | 非 MAX 惯例引脚 |
|
||||||
|
| U14 | C2836689 RJ45 | 多用途数据连接器 | — | 模块手册待补(§3.3-2) |
|
||||||
|
| U15 | TP8485E-SR | RS485 收发器 | 逐脚 | — |
|
||||||
|
| U16 | SD2506API-G | I2C RTC 模块 | 逐脚 | 内置晶振+充电电池 |
|
||||||
|
| U17 | STM32F407ZGT6 | 主控(LQFP-144) | 代码/.ioc 交叉 | 封装引脚编号待实物抽查(§3.3-3) |
|
||||||
|
| U18 | AIP74LVC16245TA48 | 双 8 位总线收发器(子板桥) | 逐脚(48 脚全对) | **B3** |
|
||||||
|
| U19 | GD5F2GQ5UE | SPI NAND(WSON-8) | 逐脚 | — |
|
||||||
|
|
||||||
|
> 其中 U4、U8、U9~U11、U12、U13、U15、U18(9 颗)为本次分析新确认;其余 10 颗原已知料号。
|
||||||
|
|
||||||
|
### 1.3 设计缺陷(3 处,详情 §3.1)
|
||||||
|
|
||||||
|
| # | 摘要 | 修复 |
|
||||||
|
|---|---|---|
|
||||||
|
| B1 | RTL8305 V33IN 缺串联肖特基 + MDC/MDIO 悬空(无 SMI) | V0.1 改板 + 代码 SMI 初始化 |
|
||||||
|
| B2 | 3.3V 主轨 SOT-223 LDO 余量 + 板级无独立 5V 输入 | V0.1:主轨改 buck + 5V 排针 |
|
||||||
|
| B3 | U18 桥:11 个悬空 GPIO → 子板输出线电平不定;SPI1 MISO/MOSI 耦合至子板 EXTKO1/2 | **① 代码配置 11 个 GPIO(无需改板)** ② V0.1 改线 |
|
||||||
|
|
||||||
|
### 1.4 BOM/网表清理(2 项,详情 §3.2)
|
||||||
|
|
||||||
|
| # | 事项 |
|
||||||
|
|---|---|
|
||||||
|
| A1 | D1/D2 网表记"已放置",实为 DNP |
|
||||||
|
| A2 | U4 网表料号 B0505S-1WR3,实为 B0303S |
|
||||||
|
|
||||||
|
### 1.5 待核项(4 项,详情 §3.3)
|
||||||
|
|
||||||
|
1. H1102NLT 共模磁环手册(T1)
|
||||||
|
2. HR911105A RJ45 模块手册(J1/J2)
|
||||||
|
3. STM32 封装引脚编号实物抽查(3 脚)
|
||||||
|
4. X1 25MHz 晶振选料参数(±50ppm / ESR<50Ω)
|
||||||
|
|
||||||
|
### 1.6 系统性风险:"静默功能死亡"
|
||||||
|
|
||||||
|
当前验证链全是"开机级标记"(`ADC init:` 只证明 GPIO 配置成功、不证明转换功能;RS485/RS232/ADC 均无功能级测试)——串口段(U8 DE/RE 通路、U15 总线、CN1 环回)或 ADC 即使真死了,现有测试也会全部 PASS。对策:一次性上电测量清单(§5.1)+ 开机功能级断言(§5.2)。
|
||||||
|
|
||||||
|
## 2. 总体架构
|
||||||
|
|
||||||
|
### 2.1 电源树
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
P5["子板 5V(U5: A2/B2/C15)"] --> F1["C46/C47 + C99 470uF + L3"]
|
||||||
|
F1 --> V5["5V 轨(C45 220uF + C49/52/53/56/57)"]
|
||||||
|
V5 -->|"L1 磁珠"| AVCC["AVCC → TPAFE5160 AVDD×4"]
|
||||||
|
V5 --> U7["U7 SOT223 LDO"]
|
||||||
|
V5 --> U6["U6 SOT223 LDO"]
|
||||||
|
U7 --> V33["3.3V 主轨(C11 10uF + 22×100nF)"]
|
||||||
|
U6 --> VG33["G3.3V(C54/55/60-63)"]
|
||||||
|
VG33 --> L4U4["L4 → U4 B0303S 隔离电源(3.3V→3.3V, 1W)"]
|
||||||
|
L4U4 --> VC33["C3.3V/CGND 隔离电源域(U8-U15 串口段, CN1)"]
|
||||||
|
V33 -->|"L6 磁珠"| VDDA["STM_VDDA(C77/C78→AGND)→ STM32 VDDA/VSSA"]
|
||||||
|
V33 --> H1["H1.1 → 显示模块(8080 LCD)"]
|
||||||
|
V33 -->|"U2 pin37 V33IN → 片内 LDO"| V10["AVDDL 1.0V(C3 220uF + C4-C10 7×100nF + Q1 指示)"]
|
||||||
|
GND["GND(主数字地)"] -->|"L2 0603 电感(单点桥)"| AGND["AGND(TPAFE 模拟地,与 GND 分割)"]
|
||||||
|
GND -.->|"U20/U21 4.7nF(AC 耦合)"| PGND["PGND(RJ45 屏蔽地: J1/J2/U14 shield)"]
|
||||||
|
VC33 -.->|"U22 4.7nF(AC 耦合)"| PGND
|
||||||
|
```
|
||||||
|
|
||||||
|
**四个电源/地域**:
|
||||||
|
|
||||||
|
- **GND** 主数字地;**AGND** TPAFE 模拟地,经 L2 0603 电感与 GND 单点桥(DC 连通 + 高频隔离)
|
||||||
|
- **C3.3V/CGND** 隔离域:U4(B0303S)3.3V→3.3V 隔离输出,供对外串口段(U8~U15、CN1),与主数字地直流隔离
|
||||||
|
- **PGND** RJ45 屏蔽地,经 U20-U22 4.7nF 与 GND/CGND 交流耦合(屏蔽不直连)
|
||||||
|
- 3.3V 双轨:G3.3V(U6,隔离电源输入侧)与 3.3V 主轨(U7),间有 ~0.1-0.3V 偏移(随 B2 修复并轨)
|
||||||
|
|
||||||
|
### 2.2 六大信号子系统
|
||||||
|
|
||||||
|
| 子系统 | 路径 | 状态 |
|
||||||
|
|---|---|---|
|
||||||
|
| 以太网 | CH395F(SPI2+DMA) → T1(350uH CM 磁环) → RTL8305NB port3 → 内部 crossbar → port0/1 → J1/J2(集成磁 RJ45) → 网线 | **在跑**(Trap05:CH395F PHY 与 RTL8305NBI 自协商不兼容 → 代码 `ch395f_set_phy(0x08)` 强制 100M 全双工后稳定) |
|
||||||
|
| 模拟采集 | 15 路 AIN(10 路 → TPAFE5160 8ch+备用,5 路 → STM32 ADC,均 1k+1k 匹配阻抗+滤波)→ 16 位并口回 STM32 | 开机标记通过(**功能级未验证**,见 §3.1/B3 与 §5) |
|
||||||
|
| 存储 | GD5F2GQ5UE(WSON8, SPI1) + SD 卡(FatFS) | NAND init 标记通过 |
|
||||||
|
| 时钟 | SD2506API(I2C RTC 模块:内置晶振 + 内置充电电池 + 充电电路) → 墙钟子系统 | SD2506 ID 读取通过(功能性验证);内置电池掉电自动续走,代码开机写 18H=0x82 使能充电并读 battery: 标记 |
|
||||||
|
| 串口 | USART1 调试口;U5 直连 UART×2;RS232×2(U9/U10 数字隔离器→U13 TPT3232E→CN1,其中 #3 复用 U14 RJ45);RS485(USART5→U11 数字隔离器→U15→A/B→CN1;DE/RE 经 U8 光耦 FOC-817 跨界;U12 = SuperESD 防静电阵列并接 A/B,对 CGND 钳位) | 初始化标记通过(**功能级未验证**) |
|
||||||
|
| 显示/扩展 | H1(16pin) 8080 LCD 接口 → 显示模块;U18(TSSOP48) AIP74LVC16245 双 8 位总线收发器(strapping 锁定 A→B 常通):子板 EXTKI×3→PC13/14/15、11 个未配置 GPIO→子板 LED/继电器/HT/EXTKO、SPI1 MISO/MOSI→子板 EXTKO1/2 | 代码未读 PC13/14/15、未驱动 11 个 GPIO(子板输出电平不定,**B3**) |
|
||||||
|
|
||||||
|
### 2.3 关键架构事实
|
||||||
|
|
||||||
|
1. **RTL8305NB 工作在未编程默认状态**(Trap05 反推证实):MDC/MDIO(pin25/26)悬空、无 EEPROM,靠默认 crossbar/VLAN 配置桥接 port3↔port0/1;strapping 仅用 DIS_EEE(pin29,R6 10k 上拉 = 禁 EEE;该脚为 I/O_PD 双功能脚,兼作 P0LED 指示并接 J1 模块 LED)。该拓扑实测可跑 100M,前提是**默认配置恰好匹配**,属脆弱平衡(B1)。
|
||||||
|
2. **串口段为完整隔离设计**:电源(U4)+ TX/RX(U11/U9/U10 数字隔离器)+ DE/RE(U8 光耦)三路均经隔离器件跨界,对外 485 口与主数字地完全隔离(仅 0.6-1pF 光浮电容耦合)。
|
||||||
|
|
||||||
|
## 3. 问题清单
|
||||||
|
|
||||||
|
### 3.1 设计缺陷(3 处,V0.1 应修)
|
||||||
|
|
||||||
|
| # | 问题 | 影响 | 修复 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| B1 | RTL8305 V33IN 缺手册要求的串联肖特基(3.3V 直连);MDC/MDIO 悬空(无 SMI) | 掉电时 V33IN 可倒灌 3.3V 主轨、破坏上电时序并威胁片内 LDO;PHY 全参数锁死默认态,Trap05 只能单边强制 | 3.3V→V33IN 串肖特基(BAT54/SS34,阳极接 3.3V、阴极接 V33IN,Vf 小,禁硅 PN);引 MDC/MDIO 至 STM32 GPIO(代码加 SMI 初始化:port3 强制 100F、LED 配置、VLAN 确认) |
|
||||||
|
| B2 | 3.3V 主轨 SOT-223 LDO;板级无独立 5V 输入 | 峰值电流/热余量存疑;单独调试必须依赖子板线缆 | 主轨改 buck(顺带并掉 G3.3V 双轨偏移);加 5V 调试排针 + TVS |
|
||||||
|
| B3 | U18 桥(AIP74LVC16245,strapping 锁定 A→B 恒使能):A 侧 11 个 GPIO(H16/V15/J3/F3/R16/K3/DQM0/WAIT1/DQM1/RAS/SDCKE)未配置悬空 → 子板 LED×4/RELAY_STO/HT×5/EXTKO3 电平不定;SPI1 MISO/MOSI 耦合至子板 EXTKO1/2(SPI 流量干扰) | 子板输出态(含继电器)随机;子板若用 EXTKO1/2 将被干扰 | ① 代码显式配置 11 个 GPIO 为安全默认电平(LED 灭/继电器断/告警静默,**无需改硬件**)② V0.1 改线 2A1/2A2→EXTKO1/2 耦合(或确认子板未用此 2 线) |
|
||||||
|
|
||||||
|
### 3.2 BOM/网表清理(2 项,V0.1)
|
||||||
|
|
||||||
|
初判的"网表↔实板矛盾"4 项已全部澄清撤回(CH395F TXD、SD2506 封装、D1/D2、U4,见附录 A);遗留清理项:
|
||||||
|
|
||||||
|
| # | 位置 | 网表记载 | 实际状态 | 处理 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| A1 | D1/D2 (SMB) | 记为已放置 | DNP 未贴(设计意图防浪涌,对板内电源轨意义有限) | V0.1 去掉焊盘 + 网表标 DNP |
|
||||||
|
| A2 | U4 料号 | B0505S-1WR3(5V 入/5V 出) | B0303S(3V 入/3V 出隔离电源) | V0.1 更新料号并更换焊盘 |
|
||||||
|
|
||||||
|
### 3.3 待核项(4 项)
|
||||||
|
|
||||||
|
1. **H1102NLT 共模磁环**(T1):绕组布局靠实跑反推(交叠式),手册未入库。
|
||||||
|
2. **HR911105A RJ45**(J1/J2):集成磁已反证成立;pin9(LED)/pin10(strapping)/pin4,5(屏蔽) 定义待模块手册确认。
|
||||||
|
3. **STM32 封装引脚编号**:网表与代码自洽(59 配置脚全交叉),实物抽查 3 脚后关闭(pin25=NRST、pin23/24=8MHz 波形、pin73=PB12 翻转,方法见 §5.1)。
|
||||||
|
4. **X1 25MHz 晶振**:手册要求 ±50ppm / ESR<50Ω,选料参数待核。
|
||||||
|
|
||||||
|
### 3.4 轻微改进(非缺陷,并入 V0.1,见 §5.3)
|
||||||
|
|
||||||
|
- T1 绕组远端 4/5/12/13 悬空 → 加对地旁路(EMI 细节)
|
||||||
|
- TPAFE RESET 无运行时复位能力、对 3.3V 毛刺敏感 → 可改 GPIO 控制(顺带获得软复位,见 §4.5)
|
||||||
|
- 网名 'R16'(U18 总线)与电阻 R16 撞名 → 改名防误读
|
||||||
|
|
||||||
|
## 4. 逐芯片详解
|
||||||
|
|
||||||
|
### 4.1 主控:U17 = STM32F407ZGT6(LQFP-144)
|
||||||
|
|
||||||
|
- 全部功能引脚与代码/.ioc 一一对应(59 个已配置脚);VDD×14、VDDA(pin32/33 经 L6)、NRST(pin25)= R40 10k 上拉 + 2×100nF(C14/C74) + SW1、HSE(pin23/24)= 8MHz + 12pF×2。
|
||||||
|
- 封装引脚编号(NRST=25、HSE=23/24、PB12-15=73-76、VDDA=32/33)与常见数据手册图记忆不符,但**与可工作代码+实板完全自洽** → 判定网表正确,实物抽查 3 脚后关闭(§3.3-3)。
|
||||||
|
- 悬空脚:U17.7 及若干未配置 GPIO——复位后高阻,正常;U18 A 侧 13 线中 11 线(H16/V15/J3/F3/R16/K3/DQM0/WAIT1/DQM1/RAS/SDCKE)为未配置悬空、无人驱动(**B3**,见 §4.6),另 2 线为 SPI1 MISO/MOSI(活动信号)。
|
||||||
|
|
||||||
|
### 4.2 以太网段:U1、U2、T1、J1/J2、X1/X2
|
||||||
|
|
||||||
|
#### U1 = CH395F(QFN-32,以太网 MAC+PHY,SPI 从设备)
|
||||||
|
|
||||||
|
- 引脚全对:SCS/SCK/SDI/SDO→PB12-15(封装 pin73-76)、INT→PA0(pin4)、RSTI←NRST、VDDK 1uF(C13)、晶振 X2 25MHz+12pF×2、ELINK#/EACT#→LED1/LED2(470Ω 上拉,低有效)。
|
||||||
|
- TXD 脚为 5.1k **下拉** = SPI 模式配置正确(初版"下拉可疑"疑虑已排除,见附录 A-9)。
|
||||||
|
|
||||||
|
#### U2 = RTL8305NBI-CG(QFN-48,5 端口 10/100 PHY 交换)
|
||||||
|
|
||||||
|
- port3(pin14-17)→T1→CH395F;port0(pin44-47)→J1;port1(pin2-5)→J2;port2/4 未用。
|
||||||
|
- 电源:V33IN(pin37)=3.3V;1.0V 核心由**片内 LDO** 生成(V10OUT=pin36=AVDDL,C3 220uF+7×100nF)——**无需电感**(手册 L269:"integrates one LDO regulator to generate 1.0V from a 3.3V input power, and needs only one external diode");RESETB(pin27)←主 NRST(与 MCU 同步复位,满足上电时序 Td>5ms 建议)。
|
||||||
|
- **B1(两项)**:
|
||||||
|
1. 手册要求 1 个外部二极管(L269/L336/L985;参考设计图在库内 md 中缺失,接法以手册参考设计为准):**在 3.3V→V33IN(pin37) 通路串联肖特基**,阳极接 3.3V 轨、阴极接 V33IN——上电时 3.3V 正向导通给 LDO 供电(仅降 Vf);掉电时若 V33IN 电位高于 3.3V 轨则反向截止,**防止 V33IN 倒灌回系统 3.3V 主轨、破坏上电时序(Ta<Tb),保护片内 LDO**。选型:肖特基(BAT54/SS34),Vf 尽量小,**不能用普通硅 PN 二极管**。V0.0 网表缺此二极管(U2.37 直连 3.3V 轨)——V0.1 必加。
|
||||||
|
2. MDC/MDIO 悬空 = 无 SMI 编程能力:端口速率/双工、LED 行为、VLAN 均锁死在默认值;Trap05 的"强制 100M"只在 CH395F 侧生效,交换侧不可调——当前能跑是**默认配置恰好匹配**,属脆弱平衡。
|
||||||
|
- P0LED/DIS_EEE(pin29)为**双功能脚**(I/O_PD 开漏):同一节点 {U2.29, R6 10k 上拉, J1.10(模块 LED 脚)}——上电时 10k 上拉给出 DIS_EEE=1(禁 EEE);PHY 初始化后 pin29 仍可拉低作 P0LED 链路/活动指示,10k 上拉兼作 LED 上拉 → **J1 有 PHY LED 指示,设计正确**(J2 同理:P1LED 经 R2 470Ω → J2.9;两侧上拉值不对称 10k/470Ω,对 LED 通断状态无实质影响)。
|
||||||
|
|
||||||
|
#### T1 = 350uH 16 脚共模磁环(H1102NLT)
|
||||||
|
|
||||||
|
- CH395F MDI ↔ RTL8305 port3 交叉配对完整(RXP↔TXOP3、RXN↔TXON3、TXP↔RXIP3、TXN↔RXIN3),**依赖交叠绕组布局 (1,16)(3,14)(6,11)(8,9)**——Trap05 证实该路径实测通流(100M),布局推断成立。
|
||||||
|
- 小缺陷(§3.4):绕组远端 T1.4/5/12/13 悬空(无对地旁路),EMI 细节;手册未入库(§3.3-1)。
|
||||||
|
|
||||||
|
#### J1/J2 = HR911105A RJ45
|
||||||
|
|
||||||
|
- MDI 直连(无外挂变压器)⇒ 模块必为**集成网络变压器型**(100M 实测通过反证成立)。J1.10 = 模块 LED(U2 P0LED 驱动 + R6 10k 上拉)、J1.9 = 仅 470Ω 上拉(无 PHY 驱动,LED 灭)、J2.9 = 模块 LED(U2 P1LED 驱动 + R2 470Ω 上拉)、J2.10 = GND、pin4/5 = 屏蔽对地。引脚定义待模块手册(§3.3-2)。
|
||||||
|
|
||||||
|
#### X1/X2/X3 晶振
|
||||||
|
|
||||||
|
- X1=25MHz→U2(15pF×2;手册要求 ±50ppm / ESR<50Ω,选料待核 §3.3-4);X2=25MHz→U1(12pF×2);X3=8MHz→U17 HSE(12pF×2)。均正确。
|
||||||
|
|
||||||
|
### 4.3 电源段:U5、U6/U7、U4
|
||||||
|
|
||||||
|
#### U5 = 48pin 子板连接器(WINGTAT)
|
||||||
|
|
||||||
|
- 供电入口 VDD50(A2/B2/C15 三脚并联);15 路 AIN;ST_UART0/2 直连;EXTKI/EXTKO/CLZ_LED/ERT_LED 等全部经 U18 桥;CF_P/CF_Q、CLOCK 经 U14 RJ45 复用传子板。
|
||||||
|
- **B2(其一)**:板级无独立电源输入——单独调试必须经 48pin 线缆。V0.1 加 5V 排针。
|
||||||
|
|
||||||
|
#### U6/U7 = SOT-223-4 LDO(引脚 1=GND, 2/4=VOUT, 3=VIN,与标准一致)
|
||||||
|
|
||||||
|
- U6: 5V→G3.3V(收发器域);U7: 5V→3.3V(主轨)。
|
||||||
|
- **B2(其一)**:主 3.3V 轨负载 ≈ STM32(峰值 ~1A 量级)+CH395F+PHY 3.3V 群+NAND+RTC+U18+显示 H1,走 SOT-223 LDO 电流/热余量需核算(输入-输出压差 1.7V 上耗散可观);V0.1 建议主轨改 buck、G3.3V 并入主 3.3V 轨(C3.3V 轨为 U4 隔离电源输出,与输入侧 DC 隔离,不受并轨影响)。
|
||||||
|
|
||||||
|
#### U4 = B0303S 隔离电源芯片(隔离 DC-DC,TH 4 脚)
|
||||||
|
|
||||||
|
- 3.3V→3.3V 隔离电源:pin1=VIN−(GND)、pin2=VIN+(G3.3V,经 L4+C50)、pin3=VOUT−(CGND)、pin4=VOUT+(C3.3V)——4 脚接线即隔离电源的标准输入/输出,**正确**。
|
||||||
|
- 设计意图:对外部串口段(U8-U15 收发器/ESD 防护、CN1、C3.3V 轨)提供隔离 3.3V 电源域,CGND 与主数字地 GND 直流隔离,提升对外端口的 EMI/浪涌稳健性。
|
||||||
|
- **A2**:网表/焊盘记为 PWRM B0505S-1WR3(5V 入/5V 出),实物芯片为 B0303S(3V 入/3V 出)——实板与实际供电条件(输入 G3.3V≈3.3V)相符;V0.1 将网表料号更新为 B0303S 并更换焊盘。
|
||||||
|
- **手册在库**(`docs/芯片手册/B0303S.md`,EVISUN B_S-1WR3 系列):B0303S-1WR3 = 3.3V 输入(2.97~3.63V)/ 3.3V 输出 303mA / 1W / 隔离 1500VDC(1min) / 开关频率 200-340kHz / 持续短路保护——实物输入 G3.3V≈3.3V 在输入范围内、4 脚接线与手册标准输入/输出一致(初版误判"3Ω 功率电阻"已撤回,见 A-1;初版"手册未入库"判定系目录扫描误报,见 A-11)。
|
||||||
|
- 小注(非缺陷):该系列为**非稳压**输出(负载调节率 8% typ / 20% max,10%→100% 负载)——C3.3V 轨电压随串口段负载变化而 sag,隔离段各芯片(U8-U15)供电范围宽(3V~5.5V 类),当前负载水平下无影响;V0.1 若串口段负载显著增加需复核最低负载电压。
|
||||||
|
|
||||||
|
### 4.4 隔离串口段:U8~U15
|
||||||
|
|
||||||
|
**隔离拓扑总览**:对外 485/RS232 口与主数字地完全隔离——电源经 U4(隔离 DC-DC)跨界,TX/RX 经 U11/U9/U10(数字隔离器)跨界,DE/RE 经 U8(光耦)跨界,A/B 线 ESD 经 U12/D3-D6 钳位至 CGND。
|
||||||
|
|
||||||
|
#### U8 = FOC-817SC-F 光耦(RS485 DE/RE 隔离)
|
||||||
|
|
||||||
|
- 手册已入库(`docs/芯片手册/光耦隔离芯片FOC-817SC-F.md`,佛山市国星光电):红外 LED+光电晶体管,V_ISO=5kVrms、CTR 50-600%@IF=5mA/VCE=5V、V_CE(sat)≤0.2V、BV_CEO≥80V、隔离电容 0.6-1pF。
|
||||||
|
- **引脚定义(手册:1=阳极、2=阴极、3=发射极、4=集电极),网表逐脚核实为标准开集电极隔离接法**:
|
||||||
|
- LED 侧(主侧电源域):阳极(1) ← G3.3V 经 R34 390Ω(LED 限流电阻,IF≈(3.3−1.2)/390≈5.4mA);阴极(2) ← ST_DIR4(STM32 PD0)。
|
||||||
|
- 晶体管侧(隔离侧电源域):发射极(3) → CGND;集电极(4) → DIR4 → U15.2/3(DE+/RE− 并接)+ R35 1.5k 上拉至 C3.3V。
|
||||||
|
- **逻辑正确(LED 低有效、反相输出)**:PD0=1(发送)→ 阴极电位=阳极,LED 灭 → 晶体管截止 → DIR4=高(C3.3V)→ DE=1、/RE=1 = 发送态;PD0=0(空闲)→ LED 亮 → 晶体管导通 → DIR4≈V_CE(sat)≈0.1-0.3V → DE=0、/RE=0 = 接收态。
|
||||||
|
- 小注(非缺陷):817 截止频率 ~80kHz,DE/RE 慢信号充裕;CTR 裕量取决于分档——档 C(200-400%)最恶劣高温角(110°C,CTR×0.54)驱动电流仍 ≥5mA、对 2.2mA 下沉电流裕量充足;若实物为档 L(50-100%),≥100°C 角低电平略不足(最坏 DIR4 低 ≈1.3V > VIL 1.0V),可 V0.1 将 R35 1.5k 改 10k(分档以丝印核实)。
|
||||||
|
|
||||||
|
#### U9/U10/U11 = CA-IS3722HS 双通道数字隔离器
|
||||||
|
|
||||||
|
- 手册已入库(`docs/芯片手册/数字隔离器 CA-IS3722HS.md`):CA-IS371x/2x 系列,DC~150Mbps、CMTI ±100kV/µs、施密特输入、传播延迟 8ns typ;SOIC8 窄体 3.75kVrms(WB 宽体 5kV);"H"后缀 = 失电/失信号时输出默认高。
|
||||||
|
- **SOIC8 引脚定义(手册表 6-2),三颗网表全部逐脚吻合 CA-IS3722**:pin1=VDDA、pin2=VO1(通道1 A 侧输出)、pin3=VI2(通道2 A 侧输入)、pin4=GNDA、pin5=GNDB、pin6=VO2(通道2 B 侧输出)、pin7=VI1(通道1 B 侧输入)、pin8=VDDB——两通道方向相反:通道1 = B→A(pin7→pin2,RX 用)、通道2 = A→B(pin3→pin6,TX 用),恰为设计所需的 TX+RX 配对。
|
||||||
|
- U11(RS485 通道 #4):TX:U17.113(TX)→ST_TX4→U11.3 →[隔离]→ U11.6→TX4→U15.4(DI);RX:U15.1(RO)→RX4→U11.7 →[隔离]→ U11.2→ST_RX4→U17.116(RX)。8 脚全接、两侧各取本侧电源,接法正确。
|
||||||
|
- U9(RS232#1):U17.119(TX)→ST_TX1→U9.3 →[隔离]→ U9.6→TX1→U13.11(TIN1);U13.12(ROUT1)→RX1→U9.7 →[隔离]→ U9.2→ST_RX1→U17.122(RX)。U10(RS232#3):U17.111/112 ↔ U13.10/9,两侧同样全接、方向正确。
|
||||||
|
- 小注(非缺陷):"H"后缀 = 失电/失信号时输出默认高——主侧(STM32)掉电后 B 侧 TX 输出默认高,且 U8 光耦 LED 同时熄灭(DIR4 被 R35 拉高 → DE=1);若隔离侧电源仍存活,收发器可能对总线驱动不定电平。如需掉电"总线静默",V0.1 可考虑选 L 后缀(默认低)或加掉电检测。
|
||||||
|
|
||||||
|
#### U12 = SuperESD-CDSOT23 防静电(RS485 A/B 线,无源)
|
||||||
|
|
||||||
|
- pin1=A、pin2=B、pin3=CGND、pin4(中心 GND 焊盘)悬空——CDSOT23 双通道 ESD 二极管阵列(IO1/IO2/GND/GND-pad)的标准接法。
|
||||||
|
- 功能:CN1 对外 RS485 A/B 线的 ESD/浪涌钳位,对隔离侧地 CGND 钳位——与被保护收发器 U15 同属 CGND 地,参考地正确;与 RS232 线 D3-D6(SMB) 保护配置对称。pin4 中心焊盘悬空为 SMT 常态,ESD 电流仍经 pin3 回 CGND,无功能影响。
|
||||||
|
- 具体料号以丝印复核(Bourns/TE 系列,PESD0502B 类);手册已入库。
|
||||||
|
|
||||||
|
#### U13 = TPT3232E SOP-16 双路 RS232 收发器(第二级,→CN1 与 U14)
|
||||||
|
|
||||||
|
- 手册已入库(`docs/芯片手册/TPT3232E RS232 电平转换芯片.md`):3V~5.5V、250kbps、2 驱动器+2 接收器、RS232 总线脚 IEC61000 ESD 保护(±15kV HBM / ±12kV 接触放电)。
|
||||||
|
- **引脚定义为非 MAX 惯例**(7=TOUT2、8=RIN2、9=ROUT2、10=TIN2、11=TIN1、12=ROUT1、13=RIN1、14=TOUT1;MAX232 为 7=R2OUT、8=T2IN、9=T2OUT、10=R2IN、11=T1OUT、12=R1IN、13=R1OUT、14=T1IN),网表已对照手册**逐脚核实全部一致**:
|
||||||
|
- 通道1:TIN1(11)←TX1←U9.6(STM32 TX 经 U9 隔离通道);TOUT1(14)→RS232_TX1→CN1.12;RIN1(13)←RS232_RX1←CN1.10;ROUT1(12)→RX1→U9.7(→STM32 RX)。
|
||||||
|
- 通道2:TIN2(10)←TX3←U10.6;TOUT2(7)→RS232_TX3→CN1.11;RIN2(8)←RS232_RX3←CN1.9;ROUT2(9)→RX3→U10.7(→STM32 RX)。
|
||||||
|
- 电源:pin15=GND→CGND、pin16=VCC→C3.3V(隔离侧)。
|
||||||
|
- 泵电容:C1=pin1-3(C68) ✓、C2=pin4-5(C71) ✓、V−(pin6)→C69→GND ✓;V+(pin2)→C70→GND——手册典型电路为 V+→VCC,稳态下两者功能等价(两端均为平整 DC 轨、电容无 DC 电流、V+ 轨电平由电荷泵拓扑确定),非功能缺陷,V0.1 可改与手册一致。
|
||||||
|
- 泵电容 C68-C71 值网表未标(归 '{Value}' 组),实板对照手册 Table 1 核对:3.3V 供电 → C1≥0.2µF、C2/C3/C4≥0.1µF(统一 0.2µF 亦合规)。
|
||||||
|
- CN1 线上 D3-D6 四只 SMB 二极管对 CGND 钳位(ESD/浪涌,CN1 为对外边界,保护有效);芯片总线脚自身亦有 ±15kV HBM 保护,两级防护。
|
||||||
|
|
||||||
|
#### U15 = TP8485E-SR RS485 收发器(3PEAK,板侧,总线上唯一有源收发器)
|
||||||
|
|
||||||
|
- 手册已入库(`docs/芯片手册/TP8485E-SR.md`):3V~5.5V 供电、300bps~250kbps、1/8 unit load(总线最多 256 节点)、full fail-safe 接收器(总线悬空/短路/空闲时 RO 输出高)、热插拔电路(上/掉电 VCC<~2.5V 期间 Tx/Rx 保持高阻,防扰总线)、总线脚片上 ESD ±18kV HBM(按手册板级 TVS 可省)。
|
||||||
|
- **引脚定义(SOIC-8,SN65HVD230/MAX485 族标准 8 脚布局),网表逐脚吻合 TP8485E**:pin1=RO、pin2=DE、pin3=/RE、pin4=DI、pin5=GND、pin6=A、pin7=B、pin8=VCC。
|
||||||
|
- 接线:pin1=RO→RX4、pin2=DE 与 pin3=/RE 并接 DIR4(单线控制)、pin4=DI←TX4、pin5=CGND、pin6=A、pin7=B、pin8=C3.3V(VCC)——8 脚全接、取隔离侧 C3.3V/CGND 电源,接法正确。
|
||||||
|
- 控制逻辑正确:空闲 DIR4=0 → DE=0(驱动关断)+/RE=0(接收器开) = 接收态;发送 DIR4=1 → 驱动开、接收关。
|
||||||
|
|
||||||
|
### 4.5 采集/时钟/存储:U3、U16、U19
|
||||||
|
|
||||||
|
#### U3 = TPAFE5160(LQFP-64,8ch 16-bit ADC,ADS8688 类)
|
||||||
|
|
||||||
|
- **参考电路完整**(REFSEL 经 R29 10k 上拉 = 内部基准;REGCAP C42/C41;REFIN C39;REFCAPA/B 经 C37 短接)。
|
||||||
|
- 模式配置全对:RANGE(pin8)=GND → ±5V;/PAR-SER(pin6) 10k 下拉 → 并口;/STBY(pin7)=3.3V → 正常工作;/CS(pin13)=GND(并口模式不使用)。
|
||||||
|
- **RESET(pin11) 电路(设计正确)**:'HRST' 网 = {U3.11, R16(10k)→GND, C31(1uF)←3.3V 轨}。R16 另一端在 **GND 网**,C31 跨接 3.3V 轨与 HRST → 标准**上电复位脉冲电路**:3.3V 上升沿经 C31 对 RESET 产生约 1uF×10k ≈ 10ms 的高电平脉冲,随后 10k 把 RESET 拉到 0V。RESET 为**高有效**(手册 L532:"set to logic high, the device is in the reset mode"),DC=0V = 正常工作。
|
||||||
|
- 小缺陷(§3.4):无运行时复位能力(代码确实不需要);3.3V 轨大毛刺可经 C31 再触发误复位(概率低)。
|
||||||
|
- 并口数据 DB0-15→PG0-15、/RD=PD3、CONVST=PD4、BUSY=PD7、FRSTDATA→U17.115(经 R24 4.7k 上拉)、OS0-2=PF13-15,与代码完全一致。
|
||||||
|
|
||||||
|
#### U16 = SD2506API-G(I2C RTC 模块,6 引脚)
|
||||||
|
|
||||||
|
- 器件为 **SD2506API 模块**(非裸片):内置 32.768k 晶振 + **内置充电电池 + 充电电路**(手册 L11:电池满充常温下掉电走时约 8 个月,电池寿命 5~8 年;自动电源切换:VDD<2.4V 且 VDD<VBAT 时自动转电池供电,PMF 位指示电源模式)。
|
||||||
|
- **封装与引脚编号(已核实,设计正确)**:实物封装 6 个引脚,但编号**不按 1~6 顺序**——模块只引出手册脚号 **1/4/5/6/7/8**(表 1:1=TEST, 4=GND, 5=SDA, 6=SCL, 7=INT, 8=VDD;pin2/3 未引出)。网表接 4/5/6/8 = GND/SDA/SCL/VDD ✓,1(TEST,手册要求悬空)与 7(INT,未用)悬空 ✓,与手册完全一致。
|
||||||
|
- **掉电走时(已核实,无缺陷)**:后备电源为模块内置充电电池(无外接 VBAT 脚),不存在"无后备电池"问题;代码每次上电写 18H=0x82 使能内置充电(手册 L390 要求),并开机读电池电压寄存器 1AH/1BH 输出 battery: 标记(sd2506.c L180-182 / L327-335),与手册完全一致。
|
||||||
|
|
||||||
|
#### U19 = GD5F2GQ5UE(WSON-8,SPI NAND)
|
||||||
|
|
||||||
|
- 引脚全部验证正确(1=CS 经 R43 4.7k 上拉、2=SO、3=WP、4=VSS、5=SI、6=SCK、7=HOLD、8=VCC、EP=GND);VCC 去耦 C72/C73。无问题。
|
||||||
|
|
||||||
|
### 4.6 显示/子板桥:U18、U14
|
||||||
|
|
||||||
|
#### U18 = AIP74LVC16245TA48 双 8 位总线收发器(TSSOP-48,子板桥)
|
||||||
|
|
||||||
|
- 手册已入库(`docs/芯片手册/锁存器_AIP74LVC16245TA48.TB.md`):16 位 = 2×8 位总线收发器,每字节独立 OE(低有效)+ DIR(方向)控制;电源 1.2~3.6V、I/O 5V 耐压(可对接 5V 逻辑)、TSSOP-48;手册涵盖 LVC(无总线保持)/LVCH(总线保持)两变体、打印标识同为 "74LVC16245"(实际变体以订料料号为准,对本电路功能无影响)。
|
||||||
|
- **Strapping(网表核实,工作模式锁定)**:1DIR(pin1)/2DIR(pin24) 经 4.7k(R38/R41)上拉 3.3V → DIR=H;1OE(pin48)/2OE(pin25) 经 4.7k(R39/R42)下拉 GND → OE=L。按手册功能表(nOE=L、nDIR=H:nBn 随 nAn),两字节均工作于 **A→B 单向直通、恒使能**(A 侧为输入、B 侧为输出,桥永久导通)。
|
||||||
|
- **逐脚核实(48 脚与手册全部吻合)**:12 电源脚(GND=4/10/15/21/28/34/39/45、VCC=7/18/31/42,取主 3.3V/GND 轨)✓;32 个 I/O 脚与 1A/2A/1B/2B 分配完全一致 ✓;4 控制脚(pin1/24=1DIR/2DIR、pin48/25=1OE/2OE)✓。
|
||||||
|
- **信号通路(A→B,三类)**:
|
||||||
|
1. **子板→STM32(确定、有功能)**:EXTKI1/2/3(子板按键态,A 侧主动驱动:U5.C1/B16/A16→1A2/1A1/1A0)→1B2/1B1/1B0→ST_IN_E4/C3/D4→STM32 封装 pin3/2/1 = PC15/PC14/PC13(LQFP-144 标准编号,与 59 配置脚已证实的网表编号体系一致)。注意:网名为历史遗留(ST_IN_C3 实为 EXTKI2、ST_IN_D4 实为 EXTKI3、ST_IN_E4 实为 EXTKI1)——这 3 线实为**子板 EXTKI 按键信号经收发器传入 STM32**,电平由子板按键状态决定;V0.0 代码尚未读 PC13/14/15(无 EXTKI 处理)——硬件通路完整,待固件启用。
|
||||||
|
2. **STM32→子板(悬空、不定,B3)**:H16/V15/J3/F3/R16(1A3~7←U17.79/80/81/82/85)+ K3/DQM0/WAIT1/DQM1/RAS/SDCKE(2A0/3~7←U17.86/96/97/98/99/109)共 **11 线均为未配置高阻引脚** → 所驱动子板输出 11 线(RUN_LED/TRIP_LED/ERT_LED/CLZ_LED、RELAY_STO、HT_A23/HT_A26/HT_C25/HT_C26/HT_C27、EXTKO3)**电平不定** → 子板 LED/继电器/告警状态不可预测。
|
||||||
|
3. **SPI 线耦合到子板(布线副作用)**:2A1/2A2 = SPI1 MISO/MOSI(U17.77/78,活动信号,与 NAND 共用)→ 子板 EXTKO1/EXTKO2——NAND 侧 SPI 流量会调制子板这 2 线,若子板将其作通用输出将受扰(代码无法解决,V0.1 需改线或确认子板未使用)。
|
||||||
|
|
||||||
|
#### U14 = RJ45(C2836689)多用途数据连接器
|
||||||
|
|
||||||
|
- 复用向子板传:RS232#3(TX3/RX3,RJ45 pin3/6)、CF_P/CF_Q 差分对、CLOCK。pin4/5 = 屏蔽→CGND、pin8 → GND(金属壳性耦合两地,无 DC 电源路径,无碍)。引脚定义待对照模块手册(§3.3-2)。
|
||||||
|
|
||||||
|
### 4.7 无源器件
|
||||||
|
|
||||||
|
#### 电感/磁珠/其他
|
||||||
|
|
||||||
|
- L1/L6 = 0603 磁珠(AVCC/STM_VDDA 滤波);L2 = 0603 电感,AGND↔GND 单点桥(模拟/数字地分割:DC 连通 + 高频隔离);L3 = 5V 输入滤波电感;L4 = U4 输入侧滤波电感(G3.3V→U4 VIN+)。
|
||||||
|
- Q1 = SOT-23 NPN(1.0V 轨指示):基极经 R10(1k) 接 AVDDL,集电极→LED,发射极→GND:AVDDL 高于导通阈值时点亮。合理。
|
||||||
|
- U20/U21/U22 = 4.7nF 跨地电容(GND↔PGND↔CGND 单点耦合)。
|
||||||
|
- D3-D6(SMB) = CN1 线上 ESD 钳位(pin1→CGND, pin2→信号线;CN1 为对外边界,保护有效);D1/D2(SMB) = 3.3V/G3.3V 轨对地(**实为 DNP 未贴**,见 A1)。
|
||||||
|
|
||||||
|
#### 电容/电阻分组速览
|
||||||
|
|
||||||
|
| 组 | 元件 | 作用 | 结论 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 输入 bulk | C99 470uF, C46/C47, L3 | 5V 入口滤波 | ✓ |
|
||||||
|
| 5V 轨 | C45 220uF, C49/52/53/56/57 | L3 后 bulk+去耦 | ✓ |
|
||||||
|
| 3.3V 主轨 | C11 10uF + 22×100nF(C12/15/16-21/58/59/72/73/80-93/100/102) | LDO 输出+全芯片去耦 | ✓ 数量充足 |
|
||||||
|
| G3.3V 轨 | C54/55/60-63 | 收发器 LDO 输出 | ✓ |
|
||||||
|
| C3.3V 轨(隔离域) | C48/51/64-67 | U4 隔离电源输出 bulk | ✓ |
|
||||||
|
| 1.0V 轨 | C3 220uF + C4-C10 7×100nF | 片内 LDO 输出 | ✓ 配置标准 |
|
||||||
|
| 晶振匹配 | C25/26 15pF, C27/28/75/76 12pF | X1-X3 负载 | ✓ |
|
||||||
|
| VDDA | C77/C78(L6 后) | 模拟电源 | ✓ |
|
||||||
|
| TPAFE 参考 | C37(REFCAPA/B 短接), C39(REFIN), C41/42(REGCAP) | 内部基准 | ✓ 完整 |
|
||||||
|
| RS232 泵电容 | C68-C71(0603) | TPT3232E 电荷泵(C1:1-3、C2:4-5、V+:2→GND、V-:6→GND) | C1/C2/V- 与手册一致;V+ 储能接 GND(手册典型电路接 VCC,稳态等价);值网表未标,实板对照手册 Table 1 核 |
|
||||||
|
| ADC 输入前端 | 15×(1k 串联 + 1k 到 AIN_nGND + 滤波 C) | 源阻抗匹配(手册推荐做法,非分压) | ✓ |
|
||||||
|
| 上拉/下拉 | R40(NRST), R29(REFSEL), R43(GD_CS), R35(DE/RE), R22(PAR/SER), R6(DIS_EEE), R24(FIRSTDATA), R4(TXD 下拉), R44/50/53(KEY1-3), R36/37/39/54-58(strapping/LED) | strapping + 默认态 | ✓ |
|
||||||
|
| 4.7k×5 | R24(U3 FRSTDATA 上拉) + R38/R41(U18.1/24=1DIR/2DIR 上拉 3.3V) + R39/R42(U18.48/25=1OE/2OE 下拉 GND) | ADC 首数据线默认态 + 桥片模式锁定(A→B 单向、恒使能) | ✓ 已按手册功能表核实 |
|
||||||
|
| LED 限流 | R1/7/8(470Ω), R59-R64(1k), R33 | 指示 LED | ✓ |
|
||||||
|
| 地桥 | U20-U22(4.7nF 跨地: GND↔PGND↔CGND) | 多域地单点耦合 | ✓ 常规 |
|
||||||
|
|
||||||
|
## 5. 改进方向
|
||||||
|
|
||||||
|
### 5.1 一次性上电测量清单(万用表 + 示波器,约 30 分钟,把全部"待核"变"已确认")
|
||||||
|
|
||||||
|
1. U1.28 直流(应 ≈0V:5.1k 下拉,SPI 模式配置脚;异常时才需排查)
|
||||||
|
2. U3.11 直流(0V?= ADC 复位电路正常;3.3V = ADC 静默死亡)
|
||||||
|
3. C3.3V 轨(U4 隔离电源输出,应 ≈3.2-3.3V)/ G3.3V 轨 / AVDDL(1.0V) / 3.3V 主轨 / 5V 轨 直流;DIR4 静态电平(空闲应 ≈0.1-0.3V = 接收态;恒 3.3V = 光耦 LED 侧异常,恒 0V = 上拉异常)+ U8.1(LED 阳极,PD0 拉低时应 ≈2.1V)
|
||||||
|
4. U17.23/24 8MHz 波形;U17.25 静止 3.3V、按 SW1 时 0V(关闭 §3.3-3)
|
||||||
|
5. U17.73 (PB12/CS) 通信时翻转(关闭 §3.3-3)
|
||||||
|
6. AIN1 注入 1V 直流 → UI ADC1 值变化 + U3.14 BUSY 脉冲(**首次功能级 ADC 验证**)
|
||||||
|
7. RS485 A/B 环回:发送→回显(**首次功能级 RS485 验证**)
|
||||||
|
8. CN1 RS232/RS485 环回(经子板)
|
||||||
|
9. 目视:RJ45 模块型号、C68-C71 实际值(对照手册 Table 1)、U18 印字(应为 74LVC16245;LVC/LVCH 变体印字相同,无功能影响)、U8 丝印 CTR 分档等级
|
||||||
|
|
||||||
|
### 5.2 软件验证链补强(消除"静默死亡"盲区)
|
||||||
|
|
||||||
|
- 开机自检加功能级断言:ADC 注入-读回校验(利用 FRSTDATA/BUSY 握手)、RS485 回环校验(DE 拉高自发自收)、CH395F PHY 寄存器读回(确认 SPI 模式 + 100M link)
|
||||||
|
- `verify_log.ps1` 增加对应 Required 标记(`ADC selftest: OK` / `RS485 loop: OK` / `PHY: 100M FULL`)
|
||||||
|
- U18 桥:代码配置 11 个 A 侧 GPIO(H16/V15/J3/F3/R16/K3/DQM0/WAIT1/DQM1/RAS/SDCKE)为安全默认电平(LED 灭/继电器断/告警静默)并加读回断言,同时启用 PC13/14/15(EXTKI×3)按键读取(解决 B3①,无需改硬件)
|
||||||
|
|
||||||
|
### 5.3 V0.1 改版清单
|
||||||
|
|
||||||
|
**改板项**:
|
||||||
|
|
||||||
|
- RTL8305 V33IN 串联肖特基(BAT54/SS34)+ MDC/MDIO(B1)
|
||||||
|
- 3.3V 主轨改 buck + 5V 调试排针 + TVS(B2,顺带并掉 G3.3V 双轨偏移)
|
||||||
|
- U18 2A1/2A2→EXTKO1/2 的 SPI 耦合布线改线(或确认子板未用该 2 线)(B3②)
|
||||||
|
- T1 远端对地旁路;D1/D2 去焊盘;U4 焊盘更换(A1/A2)
|
||||||
|
- 若 U8 CTR 分档核实为档 L:R35 1.5k → 10k(提高高温低电平裕量)
|
||||||
|
- TPAFE RESET 改 GPIO 控制(获得软复位)
|
||||||
|
|
||||||
|
**代码项(可先做,不依赖改版)**:
|
||||||
|
|
||||||
|
- U18 桥:配置 11 个 GPIO 安全默认电平 + 启用 PC13/14/15 EXTKI 读取(解决 B3①)
|
||||||
|
- 开机功能级断言:ADC/RS485/CH395F(§5.2)
|
||||||
|
|
||||||
|
**文档/网表项**:
|
||||||
|
|
||||||
|
- 网表按 A1/A2 勘误(D1/D2 标 DNP、U4 料号改 B0303S)后重新导出存档
|
||||||
|
- 手册补全:H1102NLT、HR911105A 入 `docs/芯片手册/`(芯片手册已在库 12 份,见附录 B;B0303S 已在库)
|
||||||
|
|
||||||
|
### 5.4 文档补全
|
||||||
|
|
||||||
|
- 待补手册 2 份:H1102NLT(T1 共模磁环)、HR911105A(J1/J2 RJ45)
|
||||||
|
- 芯片手册 12 份已在库(附录 B,含 B0303S.md)
|
||||||
|
|
||||||
|
## 6. 最优先三件事
|
||||||
|
|
||||||
|
1. 跑 §5.1 测量清单(电源/风险项多已随分析澄清,重点转向功能验证:C3.3V 隔离输出、U3.11 确认、RS485/RS232 环回);
|
||||||
|
2. 代码落地 §5.2 功能级断言 + U18 桥 11 个 GPIO 配置(解决 B3、消除静默死亡盲区,无需改板,可先做);
|
||||||
|
3. 补齐 2 份手册(H1102NLT / HR911105A)+ 实物抽查 3 脚(关闭 §3.3 全部待核项)。
|
||||||
|
|
||||||
|
完成这三步,V0.1 改版就没有未知数了。
|
||||||
|
|
||||||
|
## 附录 A:勘误记录(初版误判,全部撤回)
|
||||||
|
|
||||||
|
| # | 位置 | 初版判断 | 实际 | 核实依据 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| A-1 | U4 | "3Ω 4 脚功率电阻 → P0 致命短路风险" | B0303S 隔离电源芯片,4 脚即隔离电源输入/输出,无短路 | 丝印 + 网表脚位 |
|
||||||
|
| A-2 | U8 | "4 脚缓冲器,电源跨接 U4 隔离边界 → 两接地域 DC 耦合(初版 B1)" | FOC-817SC-F 光耦,LED 侧/晶体管侧光耦合、无 DC 路径(390Ω 系 LED 限流、R35 系隔离侧开集上拉) | 手册逐脚 |
|
||||||
|
| A-3 | U9/U10/U11 | "SOIC-8 串口收发器;U11 串入 USART5 线、疑 232 泵节点污染(初版 B1)" | CA-IS3722HS 数字隔离器 ×3,双侧各自供电,接法正确 | 手册逐脚 |
|
||||||
|
| A-4 | U12 | "无供电失活死芯片 → 标 DNP/移除" | SuperESD-CDSOT23 无源 ESD 阵列,本无需供电,pin1/2 在 A/B 线正是 I/O 连接 | 手册 |
|
||||||
|
| A-5 | U13 | "非 MAX 克隆,若按 MAX 惯例则 6 个信号脚反接" | TPT3232E 非 MAX 惯例,网表逐脚吻合、方向正确 | 手册逐脚 |
|
||||||
|
| A-6 | U15 | "料号未知、疑 SN65HVD230 族、非标引脚定义" | TP8485E-SR(3PEAK,与 SN65HVD230/MAX485 引脚兼容),标准 8 脚布局 | 手册逐脚 |
|
||||||
|
| A-7 | U18 | "料号未知、行为不可预测;ST_IN_C3/D4/E4 判为来自 STM32 悬空脚" | AIP74LVC16245TA48 纯电平缓冲器,strapping 锁定 A→B 恒使能;ST_IN 3 线实为子板 EXTKI 按键信号经桥传入 STM32(初版方向搞反) | 手册 + 网表复核 |
|
||||||
|
| A-8 | U16 | "引用 pin8 为网表矛盾;RTC 无后备电池" | 模块引脚按手册编号引出(1/4/5/6/7/8,pin8=VDD 有效);模块内置充电电池,掉电自动续走约 8 个月 | 手册 |
|
||||||
|
| A-9 | U1(CH395F) | "TXD 上拉疑似错误" | TXD 实为 5.1k 下拉,SPI 模式配置正确 | 网表复核 |
|
||||||
|
| A-10 | D1/D2 | "网表↔实板矛盾(方向)" | 实为 DNP 未贴;板内电源轨无真实浪涌威胁,保护意义有限 | 实板 |
|
||||||
|
| A-11 | 手册库存 | "B0303S 手册未入库"(曾列为待核项) | B0303S.md 实际在库(EVISUN B_S-1WR3 系列手册,型号表含 B0303S-1WR3:3.3V 入/3.3V 出 303mA/1500VDC),U4 核实升级为"丝印+脚位+手册"三重吻合;初版目录扫描检查误报 | 目录实物列举 + 手册内容 |
|
||||||
|
|
||||||
|
## 附录 B:手册清单(已入库 `docs/芯片手册/`)
|
||||||
|
|
||||||
|
| 手册文件 | 对应芯片 |
|
||||||
|
|---|---|
|
||||||
|
| CH395F.md | U1 |
|
||||||
|
| RTL8305NBI-CG.md | U2 |
|
||||||
|
| TPAFE5160.md | U3 |
|
||||||
|
| B0303S.md | U4 |
|
||||||
|
| SD2506API-G.md | U16 |
|
||||||
|
| GD5F2GQ5UExxG.md | U19 |
|
||||||
|
| 光耦隔离芯片FOC-817SC-F.md | U8 |
|
||||||
|
| 数字隔离器 CA-IS3722HS.md | U9/U10/U11 |
|
||||||
|
| SuperESD-CDSOT23.md | U12 |
|
||||||
|
| TPT3232E RS232 电平转换芯片.md | U13 |
|
||||||
|
| TP8485E-SR.md | U15 |
|
||||||
|
| 锁存器_AIP74LVC16245TA48.TB.md | U18 |
|
||||||
|
| stm32f405rg.md / STM32F4xx参考手册_V18英文版_1-1000.md | U17(参考件) |
|
||||||
|
|
||||||
|
> 未入库(待补,见 §3.3):T1(H1102NLT)、J1/J2(HR911105A)。
|
||||||
+54
-23
@@ -59,7 +59,7 @@ sys_clock_init(); /* 读取 RTC → 建立墙钟基准 */
|
|||||||
当前 Unix 秒数 = s_base_unix_secs + (HAL_GetTick() - s_base_tick) / 1000
|
当前 Unix 秒数 = s_base_unix_secs + (HAL_GetTick() - s_base_tick) / 1000
|
||||||
```
|
```
|
||||||
|
|
||||||
其中 `(now_tick - s_base_tick)` 为 **unsigned 减法**,在 Tick 每约 49 天回绕一次时依然正确(只要两次采样间隔 < 2³² ms ≈ 49 天,单次运行必然满足),所以连续上电不超过 49 天的场景无回绕问题。
|
其中 `(now_tick - s_base_tick)` 为 **unsigned 模减法**:Tick 每 ~49.7 天(2³² ms)回绕一次时,单次回绕本身被模运算无缝吸收。但**差值窗口必须始终小于一整圈**——否则连续运行超过 49.7 天后差值混叠,"过了 2.5 天" 与 "过了一整圈 + 2.5 天" 无法区分,墙钟整体倒退一圈。因此 `sys_clock_get()` 内置**惰性再基准化**(§7):窗口达到 30 天时把基准向前平移(墙钟值不变、窗口清零,亚秒余数结转,无损),窗口恒 < 49.7 天,任意长连续运行均无回绕。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -72,9 +72,9 @@ static volatile uint32_t s_base_tick = 0; /* HAL_GetTick() 基准(建
|
|||||||
static volatile uint32_t s_base_unix_secs = UINT32_MAX; /* 基准对应的 Unix 秒数;初始为 UINT32_MAX 表示"未建立" */
|
static volatile uint32_t s_base_unix_secs = UINT32_MAX; /* 基准对应的 Unix 秒数;初始为 UINT32_MAX 表示"未建立" */
|
||||||
```
|
```
|
||||||
|
|
||||||
- `s_base_tick`:`sys_clock_init()` / `sys_clock_set()` 时采样一次。
|
- `s_base_tick`:`sys_clock_init()` / `sys_clock_set()` 时采样;运行期另由 `sys_clock_get()` 的惰性再基准化(§7)每 30 天平移一次。
|
||||||
- `s_base_unix_secs`:与 `s_base_tick` 同一时刻的 Unix 秒数;`sys_clock_get()` 以它为锚推算当前值。
|
- `s_base_unix_secs`:与 `s_base_tick` 同一时刻的 Unix 秒数;`sys_clock_get()` 以它为锚推算当前值。
|
||||||
- 二者均带 `volatile`,因为时间是跨任务共享的状态(虽更新在 nets/默认任务中,但读取可能发生在任意任务上下文)。
|
- 二者均带 `volatile`(跨任务共享:更新只发生在 `sys_clock_init` / `sys_clock_set` / 再基准化临界区,读取可能发生在任意任务/中断上下文)。
|
||||||
|
|
||||||
> 注:`app_main.c`(app_main_init)调用 `sys_clock_init()`;使用方含 `dbg_log`(日志时间戳)、`ffsystem`(文件时间戳)、`time_sync`(对时)等。
|
> 注:`app_main.c`(app_main_init)调用 `sys_clock_init()`;使用方含 `dbg_log`(日志时间戳)、`ffsystem`(文件时间戳)、`time_sync`(对时)等。
|
||||||
|
|
||||||
@@ -84,12 +84,12 @@ static volatile uint32_t s_base_unix_secs = UINT32_MAX; /* 基准对应的 Unix
|
|||||||
|
|
||||||
| 函数 | 功能 | 返回值 | 限定条件 |
|
| 函数 | 功能 | 返回值 | 限定条件 |
|
||||||
|------|------|--------|----------|
|
|------|------|--------|----------|
|
||||||
| `int sys_clock_init(void)` | 从 SD2506 读取初始时间,建立墙钟基准(含可选校时) | `0`(始终成功) | `sd2506_init()` 已调用 |
|
| `int sys_clock_init(void)` | 从 SD2506 读取初始时间,建立墙钟基准(含可选校时) | `0` - 成功;`-1` - RTC 不可用(启用默认值宏时降级为默认时间基准,墙钟仍可用) | `sd2506_init()` 已调用 |
|
||||||
| `uint32_t sys_clock_get(void)` | 获取当前 Unix 时间戳(秒) | 当前秒数;未初始化返回 `UINT32_MAX` | `sys_clock_init()` 已调用 |
|
| `uint32_t sys_clock_get(void)` | 获取当前 Unix 时间戳(秒) | 当前秒数;未初始化返回 `UINT32_MAX` | `sys_clock_init()` 已调用 |
|
||||||
| `char *sys_clock_get_str(char *buf, size_t buf_size)` | 获取格式化字符串 `YYYY-MM-DD HH:MM:SS` | `buf` 指针;未初始化输出 `----/--/-- --:--:--` | `buf` 有效且 `buf_size ≥ 20` |
|
| `char *sys_clock_get_str(char *buf, size_t buf_size)` | 获取格式化字符串 `YYYY-MM-DD HH:MM:SS` | `buf` 指针;未初始化输出 `----/--/-- --:--:--` | `buf` 有效且 `buf_size ≥ 20` |
|
||||||
| `int sys_clock_set(uint32_t unix_secs, const sd2506_time_t *sd_time)` | 更新基准,可写回 SD2506 | `0`(始终成功) | `unix_secs` 为合法时间戳 |
|
| `int sys_clock_set(uint32_t unix_secs, const sd2506_time_t *sd_time)` | 更新基准,可写回 SD2506 | `0`(始终成功) | `unix_secs` 为合法时间戳 |
|
||||||
|
|
||||||
> 头文件 `sys_clock.h` 中注释的返回值含 `-1` 失败码,但实际实现恒返回 `0`,以"成功"语义对外;调用方按 `0` 成功处理即可。
|
> `sys_clock_init()` 返回 `-1` 表示 RTC 芯片不可用:`RTC_DEFAULT_INIT_ENABLE=1` 时墙钟降级为编译期默认时间基准(日志时间戳仍有效),`app_main` 记录"时钟芯片异常"自检;禁用时墙钟保持"未初始化"(各取时接口返回无效哨兵)。`sys_clock_set()` 只更新基准(写回 RTC 尽力而为),恒返回 `0`。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -102,11 +102,14 @@ sequenceDiagram
|
|||||||
participant RTC as SD2506 RTC
|
participant RTC as SD2506 RTC
|
||||||
participant HAL as HAL Tick
|
participant HAL as HAL Tick
|
||||||
|
|
||||||
Note over SC,RTC: Step 1 从 SD2506 读取初始时间
|
Note over SC,RTC: Step 1 从 SD2506 读取初始时间(检查返回值)
|
||||||
SC->>RTC: sd2506_get_time(sd_time)
|
SC->>RTC: sd2506_get_time(sd_time)
|
||||||
RTC-->>SC: sd_time(year 已是完整年份)
|
RTC-->>SC: sd_time(year 已是完整年份)+ 返回值
|
||||||
Note right of SC: 后续换算【不得】再加 2000<br>否则年份虚增 → Unix 秒数超 uint32 回绕
|
Note right of SC: 后续换算【不得】再加 2000<br>否则年份虚增 → Unix 秒数超 uint32 回绕
|
||||||
Note right of SC: 可选校时(见第 9 节 RTC_DEFAULT_INIT_* 宏)
|
Note right of SC: 可选校时(见第 9 节):读失败/越界 →<br>写默认时间 → 重读(检查返回值)→ 复验范围
|
||||||
|
alt RTC 仍不可用
|
||||||
|
Note over SC: 降级:ENABLE=1 → 以编译期默认时间建基准(仅 RAM)并返回 -1;<br>ENABLE=0 → 不建基准(墙钟保持"未初始化")并返回 -1<br>app_main 记录"时钟芯片异常"自检
|
||||||
|
end
|
||||||
|
|
||||||
Note over SC: Step 2 将 RTC 时间换算为 Unix epoch 秒数
|
Note over SC: Step 2 将 RTC 时间换算为 Unix epoch 秒数
|
||||||
SC->>SC: 累计 1970 至当前年份的整年天数(含闰年 366 天判定)
|
SC->>SC: 累计 1970 至当前年份的整年天数(含闰年 366 天判定)
|
||||||
@@ -128,17 +131,33 @@ sequenceDiagram
|
|||||||
|
|
||||||
```c
|
```c
|
||||||
uint32_t now_tick = HAL_GetTick();
|
uint32_t now_tick = HAL_GetTick();
|
||||||
int64_t unix_secs = (int64_t)s_base_unix_secs
|
uint32_t diff = now_tick - s_base_tick; /* 32 位模减,跨 Tick 回绕无缝 */
|
||||||
+ (int64_t)((uint32_t)(now_tick - s_base_tick) / 1000uL);
|
|
||||||
if (unix_secs < 0) return UINT32_MAX; /* 基准未建立(理论上不会发生) */
|
if (s_base_unix_secs != UINT32_MAX && diff > SYS_CLOCK_REBASE_MS) {
|
||||||
return (uint32_t)unix_secs;
|
/* 惰性再基准化:窗口达 30 天,基准前移(墙钟值不变),余数结转 */
|
||||||
|
taskENTER_CRITICAL();
|
||||||
|
diff = now_tick - s_base_tick; /* 复核:防双任务重复累加 */
|
||||||
|
if (diff > SYS_CLOCK_REBASE_MS) {
|
||||||
|
s_base_unix_secs += diff / 1000u;
|
||||||
|
s_base_tick = now_tick - (diff % 1000u); /* 新窗自 (now − 余数) 起算 */
|
||||||
|
diff = diff % 1000u;
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_base_unix_secs == UINT32_MAX) return UINT32_MAX; /* 未初始化(显式哨兵判断) */
|
||||||
|
return (uint32_t)((int64_t)s_base_unix_secs + diff / 1000u);
|
||||||
```
|
```
|
||||||
|
|
||||||
要点:
|
要点:
|
||||||
|
|
||||||
- 用 **整除 1000** 把毫秒 Tick 折算为秒,**不**做每毫秒累加,避免累加误差累积与频繁除法;
|
- 用 **整除 1000** 把毫秒 Tick 折算为秒,**不**做每毫秒累加,避免累加误差累积与频繁除法;
|
||||||
- `now_tick - s_base_tick` 为无符号减法,自动正确处理 Tick 回绕;
|
- `now_tick - s_base_tick` 为**模差**:Tick 每 ~49.7 天回绕被无缝吸收,但窗口必须恒 < 一整圈(见下方再基准化);
|
||||||
- 若基准未建立(`s_base_unix_secs` 仍为 `UINT32_MAX` 且未初始化),返回 `UINT32_MAX` 作为"无效"哨兵。
|
- **惰性再基准化(30 天)**:差值窗口达到 `SYS_CLOCK_REBASE_MS` 时,基准前移流逝秒数并清零窗口——墙钟值逐位不变,亚秒余数结转入新窗(`base_tick = now − rem`),与"从不重基"数学等价,零损失;
|
||||||
|
- 再基准化为**自我参照**:纯内存操作、零 I2C、非阻塞——不重读 RTC 重锚(RTC 漂移 ±20ppm ≈ ±1.7 s/天,远大于 Tick 漂移,重锚反而降低精度;RTC 只承担冷启动锚点 + 掉电保持);
|
||||||
|
- 触发为**惰性**:墙钟读取高频(每条日志/文件操作/待机屏),阈值越过后的下一次读取即完成再基准化,无需定时器任务;30 天阈值留 19.7 天余量,设备完全静默也不会越界;
|
||||||
|
- 再基准化在**临界区 + 区内复核**中执行,防双任务并发重复累加;
|
||||||
|
- 基准未建立(`s_base_unix_secs` 仍为 `UINT32_MAX` 哨兵)时返回 `UINT32_MAX` 作为"无效"(显式哨兵判断,替代旧版对正 int64 永不成立的 `< 0` 检查)。
|
||||||
|
|
||||||
### 7.1 字符串格式化(`sys_clock_get_str`)
|
### 7.1 字符串格式化(`sys_clock_get_str`)
|
||||||
|
|
||||||
@@ -179,10 +198,11 @@ if (sd_time != NULL) {
|
|||||||
|
|
||||||
行为(`sys_clock_init` 内,`#if defined(RTC_DEFAULT_INIT_ENABLE)` 包裹):
|
行为(`sys_clock_init` 内,`#if defined(RTC_DEFAULT_INIT_ENABLE)` 包裹):
|
||||||
|
|
||||||
- 判定 RTC 时间是否"无效":`year` 越界(<2000 或 >2099)、`month` 越界、`day` 越界;
|
- 判定 RTC"不可用":`sd2506_get_time()` 返回值非 OK(I2C 读失败)、`year` 越界(<2000 或 >2099)、`month`/`day` 越界;
|
||||||
- `RTC_DEFAULT_INIT_FORCE == 1`:强制每次启动都用上述宏写入默认时间;
|
- `RTC_DEFAULT_INIT_FORCE == 1`:强制每次启动都用上述宏写入默认时间;
|
||||||
- 否则仅在 RTC 时间无效时写入;
|
- 否则仅在 RTC 不可用时写入;
|
||||||
- 写入后重新 `sd2506_get_time()` 读取校准后的值,再进入 Step 2 换算。
|
- 写入后重新 `sd2506_get_time()` 读取校准后的值(同样检查返回值)并复验范围,再进入 Step 2 换算;
|
||||||
|
- RTC 仍不可用时:`ENABLE=1` 则以编译期默认时间建基准(仅 RAM 的降级基准,墙钟仍可用)且 `sys_clock_init` 返回 `-1`;`ENABLE=0` 则不建基准,返回 `-1`。
|
||||||
|
|
||||||
> ⚠️ **使用注意**:`FORCE=1` 会**每次开机覆盖用户/网络已设的时间**,仅用于首次烧录或硬件时钟丢失时的开发期校时。校时完成后应将 `RTC_DEFAULT_INIT_FORCE` 置 `0`(或注释 `ENABLE`),否则会抹掉正常运行中通过 SNTP 等写入的正确时间。
|
> ⚠️ **使用注意**:`FORCE=1` 会**每次开机覆盖用户/网络已设的时间**,仅用于首次烧录或硬件时钟丢失时的开发期校时。校时完成后应将 `RTC_DEFAULT_INIT_FORCE` 置 `0`(或注释 `ENABLE`),否则会抹掉正常运行中通过 SNTP 等写入的正确时间。
|
||||||
|
|
||||||
@@ -240,8 +260,8 @@ uint32_t now = sys_clock_get(); /* Unix 秒,可用于 FatFS 文件时间、
|
|||||||
2. **`uint32_t` Unix 时间戳的 2038 上限**
|
2. **`uint32_t` Unix 时间戳的 2038 上限**
|
||||||
基准与返回值均为 `uint32_t`,时间范围约为 `1970-01-01 ~ 2038-01-19`。超过 2038 年换算会回绕。当前设备生命周期内可接受;若需长期运行,需改用 `uint64_t` 或 `time_t`。
|
基准与返回值均为 `uint32_t`,时间范围约为 `1970-01-01 ~ 2038-01-19`。超过 2038 年换算会回绕。当前设备生命周期内可接受;若需长期运行,需改用 `uint64_t` 或 `time_t`。
|
||||||
|
|
||||||
3. **Tick 回绕安全**
|
3. **Tick 回绕安全与 30 天再基准化**
|
||||||
`(now_tick - s_base_tick)` 为无符号减法,Tick 每 ~49 天回绕一次时计算依然正确,无需特殊处理。
|
`(now_tick - s_base_tick)` 为无符号模差:Tick 每 ~49.7 天(2³² ms)回绕被模运算无缝吸收,但**差值窗口必须恒小于一整圈**——否则连续上电超过 49.7 天后差值混叠,墙钟"倒退"一整圈(49.7 天)。因此 `sys_clock_get()` 在窗口达 30 天时惰性再基准化(基准前移 + 窗口清零,亚秒余数结转、无损、纯内存操作、零 I2C),详见 §7。
|
||||||
|
|
||||||
4. **运行期不访问 RTC**
|
4. **运行期不访问 RTC**
|
||||||
`sys_clock_get()` 无任何 I2C 操作,零阻塞、可随时在任意任务/中断上下文安全调用(仅读 `volatile` 基准)。
|
`sys_clock_get()` 无任何 I2C 操作,零阻塞、可随时在任意任务/中断上下文安全调用(仅读 `volatile` 基准)。
|
||||||
@@ -249,6 +269,9 @@ uint32_t now = sys_clock_get(); /* Unix 秒,可用于 FatFS 文件时间、
|
|||||||
5. **校时宏的副作用**
|
5. **校时宏的副作用**
|
||||||
见第 9 节 `FORCE=1` 会覆盖既有正确时间,仅限开发期使用。
|
见第 9 节 `FORCE=1` 会覆盖既有正确时间,仅限开发期使用。
|
||||||
|
|
||||||
|
6. **未初始化哨兵必须显式判断**
|
||||||
|
"基准未建立"以 `s_base_unix_secs == UINT32_MAX` 表示,`sys_clock_get()` 须**先显式判哨兵**再推算。旧实现以"推算结果 < 0"判断,但哨兵转 int64 后是正数(4294967295),条件永不成立、会返回垃圾小值而非 `UINT32_MAX`(使所有消费方的降级路径失效)——v1.3(2026-09-15)已修正。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13. 已知限制与可扩展方向
|
## 13. 已知限制与可扩展方向
|
||||||
@@ -256,7 +279,7 @@ uint32_t now = sys_clock_get(); /* Unix 秒,可用于 FatFS 文件时间、
|
|||||||
| 项目 | 现状 | 可扩展方向 |
|
| 项目 | 现状 | 可扩展方向 |
|
||||||
|------|------|------------|
|
|------|------|------------|
|
||||||
| 时间范围 | 受 `uint32_t` 限制至 2038 | 改用 `uint64_t`/`time_t` 扩展 |
|
| 时间范围 | 受 `uint32_t` 限制至 2038 | 改用 `uint64_t`/`time_t` 扩展 |
|
||||||
| 运行期校准 | 仅初始化时读 RTC | 可定时(如每天)重新 `sd2506_get_time()` 校准,消除 RTC 与 Tick 的微小累积偏差 |
|
| 运行期校准 | 30 天惰性再基准化已实现(§7):纯自我参照、零 I2C;**有意不**周期性重读 RTC 重锚——RTC 漂移(±20ppm ≈ ±1.7 s/天)远大于 Tick 漂移,重锚反而降低精度;时间纠偏由时间同步(§15)负责 |
|
||||||
| 网络校时 | 已实现(PC 推送 / TCP,见第 15 节) | SNTP/NTP 公网校时仍可作为后续扩展 |
|
| 网络校时 | 已实现(PC 推送 / TCP,见第 15 节) | SNTP/NTP 公网校时仍可作为后续扩展 |
|
||||||
| 时区 | 按 RTC 本地时间处理 | 如需 UTC/时区,可在 API 层增加偏移参数 |
|
| 时区 | 按 RTC 本地时间处理 | 如需 UTC/时区,可在 API 层增加偏移参数 |
|
||||||
|
|
||||||
@@ -303,9 +326,11 @@ PC 每轮发送固定 8 字节帧:
|
|||||||
|
|
||||||
### 15.3 任务流程
|
### 15.3 任务流程
|
||||||
|
|
||||||
`timeSyncTask` 启动后延迟 8s(等 netTask 完成 `net_init` 与 PHY 协商),进入循环:
|
`timeSyncTask` 启动后先等待 `SYS_EVT_NET_READY` 事件标志(取代旧版 8s 魔法延时;网络不就绪则一直等待),进入循环:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
osEventFlagsWait(sys_evtHandle, SYS_EVT_NET_READY, osFlagsWaitAny, osWaitForever);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ls = time_sync_open_listener(); /* net_socket + net_bind + net_listen,失败重试 */
|
ls = time_sync_open_listener(); /* net_socket + net_bind + net_listen,失败重试 */
|
||||||
conn = net_accept(ls, NULL, NULL); /* 阻塞等待 PC 连接(无连接立即返回 -1,循环重试) */
|
conn = net_accept(ls, NULL, NULL); /* 阻塞等待 PC 连接(无连接立即返回 -1,循环重试) */
|
||||||
@@ -325,8 +350,8 @@ for (;;) {
|
|||||||
### 15.5 Socket 分配与冲突
|
### 15.5 Socket 分配与冲突
|
||||||
|
|
||||||
- `net_socket()` 从 0 开始分配第一个空闲 Socket 控制块(`alloc_socket()`),并把硬件 Socket 号设为该下标;调用时的第三个参数(0)仅为协议占位,不影响分配。
|
- `net_socket()` 从 0 开始分配第一个空闲 Socket 控制块(`alloc_socket()`),并把硬件 Socket 号设为该下标;调用时的第三个参数(0)仅为协议占位,不影响分配。
|
||||||
- 当前启动顺序:FTP 任务(延迟 7s)先监听 → 占用 **socket 0**(控制)+ **socket 1**(数据);时间同步任务(延迟 8s)后监听 → 占用 **socket 1**(或下一个空闲)。二者不冲突。
|
- 当前启动顺序:FTP 任务(`NET_READY` + `STORAGE_READY` 屏障满足后,无魔法延时)先监听 → 占用一个 Socket(单连接模式下监听通道复用为数据通道);时间同步任务(`NET_READY` 后)后监听 → 占用另一个空闲 Socket。二者不冲突。
|
||||||
- 单连接模式允许**任意** Socket 作为"监听 + 数据复用"通道,且总共 8 个 Socket,FTP 用 2 个、时间同步用 1 个,余量充足。
|
- 单连接模式允许**任意** Socket 作为"监听 + 数据复用"通道,且总共 8 个 Socket,FTP 与时间同步各用 1 个,余量充足。
|
||||||
|
|
||||||
### 15.6 客户端实现要点(避坑)
|
### 15.6 客户端实现要点(避坑)
|
||||||
|
|
||||||
@@ -353,4 +378,10 @@ PC 端 `python test/time_sync_server.py` 每 `interval` 秒推送一次,epoch
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 变更记录
|
||||||
|
|
||||||
|
| 日期 | 变更 |
|
||||||
|
|------|------|
|
||||||
|
| 2026-09-15 | v1.3:① `sys_clock_get` 30 天惰性再基准化——修复 49.7 天墙钟回绕(§3/§7/§12);② `sys_clock_init` 检查 RTC 读返回值/写回复验,失败降级为默认时间基准并返回 -1——激活"时钟芯片异常"自检(§5/§6/§9);③ 修正未初始化哨兵判断(§12-6);④ 时间同步任务启动/Socket 占用描述同步为事件屏障 + 单连接实现(§15);⑤ 新增日志串用 ASCII——本机 ARMCC 按 CP936 解读无 BOM 源文件,奇数汉字字符串会吞掉结束引号致编译失败(见 AGENTS.md 编码铁律) |
|
||||||
|
|
||||||
*文档依据 `App/util/sys_clock.c` / `App/time_sync.c` 实现与《嵌入式C语言代码规范(V1.0)》整理。*
|
*文档依据 `App/util/sys_clock.c` / `App/time_sync.c` 实现与《嵌入式C语言代码规范(V1.0)》整理。*
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,341 @@
|
|||||||
|
3V to 5.5V, 250kbps RS-232 Transceivers
|
||||||
|
|
||||||
|
# Features
|
||||||
|
|
||||||
|
● Meets the Requirements of TIA/EIA- 232-F and ITU V.28 Standards
|
||||||
|
● Wide Power Supply Range: Single +3V to +5.5V
|
||||||
|
● Two Drivers and Two Receivers
|
||||||
|
● Operates up to 250 kbps
|
||||||
|
● Requires Only Four External 0.1μF Capacitors
|
||||||
|
● ESD Protection for RS-232 Bus Pins
|
||||||
|
|
||||||
|
$$
|
||||||
|
\pm 15 \mathrm{kV} (\mathrm{HBM})
|
||||||
|
$$
|
||||||
|
|
||||||
|
$$
|
||||||
|
\pm 12 \mathrm{kV} (\text {IEC61000 - 4 - 2, Contact Discharge})
|
||||||
|
$$
|
||||||
|
|
||||||
|
$$
|
||||||
|
\pm 15 \mathrm{kV} (\text {IEC61000 - 4 - 2, Air - Gap Discharge})
|
||||||
|
$$
|
||||||
|
|
||||||
|
# Description
|
||||||
|
|
||||||
|
The TPT3232E is IEC61000 ESD protected, 3.0V to 5.5V powered transceivers that meet the RS-232 standards for balanced communication. Each receiver converts TIA/RS-232 inputs to TTL/CMOS levels.
|
||||||
|
|
||||||
|
The devices have a typical threshold of 1.25V, a typical hysteresis of 0.3V, and can accept ±15V inputs. The device operates at data signaling rates up to 250 kbps. The TPT3232E is available in SOP16, SSOP16 and TSSOP16 package, and is characterized from -40°C to 125°C.
|
||||||
|
|
||||||
|
# Applications
|
||||||
|
|
||||||
|
● Battery-Powered Equipment
|
||||||
|
● Industry Human Machine Interface
|
||||||
|
- Notebook, Computers
|
||||||
|
- Printers
|
||||||
|
|
||||||
|
Device Table
|
||||||
|
|
||||||
|
<table><tr><td>Device</td><td>Package</td><td>Body size</td></tr><tr><td>TPT3232E-SS3R</td><td>SSOP16</td><td>6.2 mm x 5.3 mm</td></tr><tr><td>TPT3232E-TS3R</td><td>TSSOP16</td><td>5.0 mm x 4.4 mm</td></tr><tr><td>TPT3232E-SO3R</td><td>SOP16</td><td>9.9 mm x 3.9 mm</td></tr></table>
|
||||||
|
|
||||||
|
# Function Block
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
3.3 V, 5 V
|
||||||
|
POWER
|
||||||
|
GND
|
||||||
|
DIN
|
||||||
|
2
|
||||||
|
TX
|
||||||
|
2
|
||||||
|
DOUT
|
||||||
|
RS232
|
||||||
|
ROUT
|
||||||
|
2
|
||||||
|
RX
|
||||||
|
2
|
||||||
|
RIN
|
||||||
|
RS232
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Revision History
|
||||||
|
|
||||||
|
<table><tr><td>Date</td><td>Revision</td><td>Notes</td></tr><tr><td>2019/02/22</td><td>Rev. Prelim</td><td>Definition Draft</td></tr><tr><td>2019/02/23</td><td>Rev. Prelim V0.2</td><td>Add SSOP16 package</td></tr><tr><td>2019/05/06</td><td>Rev. Prelim V0.3</td><td>Add order information</td></tr><tr><td>2019/06/24</td><td>Rev. Prelim V0.4</td><td>Add package and thermal information</td></tr><tr><td>2019/08/19</td><td>Rev. Prelim V0.5</td><td>Update ESD level</td></tr><tr><td>2019/10/21</td><td>Rev. 0</td><td>Final datasheet Rev. 0</td></tr><tr><td>2020/02/18</td><td>Rev. A</td><td>Update RIN1/2 voltage range</td></tr><tr><td>2020/04/24</td><td>Rev. B</td><td>Update C1~C4 recommended value</td></tr><tr><td>2021/06/02</td><td>Rev. B.1</td><td>Update HBM all pin: ±6 kV</td></tr></table>
|
||||||
|
|
||||||
|
Order Information
|
||||||
|
|
||||||
|
<table><tr><td>Order Number</td><td>Operating Temperature Range</td><td>Package</td><td>Marking Information</td><td>MSL</td><td>Transport Media, Quantity</td></tr><tr><td>TPT3232E-SS3R</td><td>-40 to 125°C</td><td>SS3R16-Pin SSOP</td><td>3232E</td><td>MSL3</td><td>Tape and Reel, 2000</td></tr><tr><td>TPT3232E-TS3R</td><td>-40 to 125°C</td><td>TS3R16-Pin TSSOP</td><td>3232E</td><td>MSL3</td><td>Tape and Reel, 3000</td></tr><tr><td>TPT3232E-SO3R</td><td>-40 to 125°C</td><td>SO3R16-Pin SOP</td><td>3232E</td><td>MSL3</td><td>Tape and Reel, 2500</td></tr></table>
|
||||||
|
|
||||||
|
Pin Configuration and Functions
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
C1+ 1
|
||||||
|
V+ 2
|
||||||
|
C1- 3
|
||||||
|
C2+ 4
|
||||||
|
C2- 5
|
||||||
|
V- 6
|
||||||
|
TOUT2 7
|
||||||
|
RIN2 8
|
||||||
|
TPT3232E
|
||||||
|
16 Vcc
|
||||||
|
15 GND
|
||||||
|
14 TOUT1
|
||||||
|
13 RIN1
|
||||||
|
12 ROUT1
|
||||||
|
11 TIN1
|
||||||
|
10 TIN2
|
||||||
|
9 ROUT2
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<table><tr><td>Pin No.</td><td>Symbol</td><td>I/O Type</td><td>Description</td></tr><tr><td>1</td><td>C1+</td><td></td><td>Positive lead of C1 capacitor</td></tr><tr><td>2</td><td>V+</td><td>Output</td><td>Positive charge pump output for storage capacitor only</td></tr><tr><td>3</td><td>C1-</td><td></td><td>Negative lead of C1 capacitor</td></tr><tr><td>4</td><td>C2+</td><td></td><td>Positive lead of C2 capacitor</td></tr><tr><td>5</td><td>C2-</td><td></td><td>Negative lead of C2 capacitor</td></tr><tr><td>6</td><td>V-</td><td>Output</td><td>Negative charge pump output for storage capacitor only</td></tr><tr><td>7</td><td>TOUT2</td><td>Output</td><td>Output of RS232 driver, RS232 level</td></tr><tr><td>8</td><td>RIN2</td><td>Input</td><td>Input of RS232 receiver, RS232 level</td></tr><tr><td>9</td><td>ROUT2</td><td>Output</td><td>Output of RS232 receiver, TTL/CMOS level</td></tr><tr><td>10</td><td>TIN2</td><td>Input</td><td>Input of RS232 driver, TTL/CMOS level</td></tr><tr><td>11</td><td>TIN1</td><td>Input</td><td>Input of RS232 driver, TTL/CMOS level</td></tr><tr><td>12</td><td>ROUT1</td><td>Output</td><td>Output of RS232 receiver, TTL/CMOS level</td></tr><tr><td>13</td><td>RIN1</td><td>Input</td><td>Input of RS232 receiver, RS232 level</td></tr><tr><td>14</td><td>TOUT1</td><td>Output</td><td>Output of RS232 driver, RS232 level</td></tr><tr><td>15</td><td>GND</td><td></td><td>Ground</td></tr><tr><td>16</td><td> $V_{CC}$ </td><td></td><td>Supply voltage</td></tr></table>
|
||||||
|
|
||||||
|
3V to 5.5V, 250kbps RS-232 Transceivers
|
||||||
|
|
||||||
|
Absolute Maximum Ratings
|
||||||
|
|
||||||
|
<table><tr><td>SYMBOL</td><td>DESCRIPTION</td><td>MIN</td><td>MAX</td><td>UNIT</td></tr><tr><td> $V_{CC}$ </td><td>Supply voltage</td><td>-0.3</td><td>6</td><td>V</td></tr><tr><td>V+</td><td>Positive output supply voltage</td><td>-0.3</td><td>7</td><td>V</td></tr><tr><td>V-</td><td>Negative output supply voltage</td><td>-7</td><td>0.3</td><td>V</td></tr><tr><td>V+ - V-</td><td>Supply voltage difference</td><td></td><td>13</td><td>V</td></tr><tr><td>TIN1, TIN2</td><td>Input voltage of driver, TTL/CMOS level</td><td>-0.3</td><td>6</td><td>V</td></tr><tr><td>TOUT1, TOUT2</td><td>Output voltage of driver, RS232 level</td><td>-13.2</td><td>13.2</td><td>V</td></tr><tr><td>RIN1, RIN2</td><td>Input voltage of receiver, RS232 level</td><td>-15</td><td>15</td><td>V</td></tr><tr><td>ROUT1, ROUT2</td><td>Output voltage of receiver, TTL/CMOS level</td><td>-0.3</td><td> $V_{CC} +0.3$ </td><td>V</td></tr><tr><td> $T_J$ </td><td>Operating virtual junction temperature</td><td></td><td>150</td><td>°C</td></tr></table>
|
||||||
|
|
||||||
|
(1) Stresses beyond the Absolute Maximum Ratings may cause permanent damage to the device. These are stress ratings only, which do not imply functional operation of the device at these or any other conditions beyond those indicated under Recommended Operating Conditions.
|
||||||
|
|
||||||
|
Thermal Resistance
|
||||||
|
|
||||||
|
<table><tr><td>PART NUMBER</td><td>PACKAGE TYPE</td><td> $\theta_{JA}$ </td><td> $\theta_{JC}$ </td><td>UNIT</td></tr><tr><td>TPT3232E -SS3R</td><td>16-Pin SSOP</td><td>103</td><td>45</td><td>°C/W</td></tr><tr><td>TPT3232E -TS3R</td><td>16-Pin TSSOP</td><td>115</td><td>48</td><td>°C/W</td></tr><tr><td>TPT3232E -SO3R</td><td>16-Pin SOP</td><td>91</td><td>43</td><td>°C/W</td></tr></table>
|
||||||
|
|
||||||
|
ESD Rating
|
||||||
|
|
||||||
|
<table><tr><td></td><td></td><td>Value</td><td>UNIT</td></tr><tr><td>RS232 Bus Pin: TOUT1, TOUT2, RIN1, RIN2</td><td>HBM, Human body model</td><td>±15</td><td>kV</td></tr><tr><td>RS232 Bus Pin: TOUT1, TOUT2, RIN1, RIN2</td><td>IEC-61000-4-2, Contact Discharge</td><td>±12</td><td>kV</td></tr><tr><td>RS232 Bus Pin: TOUT1, TOUT2, RIN1, RIN2</td><td>IEC-61000-4-2, Air-Gap Discharge</td><td>±15</td><td>kV</td></tr><tr><td>All Pin except RS232 Bus Pin</td><td>HBM, Human body model</td><td>±6</td><td>kV</td></tr><tr><td>All Pin</td><td>CDM, Charge device model</td><td>±1.5</td><td>kV</td></tr></table>
|
||||||
|
|
||||||
|
Electrical Characteristics
|
||||||
|
The following specifications apply for $V_{CC} = 3.0V$ to 3.6V, 4.5 to 5.5V, C1 - C4 = 0.2 $\mu$ F, $T_{A} = -40^{\circ}C$ to 125°C, unless otherwise noted.
|
||||||
|
|
||||||
|
<table><tr><td>Parameter</td><td>Conditions</td><td>Min</td><td>Typ</td><td>Max</td><td>Units</td></tr><tr><td colspan="6">DC Characteristics</td></tr><tr><td>Icc = Supply Current</td><td>no load, VCC = 3.3V, TINx = GND or VCC, TA = 25°C</td><td></td><td>1.2</td><td>15</td><td>mA</td></tr><tr><td colspan="6">Logic Inputs and Receiver Outputs</td></tr><tr><td>Input Voltage of Logic Low</td><td>TIN1, TIN2</td><td></td><td></td><td>0.8</td><td>V</td></tr><tr><td>Input Voltage of Logic High</td><td>TIN1, TIN2, VCC = 3.3V</td><td>2</td><td></td><td></td><td>V</td></tr><tr><td>Input Voltage of Logic High</td><td>TIN1, TIN2, VCC = 5.0V</td><td>2.4</td><td></td><td></td><td>V</td></tr><tr><td>Input Leakage Current</td><td>TIN1, TIN2, VIN = 0V to VCC, TA = 25°C</td><td>-1</td><td></td><td>15</td><td>μA</td></tr><tr><td>Output Leakage Current</td><td>Rout1,Rout2, VCC=3.3V</td><td>-15</td><td></td><td>10</td><td>uA</td></tr><tr><td>Output Voltage Low</td><td>IOUT = -1.5mA</td><td></td><td></td><td>0.3</td><td>V</td></tr><tr><td>Output Voltage High</td><td>IOUT = 1.5mA</td><td>VCC-0.3</td><td></td><td></td><td>V</td></tr><tr><td colspan="6">Driver Outputs</td></tr><tr><td>Output Voltage Swing</td><td>RL = 3kΩ, TINx = GND</td><td>±5.0</td><td>±5.4</td><td></td><td>V</td></tr><tr><td>Output Resistance</td><td>VCC = V+ = V- = 0V, TOUTx=+2V, note1</td><td></td><td>2.4M</td><td></td><td>Ω</td></tr><tr><td>Output Short-Circuit Current</td><td>VOUT = 0V</td><td>-60</td><td></td><td>60</td><td>mA</td></tr><tr><td colspan="6">Receiver Inputs</td></tr><tr><td>Input Voltage Range</td><td></td><td>-15</td><td></td><td>15</td><td>V</td></tr><tr><td rowspan="2">Input Threshold Low</td><td>VCC = 3.3V,</td><td>0.6</td><td>1.30</td><td></td><td rowspan="2">V</td></tr><tr><td>VCC = 5.0V</td><td>0.8</td><td>1.30</td><td></td></tr><tr><td rowspan="2">Input Threshold High</td><td>VCC = 3.3V,</td><td></td><td>1.60</td><td>2.4</td><td rowspan="2">V</td></tr><tr><td>VCC = 5.0V</td><td></td><td>1.60</td><td>2.4</td></tr><tr><td>Input Hysteresis</td><td></td><td></td><td>0.3</td><td></td><td>V</td></tr><tr><td>Input Resistance</td><td>note1</td><td>3</td><td>5</td><td>7</td><td>kΩ</td></tr><tr><td colspan="6">Timing Characteristics</td></tr><tr><td>Maximum Data Rate</td><td>RL = 3kΩ, CL = 1000pF, one driver switching, Note1</td><td></td><td></td><td>250</td><td>kbps</td></tr><tr><td>Driver Propagation Delay, high to low output, tDPHL</td><td>Driver input to receiver output, CL = 150pF</td><td></td><td>700</td><td>1000</td><td>ns</td></tr><tr><td>Driver Propagation Delay, low to high output, tDPLH</td><td>Driver input to receiver output, CL = 150pF</td><td></td><td>500</td><td>700</td><td>ns</td></tr><tr><td>Driver Skew</td><td>| tDPHL - tDPLH |</td><td></td><td>200</td><td>400</td><td>ns</td></tr><tr><td>Transition-Region Slew Rate</td><td>Vcc = 3.3V, RL = 3kΩ, CL = 1000pF, TA = 25°C, note1</td><td>6</td><td>10</td><td>30</td><td>V/μs</td></tr><tr><td>Receiver Propagation Delay, high to low output, tRPHL</td><td>Receiver input to receiver output, CL = 150pF</td><td></td><td>180</td><td>300</td><td>ns</td></tr><tr><td>Receiver Propagation Delay, low to high output, tRPLH</td><td>Receiver input to receiver output, CL = 150pF</td><td></td><td>210</td><td>400</td><td>ns</td></tr><tr><td>Receiver Skew</td><td>| tRPHL - tRPLH |</td><td></td><td>30</td><td>100</td><td>ns</td></tr></table>
|
||||||
|
|
||||||
|
Note1: based on Bench characterization and design simulation
|
||||||
|
Note2: Icc =3mA with no load; and Icc=15mA with max load, $R_{L} = 3k\Omega$ , $C_{L} = 1000pF$
|
||||||
|
|
||||||
|
3V to 5.5V, 250kbps RS-232 Transceivers
|
||||||
|
|
||||||
|
# Parameter Measurement Information
|
||||||
|
|
||||||
|

|
||||||
|
Figure 1 Receiver Propagation Delay and Receiver Skew
|
||||||
|
|
||||||
|
# Typical Application Circuit
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
Vcc
|
||||||
|
0.1µF
|
||||||
|
16
|
||||||
|
C1+
|
||||||
|
C1
|
||||||
|
C2+
|
||||||
|
C2-
|
||||||
|
TIN1
|
||||||
|
TIN2
|
||||||
|
ROUT1
|
||||||
|
ROUT2
|
||||||
|
TPT3232E
|
||||||
|
Vcc
|
||||||
|
V+
|
||||||
|
V-
|
||||||
|
T1
|
||||||
|
T2
|
||||||
|
R1
|
||||||
|
R2
|
||||||
|
GND
|
||||||
|
14
|
||||||
|
10
|
||||||
|
12
|
||||||
|
9
|
||||||
|
15
|
||||||
|
2
|
||||||
|
6
|
||||||
|
C3
|
||||||
|
C4
|
||||||
|
TOUT1
|
||||||
|
TOUT2
|
||||||
|
TOUT
|
||||||
|
13
|
||||||
|
RIN1
|
||||||
|
RIN2
|
||||||
|
5kΩ
|
||||||
|
5kΩ
|
||||||
|
RS-232
|
||||||
|
LEVELS
|
||||||
|
TTL/CMOS
|
||||||
|
LEVELS
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Figure 1 Typical application circuit
|
||||||
|
|
||||||
|
Non-polarized ceramic capacitors are acceptable. If polarized tantalum or electrolytic capacitors are used, they should be connected as shown in Figure 1. The recommended capacitor value of C1 to C4 is in Table 1. All cap is 0.2uF for TPT3232E
|
||||||
|
|
||||||
|
<table><tr><td> $V_{cc}(V)$ </td><td>C1(μF)</td><td>C2, C3, C4(μF)</td></tr><tr><td>3.0 to 3.6</td><td>0.2</td><td>0.1</td></tr><tr><td>4.5 to 5.5</td><td>0.1</td><td>0.1</td></tr><tr><td>3.0 to 5.5</td><td>0.2</td><td>0.2</td></tr></table>
|
||||||
|
|
||||||
|
Table 1 Required Minimum Capacitor Values
|
||||||
|
|
||||||
|
Tape and Reel Information
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>natural_image</summary>
|
||||||
|
|
||||||
|
Technical line drawing of a wheel with four spokes and a central hub (no text or symbols)
|
||||||
|
</details>
|
||||||
|
|
||||||
|
D1: Reel Diameter
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>natural_image</summary>
|
||||||
|
|
||||||
|
Pure structural diagram of a vertical column with horizontal supports and a central horizontal line (no text or symbols)
|
||||||
|
</details>
|
||||||
|
|
||||||
|
W1: Reel Width
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
Direction of Feed
|
||||||
|
W0
|
||||||
|
P0
|
||||||
|
A0
|
||||||
|
B0
|
||||||
|
K0
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<table><tr><td>Order Number</td><td>Package</td><td>D1</td><td>W1</td><td>A0</td><td>B0</td><td>K0</td><td>P0</td><td>W0</td><td>Pin1 Quadrant</td></tr><tr><td>TPT3232E-SO3R</td><td>SOP16</td><td>330</td><td>21.6</td><td>6.7±0.1</td><td>10.4±0.1</td><td>2.1±0.1</td><td>8.0±0.1</td><td>16.0±0.3</td><td>Q1</td></tr><tr><td>TPT3232E-TS3R</td><td>TSSOP16</td><td>330</td><td>17.6</td><td>6.8±0.1</td><td>5.4±0.1</td><td>1.3±0.1</td><td>8.0±0.1</td><td>12.0±0.1</td><td>Q1</td></tr><tr><td>TPT3232E-SS3R</td><td>SSOP16</td><td>330</td><td>21.6</td><td>8.5</td><td>6.8</td><td>2.37</td><td>12.00</td><td>16.00</td><td>Q1</td></tr></table>
|
||||||
|
|
||||||
|
# Package Outline Dimensions
|
||||||
|
|
||||||
|
SS3R (SSOP16)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
D
|
||||||
|
E
|
||||||
|
E1
|
||||||
|
</details>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
L
|
||||||
|
θ
|
||||||
|
C
|
||||||
|
</details>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
A1
|
||||||
|
e
|
||||||
|
b
|
||||||
|
A2
|
||||||
|
A
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<table><tr><td rowspan="2">Symbol</td><td colspan="2">Dimensions In Millimeters</td><td colspan="2">Dimensions In Inches</td></tr><tr><td>Min</td><td>Max</td><td>Min</td><td>Max</td></tr><tr><td>A</td><td>——</td><td>2.000</td><td>——</td><td>0.079</td></tr><tr><td>A1</td><td>0.050</td><td>——</td><td>0.002</td><td>——</td></tr><tr><td>A2</td><td>1.650</td><td>1.850</td><td>0.065</td><td>0.073</td></tr><tr><td>b</td><td>0.220</td><td>0.380</td><td>0.009</td><td>0.015</td></tr><tr><td>c</td><td>0.090</td><td>0.250</td><td>0.004</td><td>0.010</td></tr><tr><td>D</td><td>5.900</td><td>6.500</td><td>0.232</td><td>0.256</td></tr><tr><td>E</td><td>7.400</td><td>8.200</td><td>0.291</td><td>0.323</td></tr><tr><td>E1</td><td>5.000</td><td>5.600</td><td>0.197</td><td>0.220</td></tr><tr><td>e</td><td colspan="2">0.650 (BSC)</td><td colspan="2">0.026 (BSC)</td></tr><tr><td>L</td><td>0.550</td><td>0.950</td><td>0.022</td><td>0.037</td></tr><tr><td>θ</td><td>0°</td><td>8°</td><td>0°</td><td>8°</td></tr></table>
|
||||||
|
|
||||||
|
# TS3R (TSSOP16)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
E1
|
||||||
|
E
|
||||||
|
B B
|
||||||
|
e b
|
||||||
|
</details>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
D
|
||||||
|
A3
|
||||||
|
A2
|
||||||
|
A
|
||||||
|
A1
|
||||||
|
</details>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
0.25
|
||||||
|
L
|
||||||
|
L1
|
||||||
|
θ
|
||||||
|
c
|
||||||
|
</details>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
BASE METAL
|
||||||
|
WITH PLATING
|
||||||
|
SECTION B-B
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<table><tr><td rowspan="2">SYMBOL</td><td colspan="3">MILLIMETER</td></tr><tr><td>MIN</td><td>NOM</td><td>MAX</td></tr><tr><td>A</td><td>—</td><td>—</td><td>1.20</td></tr><tr><td>A1</td><td>0.05</td><td>—</td><td>0.15</td></tr><tr><td>A2</td><td>0.90</td><td>1.00</td><td>1.05</td></tr><tr><td>A3</td><td>0.39</td><td>0.44</td><td>0.49</td></tr><tr><td>b</td><td>0.20</td><td>—</td><td>0.28</td></tr><tr><td>b1</td><td>0.19</td><td>0.22</td><td>0.25</td></tr><tr><td>c</td><td>0.13</td><td>—</td><td>0.17</td></tr><tr><td>c1</td><td>0.12</td><td>0.13</td><td>0.14</td></tr><tr><td>D</td><td>4.90</td><td>5.00</td><td>5.10</td></tr><tr><td>E</td><td>6.20</td><td>6.40</td><td>6.60</td></tr><tr><td>E1</td><td>4.30</td><td>4.40</td><td>4.50</td></tr><tr><td>e</td><td colspan="3">0.65BSC</td></tr><tr><td>L</td><td>0.45</td><td>0.60</td><td>0.75</td></tr><tr><td>L1</td><td colspan="3">1.00BSC</td></tr><tr><td>θ</td><td>0</td><td>—</td><td>8°</td></tr></table>
|
||||||
|
|
||||||
|
3V to 5.5V, 250kbps RS-232 Transceivers
|
||||||
|
|
||||||
|
SO3R (SOP16)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
D
|
||||||
|
A3
|
||||||
|
A2
|
||||||
|
A
|
||||||
|
A1
|
||||||
|
</details>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>text_image</summary>
|
||||||
|
|
||||||
|
E1 E
|
||||||
|
b
|
||||||
|
e
|
||||||
|
B B
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<table><tr><td rowspan="2">SYMBOL</td><td colspan="3">MILLIMETER</td></tr><tr><td>MIN</td><td>NOM</td><td>MAX</td></tr><tr><td>A</td><td>-</td><td>-</td><td>1.75</td></tr><tr><td>A1</td><td>0.10</td><td>-</td><td>0.225</td></tr><tr><td>A2</td><td>1.30</td><td>1.40</td><td>1.50</td></tr><tr><td>A3</td><td>0.60</td><td>0.65</td><td>0.70</td></tr><tr><td>b</td><td>0.39</td><td>-</td><td>0.47</td></tr><tr><td>b1</td><td>0.38</td><td>0.41</td><td>0.44</td></tr><tr><td>c</td><td>0.20</td><td>-</td><td>0.24</td></tr><tr><td>c1</td><td>0.19</td><td>0.20</td><td>0.21</td></tr><tr><td>D</td><td>9.80</td><td>9.90</td><td>10.00</td></tr><tr><td>E</td><td>5.80</td><td>6.00</td><td>6.20</td></tr><tr><td>E1</td><td>3.80</td><td>3.90</td><td>4.00</td></tr><tr><td>e</td><td colspan="3">1.27BSC</td></tr><tr><td>h</td><td>0.25</td><td>-</td><td>0.50</td></tr><tr><td>L</td><td>0.50</td><td>-</td><td>0.80</td></tr><tr><td>L1</td><td colspan="3">1.05REF</td></tr><tr><td>θ</td><td>0</td><td>-</td><td>8°</td></tr></table>
|
||||||
|
|
||||||
|

|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user