- 添加SPI OTA同步协议,使用新的帧格式包含信用控制和CRC32校验 - 实现BOOT主动按铃功能,通过SPI Ready线通知ESP32读取数据 - 添加按铃超时保护机制,防止死锁情况发生 - 优化SPI中断处理,统一在CS释放时处理帧避免RX溢出错误 - 修改GPIO配置为开漏输出模式,实现硬件握手信号 - 添加同步帧解析功能,支持帧头偏移扫描和完整性校验 - 实现信用控制机制,当flash缓冲区满时阻止ESP32继续发送数据 - 修复BOOT命令响应逻辑,确保一致性处理裸字节和帧式命令 - 将OTA完成验证移到主循环处理,避免SPI ready线阻塞过久 - 添加详细的调试日志输出便于问题排查 refactor(SpiOta): 重构SPI OTA协议栈 - 使用CRC32替代CRC8进行帧校验,提高数据完整性 - 重命名帧相关常量以匹配新的同步协议格式 - 移除旧的帧处理方法,采用新的同步帧解析流程 - 添加大小端转换辅助函数用于数据编码解码 - 优化内存布局减少RAM使用 - 统一错误处理流程,添加帧校验失败日志记录
123 lines
4.2 KiB
C++
123 lines
4.2 KiB
C++
#ifndef __SPI_OTA_H__
|
|
#define __SPI_OTA_H__
|
|
|
|
#include "OTA.h"
|
|
|
|
/**
|
|
* @file SpiOta.h
|
|
* @brief SPI OTA 从机协议头文件(ISR 直接响应版)。
|
|
*
|
|
* CS 释放后,EXTI ISR 直接完成帧校验+处理+响应准备,
|
|
* 响应帧在 ISR 中写入 s_txBuf,下次 CS 拉低时 DMA 自动发出。
|
|
* 无需 TBE 中断,DMA 硬件逐字节推到 MISO,消除字节错位问题。
|
|
*/
|
|
|
|
typedef enum {
|
|
SPI_OTA_CMD_REQ = 0x01,
|
|
SPI_OTA_CMD_DATA = 0x02,
|
|
SPI_OTA_CMD_CANCEL = 0x03,
|
|
SPI_OTA_CMD_BOOT = 0xB0,
|
|
SPI_OTA_RSP_ACK = 0x80,
|
|
SPI_OTA_RSP_WAIT = 0x81,
|
|
SPI_OTA_RSP_ERROR = 0x82
|
|
} spi_ota_frame_type_t;
|
|
|
|
class SpiOta {
|
|
public:
|
|
static constexpr u16 kRxBufSize = 256U;
|
|
static constexpr u16 kTxBufSize = 128U;
|
|
static constexpr u16 kIsrLogBufSize = 128U;
|
|
|
|
static void init();
|
|
static void poll();
|
|
static void setSender(OTAHandler *handler);
|
|
static void onCsAssert();
|
|
static void onCsRelease();
|
|
static void configureGpio();
|
|
static void configureSpi0();
|
|
static void configureDma();
|
|
static void configureExti();
|
|
static void onSpiInterrupt();
|
|
static void onCsExtiInterrupt();
|
|
static void feedRxBytes(const u8 *data, u16 len);
|
|
static bool hasTxFrame();
|
|
static bool hasActiveSession();
|
|
static u16 copyTxFrame(u8 *out, u16 max_len);
|
|
|
|
/** @brief BOOT 主动按铃:构建请求帧并拉低 SPIready,通知 ESP32 来读。
|
|
* @param[in] frame_type 请求帧类型。
|
|
* @param[in] payload 请求帧负载。
|
|
* @param[in] payload_len 负载长度。
|
|
* @return true 按铃成功,false 当前已有按铃未处理或帧构建失败。
|
|
* @note 与 DCU_APP AppSpiCommand::requestEsp32Read 对齐。
|
|
*/
|
|
static bool requestEsp32Read(u8 frame_type, const u8 *payload, u16 payload_len);
|
|
|
|
/** @brief 取消当前按铃请求,释放 SPIready。 */
|
|
static void cancelRing();
|
|
|
|
/** @brief 翻转 SPI Ready 握手引脚(PB6)电平。
|
|
* @param[in] ready true=就绪(HIGH), false=忙(LOW)。
|
|
* @note GPIO BSRR/BRR 写入原子,无需临界区;可由 ISR 与主循环共同调用。
|
|
* 与 DCU_APP AppSpiCommand::setSpiReady 行为一致,适配 ESP32 硬件握手。 */
|
|
static void setSpiReady(bool ready);
|
|
|
|
static void isrProcessFrame();
|
|
static void isrLogFrame(const char *tag, const u8 *data, u16 len);
|
|
|
|
static OTAHandler *s_otaHandler;
|
|
static volatile bool s_csActive;
|
|
static volatile u16 s_rxStreamLen;
|
|
static volatile u16 s_txStreamPos;
|
|
static u8 s_rxStream[kRxBufSize];
|
|
static u8 s_txBuf[kTxBufSize];
|
|
static volatile u16 s_txLen;
|
|
static volatile bool s_txPending;
|
|
static volatile bool s_isrResponded;
|
|
static volatile bool s_otaSessionActive;
|
|
static volatile bool s_ringPending; ///< 是否有未读走的主动按铃请求
|
|
static volatile u16 s_ringTxLen; ///< 按铃帧长度
|
|
static volatile u32 s_ringDeadline; ///< 按铃超时截止时间(ms)
|
|
|
|
static void sender(ota_link_tx_type_t type, u8 len, const u8 *data);
|
|
|
|
private:
|
|
static bool buildFrame(spi_ota_frame_type_t type, const u8 *payload, u16 payload_len,
|
|
u8 *out, u16 *out_len);
|
|
static bool tryParseFrame(const u8 *frame, u16 frame_len,
|
|
spi_ota_frame_type_t *type,
|
|
const u8 **payload,
|
|
u16 *payload_len);
|
|
static ota_link_msg_type_t mapMsgType(spi_ota_frame_type_t type);
|
|
static void queueTxFrame(const u8 *frame, u16 len);
|
|
static uint32_t enterCritical();
|
|
static void exitCritical(uint32_t primask);
|
|
};
|
|
|
|
/* OTA.cpp 通过此变量更新 SPI 响应帧的 CREDIT 字段 */
|
|
extern volatile u8 g_localCredit;
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
void spi_ota_init(void);
|
|
void spi_ota_poll(void);
|
|
void spi_ota_set_sender(OTAHandler *handler);
|
|
void spi_ota_on_cs_assert(void);
|
|
void spi_ota_on_cs_release(void);
|
|
void spi_ota_gpio_init(void);
|
|
void spi_ota_spi0_init(void);
|
|
void spi_ota_exti_init(void);
|
|
void spi_ota_irq_handler(void);
|
|
void spi_ota_cs_exti_handler(void);
|
|
void spi_ota_feed_rx_bytes(const u8 *data, u16 len);
|
|
bool spi_ota_has_tx_frame(void);
|
|
u16 spi_ota_copy_tx_frame(u8 *out, u16 max_len);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|