feat(spi): 实现SPI同步通信协议和主动推送机制
- 实现新的SPI同步帧格式,采用0xA5 0x5A起始符和CRC32校验,提升通信可靠性 - 添加GD32与ESP32间的握手机制,通过PB6开漏输出实现SPIready线与控制 - 实现异步OTA启动机制,将Flash操作延迟到主循环执行,避免SPI ISR阻塞 - 改进CAN反馈命令处理,提取通用payload构建函数支持主动推送模式 - 实现GD32主动按铃机制,循环推送CAN反馈数据到ESP32,减少轮询开销 - 添加SPI通信超时保护和死锁防护机制,确保系统稳定性
This commit is contained in:
@@ -89,6 +89,7 @@ static bool requestMagicValid(const uint8_t *data, uint8_t length)
|
||||
|
||||
/** @brief 已写入 OTA 标志并等待软复位的挂起标志。 */
|
||||
volatile bool OtaBootRequest::s_rebootPending = false;
|
||||
volatile bool OtaBootRequest::s_bootRequestPending = false;
|
||||
|
||||
/**
|
||||
* @brief 初始化进入 Bootloader 请求模块的运行态。
|
||||
@@ -96,6 +97,7 @@ volatile bool OtaBootRequest::s_rebootPending = false;
|
||||
void OtaBootRequest::init()
|
||||
{
|
||||
s_rebootPending = false;
|
||||
s_bootRequestPending = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,6 +119,16 @@ bool OtaBootRequest::requestEnterBoot()
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 异步请求进入 Bootloader(ISR 安全)。
|
||||
* @note 仅设置 pending 标志,Flash 操作和复位由 process() 在主循环执行。
|
||||
* 用于 SPI EXTI ISR 内的 0xB0 命令处理,避免 Flash 擦除阻塞 SPI 中断。
|
||||
*/
|
||||
void OtaBootRequest::requestEnterBootAsync()
|
||||
{
|
||||
s_bootRequestPending = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理备用 CAN 入口的进入 Bootloader 请求。
|
||||
* @note 当前主路径是 SPI 命令;CAN 入口只负责识别魔术字并触发同一套标志写入逻辑。
|
||||
@@ -138,19 +150,34 @@ bool OtaBootRequest::handleCanFrame(uint8_t channel, uint32_t id, const uint8_t
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 在主循环任务中执行短延迟软复位。
|
||||
* @note 不在 SPI/CAN 中断里直接复位,避免应答还没发出就重启。
|
||||
* 这里使用毫秒级短延时,而不是 1s 心跳计数;否则一次 SPI 请求
|
||||
* 实际会拖到 2~3 秒后才复位,ESP32 第二次 OTA 时很容易在 APP 还没
|
||||
* 真正重启进入 BOOT 之前就发出 HANDSHAKE_REQ。
|
||||
* @brief 在主循环任务中执行异步 Flash 操作和短延迟软复位。
|
||||
* @note 不在 SPI/CAN 中断里直接复位,避免应答还没有发出就重启。
|
||||
* 异步路径:SPI ISR 收到 0xB0 后只设标志,Flash 操作(可能擦页 20-30ms)
|
||||
* 在此主循环执行,避免阻塞 SPI 中断导致 ESP32 ACK 轮询丢字节。
|
||||
*/
|
||||
void OtaBootRequest::process()
|
||||
{
|
||||
/* 异步处理 0xB0 请求:在主循环执行 Flash 操作(20-30ms),不阻塞 SPI ISR */
|
||||
if(s_bootRequestPending) {
|
||||
s_bootRequestPending = false;
|
||||
const bool ok = requestEnterBoot();
|
||||
if(ok) {
|
||||
s_rebootPending = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!s_rebootPending) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_rebootPending = false;
|
||||
|
||||
/* 方案A: 拉低 PB6 通知 ESP32 "即将复位"。
|
||||
* ESP32 通过 LOW→HIGH 序列识别 Bootloader 就绪:
|
||||
* APP 拉低 → 复位(μs级HIGH) → Bootloader极早拉低 → init完成释放HIGH
|
||||
* 20ms 延时确保 ESP32 5ms 轮询能捕获到 LOW 信号后再复位。 */
|
||||
gpio_bit_reset(CONFIG_SPI_READY_PORT, CONFIG_SPI_READY_PIN);
|
||||
|
||||
SysTickTimer::delayMs(kRebootDelayMs);
|
||||
__disable_irq();
|
||||
NVIC_SystemReset();
|
||||
|
||||
Reference in New Issue
Block a user