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:
cbb
2026-09-24 03:18:18 +08:00
parent 5fd986299c
commit 28d8426052
10 changed files with 272 additions and 5 deletions
@@ -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):