feat(SpiOta): 添加SPI OTA协议硬件握手功能
- 添加对BOOT实际支持的OTA协议帧(REQ/DATA/CANCEL)的过滤, 对不支持的帧类型(如CAN bridge命令)返回ERROR响应,避免误处理 - 实现SPI Ready硬件握手功能,复用PB6引脚作为SPI Ready信号输出, CS下降沿拉低表示从机忙碌,响应完成后拉高表示就绪 - 新增setSpiReady接口用于控制SPI Ready引脚状态, 确保与DCU_APP行为一致,适配ESP32的硬件握手时序 - 修复因未知帧类型被误认为CANCEL而导致OTA状态机被频繁重置的问题 ```
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#include "SpiOta.h"
|
||||
#include "SpiOta.h"
|
||||
#include "core_cm33.h"
|
||||
#include "gd32e50x_gpio.h"
|
||||
#include "gd32e50x_exti.h"
|
||||
@@ -237,6 +237,26 @@ void SpiOta::isrProcessFrame() {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 仅转发 BOOT 实际支持的 OTA 协议帧(REQ/DATA/CANCEL)给 OTA 状态机。
|
||||
* 其它帧类型(如 0xC0~0xC3 CAN bridge 命令,由 DCU_APP 注册处理器处理,
|
||||
* BOOT 无此功能)直接返回 ERROR,避免 mapMsgType 的 default 分支把
|
||||
* 未知类型误当成 CANCEL,导致 ESP32 待机时 1Hz CAN 反馈轮询(0xC1)
|
||||
* 不断重置 OTA 状态机,干扰正常 OTA 握手。 */
|
||||
if (frame_type != SPI_OTA_CMD_REQ &&
|
||||
frame_type != SPI_OTA_CMD_DATA &&
|
||||
frame_type != SPI_OTA_CMD_CANCEL) {
|
||||
u8 err = 0xEEU;
|
||||
u8 err_frame[kTxBufSize] = {};
|
||||
u16 built = 0U;
|
||||
if (buildFrame(SPI_OTA_RSP_ERROR, &err, 1U, err_frame, &built)) {
|
||||
queueTxFrame(err_frame, built);
|
||||
}
|
||||
isrLogFrameEx("[UNK-TYPE]", s_rxStream, (rx_len < 8U) ? rx_len : 8U);
|
||||
s_rxStreamLen = 0U;
|
||||
s_isrResponded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_otaHandler != nullptr) {
|
||||
s_otaSessionActive = true;
|
||||
s_otaHandler->setTransportSender(sender);
|
||||
@@ -286,8 +306,21 @@ void SpiOta::configureGpio() {
|
||||
gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE);
|
||||
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_3 | GPIO_PIN_5);
|
||||
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
|
||||
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
|
||||
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
|
||||
gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
|
||||
/* PB6 复用为 SPI Ready 握手输出,默认 HIGH(就绪),允许主机立刻发起首帧。
|
||||
* 与 DCU_APP app_spi_command.cpp configureGpio 行为一致,
|
||||
* 适配 ESP32 GPIO10 输入监测 PB6 电平的硬件握手时序。 */
|
||||
gpio_init(CONFIG_SPI_READY_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, CONFIG_SPI_READY_PIN);
|
||||
gpio_bit_set(CONFIG_SPI_READY_PORT, CONFIG_SPI_READY_PIN);
|
||||
}
|
||||
|
||||
void SpiOta::setSpiReady(bool ready) {
|
||||
if (ready) {
|
||||
gpio_bit_set(CONFIG_SPI_READY_PORT, CONFIG_SPI_READY_PIN);
|
||||
} else {
|
||||
gpio_bit_reset(CONFIG_SPI_READY_PORT, CONFIG_SPI_READY_PIN);
|
||||
}
|
||||
}
|
||||
|
||||
void SpiOta::configureSpi0() {
|
||||
@@ -386,6 +419,11 @@ void SpiOta::init() {
|
||||
void SpiOta::onCsAssert() {
|
||||
if (s_csActive) { return; }
|
||||
s_csActive = true;
|
||||
/* CS 下降沿立即拉低 PB6:表示从机即将忙碌,
|
||||
* 防止主机在 onCsRelease 准备好响应前抢跑发起下一笔 CS。
|
||||
* (若此帧为空轮询/残包,onCsRelease 会恢复 HIGH)
|
||||
* 与 DCU_APP AppSpiCommand::onCsAssert 行为一致。 */
|
||||
setSpiReady(false);
|
||||
s_rxStreamLen = 0U;
|
||||
s_txStreamPos = 0U;
|
||||
s_isrResponded = false;
|
||||
@@ -442,6 +480,12 @@ void SpiOta::onCsRelease() {
|
||||
if (s_rxStreamLen > 0U && !s_isrResponded) {
|
||||
isrProcessFrame();
|
||||
}
|
||||
|
||||
/* BOOT 在 ISR 内同步完成帧处理,响应帧已就绪(或为空轮询/残包无需响应),
|
||||
* 拉高 PB6 通知主机可发起下一笔事务。
|
||||
* 与 DCU_APP processCommand() 末尾 setSpiReady(true) 行为一致;
|
||||
* 空轮询事务同样恢复 HIGH,避免 PB6 卡 LOW 导致 ESP32 waitSpiReady 超时。 */
|
||||
setSpiReady(true);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
|
||||
@@ -46,6 +46,12 @@ public:
|
||||
static bool hasActiveSession();
|
||||
static u16 copyTxFrame(u8 *out, u16 max_len);
|
||||
|
||||
/** @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 tryProcessCompleteFrame();
|
||||
static void isrLogFrame(const char *tag, const u8 *data, u16 len);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifndef __CONFIG_H__
|
||||
#ifndef __CONFIG_H__
|
||||
#define __CONFIG_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "gd32e50x.h"
|
||||
|
||||
/** 项目内部统一使用的简写类型。 */
|
||||
typedef uint8_t u8;
|
||||
@@ -77,6 +78,15 @@ inline constexpr u32 CANFD_OTA_ACK_ID = 0x00000102U;
|
||||
inline constexpr u32 CANFD_OTA_WAIT_ID = 0x00000103U;
|
||||
inline constexpr u32 CANFD_OTA_CANCEL_ID = 0x00000000U;
|
||||
|
||||
/**
|
||||
* SPI Ready 握手输出引脚(PB6 复用为 SPI Ready)。
|
||||
* 与 DCU_APP sys/config.h 保持一致,适配 ESP32 waitSpiReady 硬件握手:
|
||||
* - CS 下降沿拉低 PB6,表示从机忙碌
|
||||
* - 响应帧就绪后拉高 PB6,通知主机可发起下一笔事务
|
||||
*/
|
||||
inline constexpr u32 CONFIG_SPI_READY_PORT = GPIOB;
|
||||
inline constexpr u32 CONFIG_SPI_READY_PIN = GPIO_PIN_6;
|
||||
|
||||
/** GD32E50x 芯片 UID 三段地址。 */
|
||||
inline constexpr u32 DEVICE_SERIAL_ADDR_LSB = 0x1FFFF7E8U;
|
||||
inline constexpr u32 DEVICE_SERIAL_ADDR_MID = 0x1FFFF7ECU;
|
||||
|
||||
Reference in New Issue
Block a user