## 实施计划:DCU 初始化时通过 PC9 复位 ESP32 ### 背景确认 - 目标仓库:`G:/Robot_v2/DCU/DCU_APP/GD32E508_DCU_APP`(GD32 侧 DCU 固件)。 - PC9 当前在 DCU_APP 中未被使用,不会与 USART0/CAN/SPI/EXMC 等冲突。 - ESP32 EN/RESET 为低电平复位、高电平释放;你给出的 50ms 低电平保持后释放逻辑正确。 - 项目风格:配置集中在 `sys/config.h`,外设封装为 `device/*.h` 中的 C++ class,延迟统一用 `SysTickTimer::delayMs()`,GPIO 清 0 用 `gpio_bit_reset()`。 ### 修改点 #### 1. `sys/config.h`:增加 ESP32 复位引脚配置 在 SPI Ready 配置附近新增: ```cpp /** @brief ESP32 硬件复位控制端口(PC9 接 ESP32 EN/RESET)。 */ constexpr uint32_t CONFIG_ESP32_RESET_PORT = GPIOC; /** @brief ESP32 硬件复位控制引脚。 */ constexpr uint32_t CONFIG_ESP32_RESET_PIN = GPIO_PIN_9; /** @brief ESP32 复位低电平保持时间,单位 ms。 */ constexpr uint32_t CONFIG_ESP32_RESET_HOLD_MS = 50U; ``` #### 2. 新增 `device/esp32_reset.h` 按现有 `device/watchdog.h` 风格编写: ```cpp #ifndef DEVICE_ESP32_RESET_H #define DEVICE_ESP32_RESET_H #include class Esp32Reset { public: /** @brief 初始化 PC9 为推挽输出,先拉低 50ms 再释放 ESP32。 */ static void init(); /** @brief 主动拉低 ESP32 RESET(进入复位)。 */ static void assertReset(); /** @brief 释放 ESP32 RESET(高电平,ESP32 启动)。 */ static void releaseReset(); }; #endif /* DEVICE_ESP32_RESET_H */ ``` #### 3. 新增 `device/esp32_reset.cpp` 按现有 `device/watchdog.cpp` 风格编写: ```cpp #include "device/esp32_reset.h" #include "sys/config.h" #include "sys/systick.h" #include "main.h" void Esp32Reset::init() { /* 1. 使能 GPIOC 时钟 */ rcu_periph_clock_enable(RCU_GPIOC); /* 2. 先把输出数据寄存器清零,确保配置成输出时就是低电平 */ gpio_bit_reset(CONFIG_ESP32_RESET_PORT, CONFIG_ESP32_RESET_PIN); /* 3. 配置 PC9 为推挽输出 */ gpio_init(CONFIG_ESP32_RESET_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, CONFIG_ESP32_RESET_PIN); /* 4. 保持复位 50ms,等电源和其他 IO 稳定 */ SysTickTimer::delayMs(CONFIG_ESP32_RESET_HOLD_MS); /* 5. 释放 ESP32 */ gpio_bit_set(CONFIG_ESP32_RESET_PORT, CONFIG_ESP32_RESET_PIN); } void Esp32Reset::assertReset() { gpio_bit_reset(CONFIG_ESP32_RESET_PORT, CONFIG_ESP32_RESET_PIN); } void Esp32Reset::releaseReset() { gpio_bit_set(CONFIG_ESP32_RESET_PORT, CONFIG_ESP32_RESET_PIN); } ``` #### 4. `sys/initial.cpp`:在初始化序列中加入 ESP32 复位 - 新增 `#include "device/esp32_reset.h"`。 - 在 `SysTickTimer::initMs()` 之后、`Usart0::configurePins()` 之前调用 `Esp32Reset::init()`,原因: - 需要 SysTick 才能做 50ms 延迟; - 尽早释放 ESP32,让它在 DCU 继续初始化 USART/CAN/SPI 期间完成自身启动,等 SPI 命令总线初始化时 ESP32 已经可用。 修改后顺序: ```cpp nvic_priority_group_set(...); SysTickTimer::initMs(); Esp32Reset::init(); // 新增 Usart0::configurePins(); Usart0::init(); ... ``` #### 5. `GD32E508_DCU_APP.cproject.yml`:把新文件加入构建 在 `groups → device` 中增加: ```yaml - file: ./device/esp32_reset.h - file: ./device/esp32_reset.cpp ``` ### 代码适配说明 - 你原代码中的 `GPIO_BC(GPIOA) = GPIO_PIN_9` 等价于 `gpio_bit_reset(...)`,项目里统一用后一个 API。 - `delay_ms(50)` 替换为 `SysTickTimer::delayMs(CONFIG_ESP32_RESET_HOLD_MS)`,与项目中其他复位/ADC 稳定延迟一致。 - 端口从 `GPIOA/PA9` 改为 `GPIOC/PC9` 的 `CONFIG_*` 常量,便于后续硬件变更。 ### 验证 - 重新生成并编译 CMSIS csolution 工程(`cbuild DCU_APP.csolution.yml` 或 Keil Studio),确认新文件被编译、无重复定义、无未定义符号。 - 若编译失败,根据错误输出修正头文件包含或 cproject.yml 路径。 ### 风险/注意事项 - `Esp32Reset::init()` 调用时 SysTick 已就绪,因此 50ms 阻塞等待是安全的(此时中断已使能但尚未初始化其他外设)。 - 若后续需要在运行期再次复位 ESP32,可直接调用 `Esp32Reset::assertReset()` + `SysTickTimer::delayMs(...)` + `Esp32Reset::releaseReset()`。 - 本次修改不改变 PA9 的 USART0_TX 功能,调试串口保持正常。