/** * @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 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); }