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:
小龙虾
2026-08-02 17:37:19 +08:00
parent 04a118219f
commit f9cbcc396b
42 changed files with 1957 additions and 4537 deletions
+23
View File
@@ -0,0 +1,23 @@
@echo off
REM Clear MSYS/MINGW env vars to bypass IDF MSys detection when called from Git Bash
set MSYSTEM=
set MSYSTEM_CHOST=
set MSYSTEM_PREFIX=
set MINGW_CHOST=
set MINGW_PREFIX=
set MINGW_PACKAGE_PREFIX=
set CHERE_INVOKING=
set MSYS2_PATH_TYPE=
REM Toolchain installed at C:\Espressif (see .vscode/settings.json idf.toolsPath)
set IDF_TOOLS_PATH=C:\Espressif
call "F:\software\.espressif\v6.0\esp-idf\export.bat"
if errorlevel 1 (
echo EXPORT_FAILED
exit /b 1
)
cd /d "G:\Robot_v2\DCU\ESP32_COMM"
idf.py build
exit /b %errorlevel%␍
+13 -5
View File
@@ -216,11 +216,19 @@ export async function pollStatus() {
if (window.isEsp32Rebooting ||
window.otaSessionState === window.OtaSessionState.REBOOTING) {
var rbElapsed = Math.round((Date.now() - window.rebootStartTime) / 1000);
// pre-reboot 窗口:后端发响应后约 1s 才 esp_restart,期间设备仍响应轮询,
// 保持"重启中"状态,不清除标志,不推进阶段。
// ★ 真正的"重启完成"由 pollLogs 收到启动 banner 触发;
// 这里只在已观察到下线(rebootObservedDown)或超 10s 安全阈值时接受恢复。
if (window.rebootObservedDown || rbElapsed >= 10) {
/* 重启完成的证据(任一即可):
* 1) rebootObservedDown:已观察到设备下线后恢复。
* 2) freshBoot:设备回报 uptime 很小(<120s,与 resolveEsp32VerifyAmbiguous
* 的 freshBoot 阈值一致)。★ 关键:设备掉线仅 3~5s 时(FAST_SCAN 生效后
* 常见),在途轮询的 TCP SYN 重传会在设备起来后完成握手、全部成功,
* rebootObservedDown 永远不置位,旧逻辑只能干等 10s 兜底——
* 实测设备 3s 就绪、页面却 10s 才恢复。uptime 是新固件启动的权威信号。
* 3) rbElapsed >= 10:安全兜底(兼容 uptime 缺失 / 设备未真重启)。
* pre-restart 窗口(finalize 响应后约 1s 设备仍在跑旧固件)uptime 很大,
* 不会误判为 freshBoot。 */
var upS = Number(data && data.uptime_sec);
var freshBoot = Number.isFinite(upS) && upS >= 0 && upS < 120;
if (window.rebootObservedDown || freshBoot || rbElapsed >= 10) {
markEsp32RebootComplete();
}
}
+3 -3
View File
@@ -113,15 +113,15 @@
function addHistory(frames, payload, text) {
/* 从设备中文文本里提取关键数字做历史行 */
var fail = (text.match(/失败:\s*(\d+)/) || [])[1] || "?";
var avg = (text.match(/平均\s*([\d.]+)\s*ms/) || [])[1] || "?";
var min = (text.match(/最快\s*([\d.]+)\s*ms/) || [])[1] || "?";
var avg = (text.match(/平均\s*([\d.]+)\s*µs/) || [])[1] || "?";
var min = (text.match(/最快\s*([\d.]+)\s*µs/) || [])[1] || "?";
var tput = (text.match(/等效吞吐:\s*([\d.]+)\s*KB\/s/) || [])[1] || "-";
var d = new Date();
var tr = document.createElement("tr");
var cells = [
pad2(d.getHours()) + ":" + pad2(d.getMinutes()) + ":" + pad2(d.getSeconds()),
String(frames), String(payload) + "B", fail,
avg + "ms", min + "ms", tput === "-" ? "-" : tput + "KB/s"
avg + "µs", min + "µs", tput === "-" ? "-" : tput + "KB/s"
];
for (var i = 0; i < cells.length; i++) {
var td = document.createElement("td");