feat(spi): 更新SPI命令v2,处理逻辑和项目配置

- 在cproject.yml中添加spi_link模块组和相关头文件路径
- 修改boot_request.cpp中的ACK响应机制,改用标准帧格式并优化CAN反馈处理
- 重构ping.cpp响应payload结构,包含版本信息、运行时间等16字节数据
- 添加systick.h依赖用于获取系统运行时间
- 优化启动bootloader流程,避免SPI中断阻塞问题
This commit is contained in:
cbb
2026-07-13 03:10:37 +08:00
parent 10989939e9
commit 7c05496b89
9 changed files with 422 additions and 345 deletions
+29 -22
View File
@@ -6,26 +6,26 @@
class ISpiCommandHandler;
/**
* @brief GD32 侧 SPI 链路状态机:封装按铃状态 + ESP32 完成信号。
* @brief GD32 侧 SPI 链路状态机:封装按铃状态。
*
* 线状态语义(对齐 OTA):
* - 线 HIGH = 空闲(双方释放),GD32 可发起新按铃
* - 线 LOW = 忙碌(GD32 按铃下拉 或 ESP32 checkGd32Request 期间下拉)
* v2 DATA_READY 语义:PB6 低 = 有待发数据,高 = 队列空。
* ESP32 不再操作 PB6,无独立「完成」信号;按铃完成由 ESP32
* 的 CS 读事务本身确认(onCsRelease 按铃响应路径调 onEsp32Complete)。
*
* 状态流转:
* - canRingNow()=true(初始/ESP32 完成后)→ requestEsp32Read() → canRingNow()=false
* - ESP32 releaseReady 上升沿 → onEsp32Complete() → canRingNow()=true
* - 按铃超时 → onRingTimeout() → canRingNow()=true(允许重试)
* canRingNow() 总是返回 true,由 requestEsp32Read() 的 m_ringPending
* 检查控制重复按铃。
*/
class SpiLinkState {
public:
/** 是否允许发起新按铃(ESP32 已完成上一帧 或 初始态)。 */
bool canRingNow() const { return m_esp32Ready; }
/** 是否允许发起新按铃。
* v2 DATA_READY: ESP32 不再操作 PB6,无独立完成信号;
* 总是允许,由 requestEsp32Read() 的 m_ringPending 检查控制重复。 */
bool canRingNow() const { return true; }
/** 发起按铃时调用(消费完成 flag)。 */
/** 发起按铃时调用(v2 下仅保留兼容写法,无实际门禁作用)。 */
void onRingStart() { m_esp32Ready = false; }
/** ESP32 releaseReady 上升沿触发(EXTI6 ISR 调用)。 */
/** ESP32 CS 读事务完成确认(onCsRelease 按铃响应路径调用)。 */
void onEsp32Complete() { m_esp32Ready = true; }
/** 按铃超时取消时调用(允许重试,不依赖 EXTI)。 */
@@ -48,14 +48,14 @@ private:
* 具体命令处理逻辑不再放在这里,而是拆到 device/spi/app_spi_cmd_*.cpp,
* 通过 registerHandler() 注册进来,保持本模块可扩展。
*
* 握手架构(线与 SPIready,PB6<->ESP32 GPIO10 开漏单线):
* - 空闲态线 HIGH(双方释放,靠上拉)。
* - ESP32 主动发起:下拉 SPIready -> 立刻 CS 发请求 -> CS 释放后保持下拉,
* GD32 在 onCsRelease() ISR 内完成帧处理+响应装载后释放 SPIready(高),
* ESP32 检测到上升沿后发起 CS#2 读响应。
* - GD32 主动按铃:下拉 SPIready -> ESP32 下降沿中断唤醒后发起读事务,
* GD32 在 onCsRelease() 中装入请求帧并释放 SPIready。
* 握手架构(v2 DATA_READY,PB6<->ESP32 GPIO10 开漏单线):
* - PB6 低 = 有待发数据(m_txLen>0 或 m_ringPending),高 = 队列空。
* - ESP32 主动发起:CS 发请求,CS 释放后 GD32 在 onCsRelease() ISR 内
* 完成帧处理+响应装载,由 updateDataReady() 据 m_txLen 驱动 PB6。
* - GD32 主动按铃:requestEsp32Read() 设 m_ringPending=true 且 m_txLen>0,
* updateDataReady() 拉低 PB6,ESP32 检测下降沿后发起读事务读走请求帧。
* - PB6 配置为开漏输出,setSpiReady(true)=高阻释放,setSpiReady(false)=下拉。
* - ESP32 不再操作 PB6,EXTI6 上升沿仅清标志,无业务含义。
*/
class AppSpiCommand {
public:
@@ -71,7 +71,8 @@ public:
/** @brief CS 边沿中断处理入口。 */
void onCsExtiInterrupt();
/** @brief SPI Ready(PB6) EXTI 上升沿中断处理入口(ESP32 完成信号)。 */
/** @brief SPI Ready(PB6) EXTI6 中断入口。
* v2 DATA_READY: ESP32 不再操作 PB6,EXTI6 仅清标志。 */
void onSpiReadyExti();
/**
@@ -120,6 +121,10 @@ public:
/** @brief 查询当前是否有未读按铃(ESP32 尚未来读)。 */
bool isRingPending() const { return m_ringPending; }
/** @brief 取消未完成的按铃(释放 SPIready、清 m_ringPending)。
* 0xB0 进 BOOT 等路径需公开调用,避免 0xC1 残留盖住 ACK。 */
void cancelRing();
/** @brief 查询 ESP32 是否已完成上一帧处理(SPIready 上升沿触发)。
* 初始为 true 允许第一次按铃;每次 requestEsp32Read 后置 false,
* ESP32 releaseReady 产生上升沿后由 EXTI 置 true。 */
@@ -172,8 +177,10 @@ private:
*/
void setSpiReady(bool ready);
/** @brief 取消未完成的按铃(释放 SPIready、清 m_ringPending)。 */
void cancelRing();
/** @brief v2 DATA_READY 语义:依据待发数据驱动 PB6。
* PB6 低 = 有待发数据(m_txLen>0 或 m_ringPending),高 = 队列空。
* 替代旧 BUSY/READY 语义中所有 setSpiReady 调用。 */
void updateDataReady();
};
/**