feat(ethercat): 添加ESP32使能控制功能通过EtherCAT SDO
添加0x2503对象字典项用于通过EtherCAT SDO控制ESP32 WiFi使能信号, 解决WiFi关断后无法重新开启的问题。同时添加sys/esp32_en.h/.cpp文件 提供GPIO控制接口。 SPI诊断命令(0xA2)扩展支持ESP32 EN引脚控制,用于诊断备援。 ESP32掉电重启后自动清理SPI链路状态,防止通信异常。
This commit is contained in:
@@ -27,6 +27,8 @@ project:
|
||||
- file: ./sys/hardfault.cpp
|
||||
- file: ./sys/cpp_stubs.cpp
|
||||
- file: ./sys/config.h
|
||||
- file: ./sys/esp32_en.h
|
||||
- file: ./sys/esp32_en.cpp
|
||||
- group: device
|
||||
files:
|
||||
- file: ./device/adc.h
|
||||
|
||||
@@ -167,6 +167,10 @@ extern void EcatPdo_WriteInputs(UINT8 *esc);
|
||||
* 只置 pending 标志,真正的配置页写入 + 复位在主循环下一圈,见 ObjBootReqWrite 注。 */
|
||||
extern void EcatEnterBootRequestAsync(void);
|
||||
|
||||
/* 0x2503 用:ESP32 EN(PC9) 控制(sys/esp32_en.cpp 的 extern "C" shim)。
|
||||
* 经 EtherCAT SDO 下发,**不走 ESP32 WiFi**——WiFi 关断后主站仍能拉回使能。 */
|
||||
extern UINT8 EcatEsp32EnDrive(UINT8 action);
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
* PDO Assign 对象 (0x1C12 / 0x1C13)
|
||||
*---------------------------------------------------------------------------*/
|
||||
@@ -346,6 +350,47 @@ static UINT8 ObjBootReqWrite(UINT16 index, UINT8 subindex, UINT32 dataSize,
|
||||
return 0U;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
* 0x2503 ESP32 WiFi EN(PC9 / WLESS_EN)控制(主站 → APP)
|
||||
*
|
||||
* 为什么走 EtherCAT 而不是 SPI 0xA2 / WiFi HTTP:WiFi 使能被拉低后 ESP32
|
||||
* 当场掉线,经 /spi/send 的控制路径跟被控对象同生共死——关得掉、开不回来。
|
||||
* EtherCAT 主站在 PC 侧,与 ESP32 完全解耦,关断/开启都能下发。
|
||||
*
|
||||
* 语义(UINT32 bit[7:0]=action,与 sys/esp32_en.h Esp32En::drive 对齐):
|
||||
* 0=拉高(开) 1=拉低保持(关) 2=拉高 3=浮空 4=只读
|
||||
* 读回:bit[7:0] = 实际引脚电平 0/1(0xEE=无效 action)。
|
||||
*---------------------------------------------------------------------------*/
|
||||
OBJCONST TSDOINFOENTRYDESC OBJMEM sEntryDesc0x2503[] = {
|
||||
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READWRITE},
|
||||
};
|
||||
static OBJCONST UCHAR aName0x2503[] = "ESP32 WiFi EN";
|
||||
|
||||
static UINT32 s_esp32EnVal = 1U; /**< 读回缓存:默认 1=上电已释放 EN */
|
||||
|
||||
static UINT8 ObjEsp32EnWrite(UINT16 index, UINT8 subindex, UINT32 dataSize,
|
||||
UINT16 MBXMEM *pData, UINT8 bCompleteAccess)
|
||||
{
|
||||
const UINT8 *p8 = (const UINT8 *)pData;
|
||||
UINT32 v;
|
||||
UINT8 action, st;
|
||||
|
||||
(void)index;
|
||||
(void)bCompleteAccess;
|
||||
|
||||
if (subindex != 0U) {
|
||||
return ABORTIDX_SUBINDEX_NOT_EXISTING;
|
||||
}
|
||||
if (pData == NULL || dataSize < 4U) {
|
||||
return ABORTIDX_PARAM_LENGTH_TOO_SHORT;
|
||||
}
|
||||
v = (UINT32)p8[0] | ((UINT32)p8[1] << 8) | ((UINT32)p8[2] << 16) | ((UINT32)p8[3] << 24);
|
||||
action = (UINT8)(v & 0xFFU);
|
||||
st = EcatEsp32EnDrive(action);
|
||||
s_esp32EnVal = (UINT32)st;
|
||||
return 0U;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
* Object Names
|
||||
*---------------------------------------------------------------------------*/
|
||||
@@ -395,6 +440,10 @@ TOBJECT OBJMEM ApplicationObjDicList[] = {
|
||||
{NULL, NULL, 0x2502, {DEFTYPE_UNSIGNED32, 0 | (OBJCODE_VAR << 8)},
|
||||
sEntryDesc0x2502, aName0x2502, &s_bootReq, NULL, ObjBootReqWrite, 0x0000},
|
||||
|
||||
/* 0x2503: ESP32 WiFi EN(PC9) —— 经 EtherCAT 控制,WiFi 关断后仍可拉回 */
|
||||
{NULL, NULL, 0x2503, {DEFTYPE_UNSIGNED32, 0 | (OBJCODE_VAR << 8)},
|
||||
sEntryDesc0x2503, aName0x2503, &s_esp32EnVal, NULL, ObjEsp32EnWrite, 0x0000},
|
||||
|
||||
/* 终止条目 */
|
||||
{NULL, NULL, 0xFFFF, {0, 0}, NULL, NULL, NULL, NULL, NULL, 0x000}
|
||||
};
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
/**
|
||||
* @file app_spi_cmd_exmc_diag.cpp
|
||||
* @brief SPI 0xA2 EXMC/HBI 诊断命令处理器:驱动 LAN9252 通断测试 pattern / NRST 手动诊断 / 电源管理。
|
||||
* @brief SPI 0xA2 EXMC/HBI 诊断命令处理器:驱动 LAN9252 通断测试 pattern / NRST 手动诊断 / 电源管理 / ESP32 EN。
|
||||
*
|
||||
* 网页按钮 → ESP32 /spi/send → SPI 0xA2 → 本 handler → 分流:
|
||||
* action 0~10 → EscExmcBus::continuityDrive() (EXMC 数据/控制线 pattern)
|
||||
* action 20~24 → EscLan9252::nrstDrive() (ECAT_NRST/PB10 拉低/拉高/浮空/回读)
|
||||
* action 30~34 → EscLan9252::pmDrive() (电源管理:读状态/进D1/D2/D3/手动唤醒)
|
||||
* action 40~44 → Esp32En::drive() (ESP32 EN/PC9 诊断备援;开关请走 EtherCAT 0x2503)
|
||||
* 立即返回 ACK,不阻塞 SPI 总线。电平保持到下次调用或 action=0(stop)。
|
||||
* NRST action 返回的 status 字节 = 实际引脚电平(0/1),非 OK 码。
|
||||
* NRST/ESP32_EN action 返回的 status 字节 = 实际引脚电平(0/1),非 OK 码。
|
||||
* PM action 返回的 status 字节 = bit0=READY bit1=PM_SLEEP_EN bit3:2=PM_MODE;
|
||||
* 唤醒(34)另有 1=成功 0=超时;0xEE=无效 action,0xE1=HBI 未就绪。
|
||||
*/
|
||||
@@ -16,6 +17,7 @@
|
||||
#include "device/spi/app_spi_command_defs.h"
|
||||
#include "comm/esc_exmc_bus.h"
|
||||
#include "comm/esc_lan9252.h"
|
||||
#include "sys/esp32_en.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -32,7 +34,9 @@ public:
|
||||
uint8_t status = 0xEE;
|
||||
if (ctx.payload_len >= 1) {
|
||||
const uint8_t action = ctx.payload[0];
|
||||
if (action >= 30U) {
|
||||
if (action >= 40U) {
|
||||
status = Esp32En::drive(action - 40U);
|
||||
} else if (action >= 30U) {
|
||||
status = EscLan9252::pmDrive(action - 30U);
|
||||
} else if (action >= 20U) {
|
||||
status = EscLan9252::nrstDrive(action - 20U);
|
||||
|
||||
@@ -38,6 +38,7 @@ extern "C" {
|
||||
#include "sys/critical.h"
|
||||
#include "sys/systick.h"
|
||||
#include "sys/cpu_load.h"
|
||||
#include "sys/esp32_en.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
@@ -558,6 +559,8 @@ void AppSpiCommand::processCommand()
|
||||
g_pendingAckSeq = hdr.tx_seq;
|
||||
|
||||
if (frame_type == V2_TYPE_LINK_HELLO) {
|
||||
/* 合法 HELLO 已到:停掉起机补清,避免 reset 打断建连 */
|
||||
Esp32En::cancelRelinkFromSpi();
|
||||
g_sessionId = hdr.session_id;
|
||||
g_txSeq = 0;
|
||||
g_expectedRxSeq = 0;
|
||||
@@ -693,6 +696,41 @@ void AppSpiCommand::cancelRing()
|
||||
updateDataReady();
|
||||
}
|
||||
|
||||
void AppSpiCommand::resetEsp32Link()
|
||||
{
|
||||
/* ESP32 被 PC9 掉电可能死在半笔 CS 里,SPI0/DMA/EXTI 都可能卡死。
|
||||
* 做一次完整外设重初始化(对齐 init 的硬件序列),而不是只清软件状态。
|
||||
* 仅在 PC9 翻转、对端确定不在发帧时调用。 */
|
||||
nvic_irq_disable(EXTI10_15_IRQn);
|
||||
exti_interrupt_disable(EXTI_15);
|
||||
|
||||
g_v2Active = false;
|
||||
g_sessionId = 0U;
|
||||
g_txSeq = 0U;
|
||||
g_expectedRxSeq = 0U;
|
||||
g_pendingAckSeq = 0U;
|
||||
g_localCredit = 1U;
|
||||
s_lastReqSeq = 0xFFU;
|
||||
s_lastRespLen = 0U;
|
||||
s_hasCachedResp = false;
|
||||
|
||||
m_csActive = false;
|
||||
m_rxLen = 0U;
|
||||
m_ringPending = false;
|
||||
m_ringDeadline = 0U;
|
||||
m_txLen = 0U;
|
||||
memset(m_txBuf, 0xFF, sizeof(m_txBuf));
|
||||
memset(m_rxBuf, 0x00, sizeof(m_rxBuf));
|
||||
|
||||
/* 硬件重初始化:SPI0 + DMA + CS EXTI(与 init() 同序列) */
|
||||
configureDma();
|
||||
configureSpi0();
|
||||
armSpiDmasForNextCs();
|
||||
updateDataReady();
|
||||
configureExti();
|
||||
printf("[SPI-APP] resetEsp32Link: SPI0/DMA/EXTI re-init done\r\n");
|
||||
}
|
||||
|
||||
bool AppSpiCommand::requestEsp32Read(uint8_t frame_type, const uint8_t *payload, uint16_t payload_len)
|
||||
{
|
||||
/* 若上一次按铃尚未被 ESP32 读走,拒绝重复按铃 */
|
||||
@@ -789,6 +827,9 @@ void AppSpiCommand::onCsRelease()
|
||||
}
|
||||
if (m_rxLen >= V2_OVERHEAD) {
|
||||
processCommand();
|
||||
} else {
|
||||
/* 残包:SPI 可能已乱,重配外设 */
|
||||
configureSpi0();
|
||||
}
|
||||
armSpiDmasForNextCs();
|
||||
updateDataReady();
|
||||
@@ -843,7 +884,9 @@ void AppSpiCommand::onCsRelease()
|
||||
|
||||
if (shouldIgnoreTransaction(m_rxBuf, m_rxLen)) {
|
||||
m_rxLen = 0U;
|
||||
/* v2 DATA_READY: 无待处理帧时 updateDataReady() 释放 PB6。 */
|
||||
/* 起机毛刺/相位漂移后仅 re-arm DMA 不够:SPI0 可能已 OVR 卡死。
|
||||
* 顺手重配 SPI0+DMA(不动 EXTI/session),下一笔 HELLO 才能收进来。 */
|
||||
configureSpi0();
|
||||
armSpiDmasForNextCs();
|
||||
updateDataReady();
|
||||
return;
|
||||
|
||||
@@ -89,6 +89,15 @@ public:
|
||||
* 0xB0 进 BOOT 等路径需公开调用,避免 0xC1 残留盖住 ACK。 */
|
||||
void cancelRing();
|
||||
|
||||
/**
|
||||
* @brief ESP32 掉电/重上电后复位 SPI 链路(PC9 翻转时调用)。
|
||||
*
|
||||
* ESP32 被 EN 拉低时可能死在半笔 CS 事务里:session/序号/按铃/DMA 都会脏。
|
||||
* 重上电 HELLO 前必须清干净,否则首帧对不齐 → 永远建不起 v2 会话。
|
||||
* 清 session(HELLO 会重建)、取消按铃、re-arm DMA、释放 DATA_READY。
|
||||
*/
|
||||
void resetEsp32Link();
|
||||
|
||||
static constexpr uint16_t kRxBufSize = CONFIG_SPI_RX_BUF_SIZE;
|
||||
static constexpr uint16_t kTxBufSize = CONFIG_SPI_TX_BUF_SIZE;
|
||||
static constexpr uint16_t kLogBufSize = CONFIG_SPI_LOG_BUF_SIZE;
|
||||
|
||||
@@ -21,7 +21,10 @@ static constexpr uint8_t kTypeOtaCancel = 0x03U;
|
||||
static constexpr uint8_t kTypeAppPing = 0xA1U;
|
||||
/** @brief EXMC/HBI 诊断命令(ESP32→GD32):payload[0]=action。
|
||||
* 0=stop(恢复AF_PP), 1-4=数据pattern(0xFFFF/0x0000/0xAAAA/0x5555),
|
||||
* 5=CS低, 6=RD低, 7=WR低, 8=A1高, 9=A2高。用于 LAN9252 通断测试。 */
|
||||
* 5=CS低, 6=RD低, 7=WR低, 8=A1高, 9=A2高。用于 LAN9252 通断测试。
|
||||
* 20~24=ECAT_NRST(PB10) 30~34=LAN9252 电源管理
|
||||
* 40~44=ESP32 EN(PC9):40/42=拉高 41=拉低保持 43=浮空 44=回读
|
||||
* (运行期开关请走 EtherCAT SDO 0x2503,本组仅 SPI 诊断备援) */
|
||||
static constexpr uint8_t kTypeExmcDiag = 0xA2U;
|
||||
/** @brief APP 初始化状态查询(ESP32→GD32,1.5.34 新增):无 payload。
|
||||
* 响应 ACK 25B(1.5.35 起;1.5.34 仅前 12B):
|
||||
|
||||
@@ -214,6 +214,8 @@ constexpr uint32_t CONFIG_SPI_RING_TIMEOUT_MS = 50U;
|
||||
* registerHandler 表满时静默丢弃,motor_ota 曾因容量=8 被丢弃(0xD0 回 0xEE)。
|
||||
* 取 14 留余量;新增 handler 时须确认本容量足够。 */
|
||||
constexpr uint8_t CONFIG_SPI_MAX_COMMANDS = 14U;
|
||||
/** @brief GD32 APP 版本(HELLO_ACK/PING 身份块;改功能后请递增便于现场核对)。 */
|
||||
/* 版本号在 app_spi_cmd_ping.cpp fillGd32AppIdentityPayload 维护 */
|
||||
/** @brief 每通道不重复 ID 快照表最大条目数(与 ESP32 CANFD_ID_SNAPSHOT_MAX 对齐)。 */
|
||||
constexpr uint8_t CONFIG_CANFD_ID_SNAPSHOT_MAX = 16U;
|
||||
/** @brief 快照条目最大数据字节数(CAN FD DLC 上限)。 */
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @file esp32_en.cpp
|
||||
* @brief ESP32 EN (PC9) 驱动。PC9 拉高后延时 1.2s 复位 SPI,避开起机毛刺。
|
||||
*/
|
||||
#include "sys/esp32_en.h"
|
||||
#include "sys/config.h"
|
||||
#include "sys/task_manager.h"
|
||||
#include "device/spi/app_spi_command.h"
|
||||
#include <stdio.h>
|
||||
|
||||
namespace {
|
||||
|
||||
/** @brief PC9 拉高后延时多久再清 SPI(等 ESP32 ROM/APP 引脚初始化毛刺结束)。 */
|
||||
constexpr uint32_t kPostBootRelinkDelayMs = 1200U;
|
||||
|
||||
/** @brief 延时复位排期;0=无。 */
|
||||
volatile uint32_t s_relinkAtMs = 0U;
|
||||
|
||||
void drivePinLow()
|
||||
{
|
||||
gpio_init(CONFIG_ESP32_RESET_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,
|
||||
CONFIG_ESP32_RESET_PIN);
|
||||
gpio_bit_reset(CONFIG_ESP32_RESET_PORT, CONFIG_ESP32_RESET_PIN);
|
||||
}
|
||||
|
||||
void drivePinHigh()
|
||||
{
|
||||
gpio_init(CONFIG_ESP32_RESET_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,
|
||||
CONFIG_ESP32_RESET_PIN);
|
||||
gpio_bit_set(CONFIG_ESP32_RESET_PORT, CONFIG_ESP32_RESET_PIN);
|
||||
}
|
||||
|
||||
void floatPin()
|
||||
{
|
||||
gpio_init(CONFIG_ESP32_RESET_PORT, GPIO_MODE_IN_FLOATING, 0,
|
||||
CONFIG_ESP32_RESET_PIN);
|
||||
}
|
||||
|
||||
bool readPin()
|
||||
{
|
||||
return gpio_input_bit_get(CONFIG_ESP32_RESET_PORT, CONFIG_ESP32_RESET_PIN) == SET;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
uint8_t Esp32En::drive(uint8_t action)
|
||||
{
|
||||
switch (action) {
|
||||
case 0: /* 拉高(开 WiFi) */
|
||||
case 2:
|
||||
/* ESP32 仍死着:先清一次 SPI;起机毛刺会在 1.2s 后再清一次 */
|
||||
s_relinkAtMs = 0U;
|
||||
AppSpiCommandBus.resetEsp32Link();
|
||||
drivePinHigh();
|
||||
s_relinkAtMs = TaskManager::state().tick_1ms + kPostBootRelinkDelayMs;
|
||||
break;
|
||||
case 1: /* 拉低保持(关 WiFi) */
|
||||
s_relinkAtMs = 0U;
|
||||
drivePinLow();
|
||||
AppSpiCommandBus.resetEsp32Link();
|
||||
break;
|
||||
case 3: /* 浮空 */
|
||||
s_relinkAtMs = 0U;
|
||||
floatPin();
|
||||
AppSpiCommandBus.resetEsp32Link();
|
||||
break;
|
||||
case 4: /* 只读 */
|
||||
break;
|
||||
case 5: /* 仅复位 SPI(诊断;ESP32 空闲时调用,再让它 HELLO) */
|
||||
s_relinkAtMs = 0U;
|
||||
AppSpiCommandBus.resetEsp32Link();
|
||||
break;
|
||||
default:
|
||||
return 0xEEU;
|
||||
}
|
||||
|
||||
const bool level = readPin();
|
||||
static const char *const kName[6] = {
|
||||
"restore HIGH", "drive LOW (hold)", "drive HIGH", "float", "read-only", "spi-relink"};
|
||||
printf("[APP][ESP32_EN] %s -> pin reads %s\r\n", kName[action],
|
||||
level ? "HIGH" : "LOW");
|
||||
return level ? 1U : 0U;
|
||||
}
|
||||
|
||||
void Esp32En::poll()
|
||||
{
|
||||
if (s_relinkAtMs == 0U) {
|
||||
return;
|
||||
}
|
||||
const uint32_t now = TaskManager::state().tick_1ms;
|
||||
if ((int32_t)(now - s_relinkAtMs) < 0) {
|
||||
return;
|
||||
}
|
||||
s_relinkAtMs = 0U;
|
||||
AppSpiCommandBus.resetEsp32Link();
|
||||
printf("[APP][ESP32_EN] post-boot SPI relink (glitch window over)\r\n");
|
||||
}
|
||||
|
||||
void Esp32En::cancelRelinkFromSpi()
|
||||
{
|
||||
/* HELLO/业务帧已进来:不必再延时复位(会打断建连) */
|
||||
s_relinkAtMs = 0U;
|
||||
}
|
||||
|
||||
/* EtherCAT SDO 0x2503 回调入口(dc_app.c 为 C 侧)。 */
|
||||
extern "C" uint8_t EcatEsp32EnDrive(uint8_t action)
|
||||
{
|
||||
return Esp32En::drive(action);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file esp32_en.h
|
||||
* @brief ESP32 EN/RESET (PC9 / WLESS_EN) 手动控制 —— 网页开关经 EtherCAT SDO 0x2503 下发。
|
||||
*
|
||||
* 硬件语义(见 sys/config.h CONFIG_ESP32_RESET_*):
|
||||
* - PC9 推挽高 = 释放 ESP_CHIP_EN,ESP32 运行、WiFi 可用
|
||||
* - PC9 推挽低 = 按死 EN,ESP32 硬复位/掉使能,WiFi 与 HTTP 全断
|
||||
* - PC9 浮空 = 外部 C41/U11 把 ESP_CHIP_EN 拉低,同样关断(与复位后一致)
|
||||
*
|
||||
* 控制必须走 EtherCAT(与 ESP32 解耦):WiFi 关断后 ESP32 已死,
|
||||
* 经 /spi/send 的路径关得掉、开不回来。
|
||||
* 恢复:再次 SDO 写 action 0/2 拉高;或 GD32 复位/重新上电(initial.cpp 无条件拉高)。
|
||||
*
|
||||
* SPI 重建:ESP32 冷启动的 GPIO 毛刺会再次弄脏 SPI 链路,故拉高 PC9 后
|
||||
* 在起机窗口内多次 resetEsp32Link(),赶在 HELLO 前把 session/DMA 清干净。
|
||||
*/
|
||||
#ifndef SYS_ESP32_EN_H
|
||||
#define SYS_ESP32_EN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class Esp32En {
|
||||
public:
|
||||
/**
|
||||
* @brief 驱动/回读 ESP32 EN(PC9)。EtherCAT SDO 0x2503 转发到此。
|
||||
* @param action 0=拉高(开) 1=拉低保持(关) 2=拉高 3=浮空 4=只读 5=仅复位 SPI
|
||||
* @return 实际引脚电平 0/1(与 nrstDrive 同口径);0xEE=无效 action。
|
||||
*/
|
||||
static uint8_t drive(uint8_t action);
|
||||
|
||||
/**
|
||||
* @brief 起机窗口内补清 SPI 链路(TaskRunner::runPending 每圈调用)。
|
||||
* @note 无排期时立即返回。PC9 拉高后早期少量补清;一旦收到 CS 事务即停,
|
||||
* 避免打断正在建连的 HELLO。
|
||||
*/
|
||||
static void poll();
|
||||
|
||||
/** @brief SPI 收到任意 CS 事务时取消剩余补清(由 processCommand 调用)。 */
|
||||
static void cancelRelinkFromSpi();
|
||||
};
|
||||
|
||||
#endif /* SYS_ESP32_EN_H */
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "sys/motor_ota_relay.h"
|
||||
#include "sys/task_manager.h"
|
||||
#include "sys/cpu_load.h"
|
||||
#include "sys/esp32_en.h"
|
||||
#include "sys/task_runner.h"
|
||||
#include "comm/ethercat_slave.h"
|
||||
#include "comm/ethercat_sync.h"
|
||||
@@ -575,6 +576,9 @@ void TaskRunner::runPending()
|
||||
* 主动推送已随 2026-08 请求驱动改造移除,此处仅需消费请求响应的按铃。 */
|
||||
AppSpiCommandBus.poll();
|
||||
|
||||
/* PC9 拉高后 ESP32 起机窗口内的 SPI 补清(GPIO 毛刺会弄脏链路)。 */
|
||||
Esp32En::poll();
|
||||
|
||||
/* 0xB0 进 BOOT:必须每圈检查,不能只靠 1Hz TASK_HEARTBEAT。
|
||||
* 否则 Flash 写/复位被拖到下一秒,ESP32 HELLO 一直 role=app 超时。 */
|
||||
if (OtaBootRequest::isRebootPending()) {
|
||||
|
||||
Reference in New Issue
Block a user