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:
@@ -90,6 +90,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;
|
||||
volatile bool OtaBootRequest::s_spiFrozenForBoot = false;
|
||||
|
||||
/**
|
||||
* @brief 初始化进入 Bootloader 请求模块的运行态。
|
||||
@@ -98,6 +99,7 @@ void OtaBootRequest::init()
|
||||
{
|
||||
s_rebootPending = false;
|
||||
s_bootRequestPending = false;
|
||||
s_spiFrozenForBoot = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,6 +117,9 @@ bool OtaBootRequest::requestEnterBoot()
|
||||
|
||||
if(ok) {
|
||||
s_rebootPending = true;
|
||||
} else {
|
||||
/* 写配置页失败则永远停在 APP,ESP32 会看到持续 role=1 */
|
||||
/* 无 printf 依赖:由调用方 process() 恢复 SPI 后继续运行 */
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@@ -127,6 +132,9 @@ bool OtaBootRequest::requestEnterBoot()
|
||||
void OtaBootRequest::requestEnterBootAsync()
|
||||
{
|
||||
s_bootRequestPending = true;
|
||||
/* 立即冻结 SPI 业务:不必等 process()(原依赖 1Hz 心跳,最坏拖 ~1s)。
|
||||
* 否则 ESP32 紧跟着 HELLO/0xC1 会继续进 processCommand,干扰擦页/复位。 */
|
||||
s_spiFrozenForBoot = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,13 +165,25 @@ bool OtaBootRequest::handleCanFrame(uint8_t channel, uint32_t id, const uint8_t
|
||||
*/
|
||||
void OtaBootRequest::process()
|
||||
{
|
||||
/* 异步处理 0xB0 请求:在主循环执行 Flash 操作(20-30ms),不阻塞 SPI ISR */
|
||||
/* 异步处理 0xB0:主循环写 Flash(可能擦页 20–30ms)。
|
||||
* 期间冻结 SPI 业务处理,避免 ESP32 紧跟着 HELLO/按铃读 打断擦写。 */
|
||||
if(s_bootRequestPending) {
|
||||
s_bootRequestPending = false;
|
||||
s_spiFrozenForBoot = true;
|
||||
nvic_irq_disable(SPI0_IRQn);
|
||||
nvic_irq_disable(EXTI10_15_IRQn);
|
||||
nvic_irq_disable(EXTI5_9_IRQn);
|
||||
|
||||
const bool ok = requestEnterBoot();
|
||||
if(ok) {
|
||||
s_rebootPending = true;
|
||||
if(!ok) {
|
||||
s_spiFrozenForBoot = false;
|
||||
nvic_irq_enable(SPI0_IRQn, 2U, 0U);
|
||||
nvic_irq_enable(EXTI10_15_IRQn, 1U, 1U);
|
||||
nvic_irq_enable(EXTI5_9_IRQn, CONFIG_IRQ_PREEMPT_SPI_USART, 1U);
|
||||
/* requestEnterBoot 失败时 s_rebootPending 仍为 false */
|
||||
return;
|
||||
}
|
||||
s_rebootPending = true;
|
||||
}
|
||||
|
||||
if(!s_rebootPending) {
|
||||
@@ -171,13 +191,14 @@ void OtaBootRequest::process()
|
||||
}
|
||||
|
||||
s_rebootPending = false;
|
||||
s_spiFrozenForBoot = true;
|
||||
nvic_irq_disable(SPI0_IRQn);
|
||||
nvic_irq_disable(EXTI10_15_IRQn);
|
||||
nvic_irq_disable(EXTI5_9_IRQn);
|
||||
|
||||
/* 方案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);
|
||||
|
||||
/* v2 DATA_READY: Boot 切换不再用 PB6 通知对端,
|
||||
* BOOT 起机后再由 HELLO role=boot 确认。 */
|
||||
/* SysTick 中断仍开,delayMs 可用;SPI 相关 IRQ 已关。 */
|
||||
SysTickTimer::delayMs(kRebootDelayMs);
|
||||
__disable_irq();
|
||||
NVIC_SystemReset();
|
||||
|
||||
@@ -42,13 +42,18 @@ public:
|
||||
/** @brief 若已确认进入 BOOT 请求,则延迟片刻后复位。 */
|
||||
static void process();
|
||||
|
||||
/** @brief 查询是否已收到进入 Bootloader 请求(等待复位中)。
|
||||
* 供主循环在复位前停止主动按铃等可能干扰 OTA 的操作。 */
|
||||
static bool isRebootPending() { return s_rebootPending; }
|
||||
/** @brief 查询是否已进入“即将进 BOOT”路径(异步 pending 或已写标志待复位)。
|
||||
* 供 CAN 按铃等模块在复位前停止干扰 SPI 的操作。 */
|
||||
static bool isRebootPending() { return s_rebootPending || s_bootRequestPending; }
|
||||
|
||||
/** @brief SPI 命令路径查询:true 时忽略业务帧,仅释放 ready。 */
|
||||
static bool isSpiFrozenForBoot() { return s_spiFrozenForBoot; }
|
||||
|
||||
private:
|
||||
static volatile bool s_rebootPending;
|
||||
static volatile bool s_bootRequestPending; ///< 0xB0 异步请求标志,process() 中执行 Flash 操作
|
||||
/** 写 OTA 配置页期间冻结 SPI 业务,避免 Flash 擦写与 SPI ISR 互踩。 */
|
||||
static volatile bool s_spiFrozenForBoot;
|
||||
};
|
||||
|
||||
#endif /* SYS_OTA_BOOT_REQUEST_H */
|
||||
|
||||
@@ -367,6 +367,12 @@ void TaskRunner::runPending()
|
||||
* 放在 canFeedbackPushStep() 前确保卡死的按铃先被清掉再推送下一帧。 */
|
||||
AppSpiCommandBus.poll();
|
||||
|
||||
/* 0xB0 进 BOOT:必须每圈检查,不能只靠 1Hz TASK_HEARTBEAT。
|
||||
* 否则 Flash 写/复位被拖到下一秒,ESP32 HELLO 一直 role=app 超时。 */
|
||||
if (OtaBootRequest::isRebootPending()) {
|
||||
OtaBootRequest::process();
|
||||
}
|
||||
|
||||
/* CAN 反馈主动推送:GD32 APP 循环推送 3 通道 × 2 页反馈帧到 ESP32,
|
||||
* 替代 ESP32 主动轮询。非阻塞:上一帧未读走时立即返回。
|
||||
* 每次主循环迭代调用一次,ESP32 读走一帧后 CS 释放中断唤醒主循环继续推送。 */
|
||||
|
||||
Reference in New Issue
Block a user