feat(spi): 增强 SPI master:性能剖析与执行耗时跟踪
- 新增 `lastWorkerExecUs()`:获取最近一次 worker 任务执行耗时(µs)。 - 引入 `SpiProfile` 结构体:事务级详细剖析,记录 SPI 事务各阶段的时间戳。 - 实现 `lastProfile()`:诊断用,获取最近一次事务剖析快照。 - SPI 时钟配置提升至 13.3 MHz,改善性能。 - 修改前端 JavaScript 轮询逻辑:新增 uptime 检查,更好地处理 ESP32 重启状态。 - SPI 测速 HTML 的计时单位由毫秒改为微秒显示。 - 新建 `spi_ring_cache.h`:共享 SPI ring push 缓存工具。 - 新增 `http_util.h`:共享 HTTP 处理器工具,含 JSON 拼接与查询参数解析。 - 引入 `json_parse.h`:轻量级 JSON 解析器,针对扁平 JSON 对象设计。 - 新增 Windows 环境下的项目构建批处理脚本。 - 重构 CAN 反馈处理:从推送式改为请求驱动架构,降低内存占用、提升效率。
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
## 方案:/can/feedback 改为请求驱动架构
|
||||
|
||||
### 目标
|
||||
- ESP32 不再被动缓存 GD32 的 0xC1 推送,改为前端请求时主动向 GD32 查询
|
||||
- GD32 停止主动推送 0xC1(降低 SPI 资源占用)
|
||||
- 删除 `s_latest[3]`/`s_work[3]` 常驻 BSS(省 ~7.8KB)+ handler 栈上 `results[3]`(省 ~3.9KB 栈)
|
||||
|
||||
### 依据
|
||||
- GD32 `handleFeedback` 已支持 0xC1 请求查询(`[channel, page]` → ACK + 页数据),无需新增协议
|
||||
- ESP32 `transact(0xC1, ...)` 是现成请求/响应机制,`canFdSend`/`canFdSetRxMode` 已在用
|
||||
- `canFdParseFeedbackPage` 可直接复用(只解析 payload 字节,不关心来源)
|
||||
- 0xC4/0xC5/0xC6/0xD2 推送独立,不受影响
|
||||
|
||||
### 改动清单
|
||||
|
||||
#### 1. ESP32 侧 — `main/transport/canfd_bridge.cpp` / `.h`
|
||||
新增 `canFdQueryFeedback(channel, page, can_feedback_result_t *out, uint8_t *entryIdx)`:
|
||||
```cpp
|
||||
int canFdQueryFeedback(uint8_t channel, uint8_t page,
|
||||
can_feedback_result_t *out, uint8_t *entryIdx);
|
||||
```
|
||||
- 发 `transact(0xC1, {channel, page}, ...)`,超时 200ms
|
||||
- 成功(resp_type==ACK)→ 调 `canFdParseFeedbackPage(resp_buf, resp_len, out, entryIdx)`
|
||||
- 返回 0=成功,-1=SPI/参数失败,-2=GD32 拒绝(ERROR)
|
||||
|
||||
#### 2. ESP32 侧 — `main/server/http_handlers.cpp` `can_feedback_handler`
|
||||
- 删除 `results[CAN_CHANNEL_MAX]` 栈数组 + `getLatestCanFeedback` 循环
|
||||
- 改为:对每个使能通道,调 `canFdQueryFeedback(ch, 0, &result, &entryIdx)` + `canFdQueryFeedback(ch, 1, &result, &entryIdx)`,在栈上用单个 `can_feedback_result_t result`(1.3KB,用完即释放)
|
||||
- lite 路径:只需 page 0(统计字段在 page0 header),1 次 SPI 查询即可
|
||||
- full 路径:page 0 + page 1,2 次查询,然后序列化
|
||||
- 查询失败 → 该通道 `valid=false`(与原来无快照时行为一致)
|
||||
- `pauseCanFeedbackTask` 调用保留(send_batch 仍需独占 SPI)
|
||||
|
||||
#### 3. ESP32 侧 — `can_mode_handler` GET
|
||||
- 原来 `getLatestCanFeedback(0, &fb)` 读缓存 mode → 改为 `canFdQueryFeedback(0, 0, &fb, &entryIdx)` 取 page0 的 mode 字段
|
||||
- 原来的 fallback `canFdSetRxMode` 保留(查询也失败时兜底)
|
||||
|
||||
#### 4. ESP32 侧 — `main/monitor/can_feedback_task.cpp`
|
||||
- **删除** `s_latest[3]`、`s_valid[3]`、`s_work[3]`、`s_workIdx[3]`、`s_lastLoggedError[3]`、`publish()`、`getLatestCanFeedback()`
|
||||
- **删除** taskLoop 里的 0xC1 分支(`canFdParseFeedbackPage` + `publish`)
|
||||
- **保留** 0xC4/0xC5/0xC6/0xD2 事件分发(这些仍走推送)
|
||||
- **保留** `pauseCanFeedbackTask`(send_batch / OTA 仍需暂停事件消费)
|
||||
- `s_mutex` 删除(仅保护 s_latest/s_valid,不再需要)
|
||||
|
||||
#### 5. ESP32 侧 — `main/monitor/can_feedback_task.h`
|
||||
- 删除 `getLatestCanFeedback` 声明
|
||||
- 保留 `startCanFeedbackTask`、`pauseCanFeedbackTask`
|
||||
|
||||
#### 6. GD32 侧 — `app_spi_cmd_can_feedback.cpp`
|
||||
- `canFeedbackStartRound()`:改为空函数(或加 `s_pushEnabled=false` 永久禁用推送)
|
||||
- `canFeedbackPushStep()`:开头加 `if (!s_pushEnabled) return;` 或直接 return
|
||||
- **保留** `handleFeedback`(请求查询处理程序不动)
|
||||
- **保留** `buildFeedbackPayload`(查询和推送共用)
|
||||
|
||||
#### 7. GD32 侧 — `task_runner.cpp`
|
||||
- `canFeedbackStartRound()` 调用可保留(变成空函数无副作用)或删除
|
||||
|
||||
### 内存收益
|
||||
| 项 | 改前 | 改后 | 省 |
|
||||
|---|---|---|---|
|
||||
| `s_latest[3]` BSS | 3.9KB | 0 | 3.9KB |
|
||||
| `s_work[3]` BSS | 3.9KB | 0 | 3.9KB |
|
||||
| handler 栈 `results[3]` | 3.9KB | 1.3KB(单通道) | 2.6KB 栈 |
|
||||
| **合计常驻 BSS** | | | **~7.8KB** |
|
||||
|
||||
### 性能影响
|
||||
- 原来读缓存:<1ms
|
||||
- 改后查询:lite 路径 1 次 SPI 往返 ~2-4ms;full 路径 6 次往返(3ch×2page)~12-24ms
|
||||
- 前端 1Hz 轮询,24ms 完全可接受(httpd 单线程最坏阻塞 <50ms)
|
||||
- GD32 不再 1Hz 推送 6 帧,省下 SPI 带宽和 PB6 中断
|
||||
|
||||
### 风险与缓解
|
||||
- **SPI 查询失败**:GD32 不响应时 `transact` 超时返回,handler 返回 valid=false,前端显示"--"(与原无快照行为一致)
|
||||
- **OTA 期间查询**:send_batch/OTA 已 `pauseCanFeedbackTask`,且 SPI worker 串行化,查询不会与 OTA 数据流冲突
|
||||
- **can_monitor.html full 路径延迟**:6 次 SPI 查询 ~24ms + JSON 序列化,总 <50ms,远小于 1s 轮询间隔
|
||||
|
||||
### 不改动的部分
|
||||
- 0xC4 ADC、0xC5 motor state、0xC6 motor version、0xD2 motor OTA 推送机制不变
|
||||
- `canFdParseFeedbackPage` 解析逻辑不变
|
||||
- GD32 `handleFeedback` 查询处理程序不变
|
||||
- 前端 JS 不变(API 响应格式不变)
|
||||
Reference in New Issue
Block a user