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:
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user