From 0b2eebe76d9a72e7b8cb46e4daa74c56f610baa5 Mon Sep 17 00:00:00 2001 From: wang Date: Thu, 7 May 2026 17:24:10 +0800 Subject: [PATCH] Add initial board, HAL, and executor modules --- main/02_physical/boards/board_sweekar.h | 25 + .../boards/board_v1_1_11/board_sweekar.cc | 261 ++++ .../boards/board_v1_1_11/board_sweekar.h | 46 + .../02_physical/boards/board_v1_1_11/config.h | 138 +++ .../board_v1_1_11/io_expansion_board.cc | 732 ++++++++++++ .../boards/board_v1_1_11/io_expansion_board.h | 284 +++++ .../boards/board_v1_1_12/board_sweekar.cc | 257 ++++ .../boards/board_v1_1_12/board_sweekar.h | 38 + .../02_physical/boards/board_v1_1_12/config.h | 139 +++ .../board_v1_1_12/io_expansion_board.cc | 724 ++++++++++++ .../boards/board_v1_1_12/io_expansion_board.h | 284 +++++ .../boards/board_v1_1_13/board_sweekar.cc | 311 +++++ .../boards/board_v1_1_13/board_sweekar.h | 45 + .../02_physical/boards/board_v1_1_13/config.h | 145 +++ .../board_v1_1_13/io_expansion_board.cc | 1053 +++++++++++++++++ .../boards/board_v1_1_13/io_expansion_board.h | 419 +++++++ .../boards/board_v1_1_14/board_sweekar.cc | 702 +++++++++++ .../boards/board_v1_1_14/board_sweekar.h | 171 +++ .../board_sweekar_complete_init.cc | 186 +++ .../02_physical/boards/board_v1_1_14/config.h | 132 +++ .../board_v1_1_14/io_expansion_board.cc | 1023 ++++++++++++++++ .../boards/board_v1_1_14/io_expansion_board.h | 421 +++++++ .../board_v1_1_14/power_management_config.h | 178 +++ .../boards/board_v1_1_16/board_sweekar.cc | 738 ++++++++++++ .../boards/board_v1_1_16/board_sweekar.h | 174 +++ .../board_sweekar_complete_init.cc | 186 +++ .../02_physical/boards/board_v1_1_16/config.h | 138 +++ .../board_v1_1_16/io_expansion_board.cc | 1034 ++++++++++++++++ .../boards/board_v1_1_16/io_expansion_board.h | 432 +++++++ .../board_v1_1_16/power_management_config.h | 178 +++ .../boards/board_v1_1_17/board_sweekar.cc | 780 ++++++++++++ .../boards/board_v1_1_17/board_sweekar.h | 181 +++ .../board_sweekar_complete_init.cc | 186 +++ .../02_physical/boards/board_v1_1_17/config.h | 136 +++ .../board_v1_1_17/io_expansion_board.cc | 1040 ++++++++++++++++ .../boards/board_v1_1_17/io_expansion_board.h | 432 +++++++ .../board_v1_1_17/power_management_config.h | 178 +++ .../boards/board_v1_1_18/board_sweekar.cc | 778 ++++++++++++ .../boards/board_v1_1_18/board_sweekar.h | 181 +++ .../board_sweekar_complete_init.cc | 200 ++++ .../02_physical/boards/board_v1_1_18/config.h | 136 +++ .../board_v1_1_18/io_expansion_board.cc | 1040 ++++++++++++++++ .../boards/board_v1_1_18/io_expansion_board.h | 432 +++++++ .../board_v1_1_18/power_management_config.h | 178 +++ main/02_physical/boards/config.h | 26 + main/02_physical/boards/module.cmake | 35 + main/04_hal/audio_codec/audio_codec.cc | 247 ++++ main/04_hal/audio_codec/audio_codec.h | 74 ++ main/04_hal/audio_codec/module.cmake | 16 + main/04_hal/base_board_hal/base_board_hal.h | 41 + .../base_board_hal/base_board_hal_i2c.h | 65 + .../base_board_hal/base_board_hal_uart.h | 45 + main/04_hal/base_board_hal/module.cmake | 13 + main/04_hal/stepper_driver/aw8646.cc | 213 ++++ main/04_hal/stepper_driver/aw8646.h | 27 + main/04_hal/stepper_driver/aw8646.pdf | Bin 0 -> 1485355 bytes main/04_hal/stepper_driver/drv8428.cc | 147 +++ main/04_hal/stepper_driver/drv8428.h | 25 + main/04_hal/stepper_driver/module.cmake | 17 + main/04_hal/stepper_driver/stepper_driver.h | 54 + .../adc_battery_monitor.cc | 167 +++ .../adc_battery_monitor/adc_battery_monitor.h | 47 + .../adc_battery_monitor/module.cmake | 16 + .../base_board_control/base_board_control.cc | 257 ++++ .../base_board_control/base_board_control.h | 63 + .../base_board_control/module.cmake | 16 + main/05_executors/gyroscope/gyroscope.cc | 625 ++++++++++ main/05_executors/gyroscope/gyroscope.h | 214 ++++ main/05_executors/gyroscope/module.cmake | 16 + .../millimeter_wave_radar.cc | 202 ++++ .../millimeter_wave_radar.h | 82 ++ .../millimeter_wave_radar/module.cmake | 16 + .../photo_interrupter/module.cmake | 16 + .../photo_interrupter/photo_interrupter.cc | 129 ++ .../photo_interrupter/photo_interrupter.h | 87 ++ main/CMakeLists.txt | 150 +++ main/Kconfig.modules | 52 + main/Kconfig.projbuild | 544 +++++++++ main/MODULE_DEVELOPMENT_GUIDE.md | 124 ++ main/generate_kconfig_modules.py | 247 ++++ main/idf_component.yml | 19 + main/main.cc | 5 + 82 files changed, 20611 insertions(+) create mode 100644 main/02_physical/boards/board_sweekar.h create mode 100644 main/02_physical/boards/board_v1_1_11/board_sweekar.cc create mode 100644 main/02_physical/boards/board_v1_1_11/board_sweekar.h create mode 100644 main/02_physical/boards/board_v1_1_11/config.h create mode 100644 main/02_physical/boards/board_v1_1_11/io_expansion_board.cc create mode 100644 main/02_physical/boards/board_v1_1_11/io_expansion_board.h create mode 100644 main/02_physical/boards/board_v1_1_12/board_sweekar.cc create mode 100644 main/02_physical/boards/board_v1_1_12/board_sweekar.h create mode 100644 main/02_physical/boards/board_v1_1_12/config.h create mode 100644 main/02_physical/boards/board_v1_1_12/io_expansion_board.cc create mode 100644 main/02_physical/boards/board_v1_1_12/io_expansion_board.h create mode 100644 main/02_physical/boards/board_v1_1_13/board_sweekar.cc create mode 100644 main/02_physical/boards/board_v1_1_13/board_sweekar.h create mode 100644 main/02_physical/boards/board_v1_1_13/config.h create mode 100644 main/02_physical/boards/board_v1_1_13/io_expansion_board.cc create mode 100644 main/02_physical/boards/board_v1_1_13/io_expansion_board.h create mode 100644 main/02_physical/boards/board_v1_1_14/board_sweekar.cc create mode 100644 main/02_physical/boards/board_v1_1_14/board_sweekar.h create mode 100644 main/02_physical/boards/board_v1_1_14/board_sweekar_complete_init.cc create mode 100644 main/02_physical/boards/board_v1_1_14/config.h create mode 100644 main/02_physical/boards/board_v1_1_14/io_expansion_board.cc create mode 100644 main/02_physical/boards/board_v1_1_14/io_expansion_board.h create mode 100644 main/02_physical/boards/board_v1_1_14/power_management_config.h create mode 100644 main/02_physical/boards/board_v1_1_16/board_sweekar.cc create mode 100644 main/02_physical/boards/board_v1_1_16/board_sweekar.h create mode 100644 main/02_physical/boards/board_v1_1_16/board_sweekar_complete_init.cc create mode 100644 main/02_physical/boards/board_v1_1_16/config.h create mode 100644 main/02_physical/boards/board_v1_1_16/io_expansion_board.cc create mode 100644 main/02_physical/boards/board_v1_1_16/io_expansion_board.h create mode 100644 main/02_physical/boards/board_v1_1_16/power_management_config.h create mode 100644 main/02_physical/boards/board_v1_1_17/board_sweekar.cc create mode 100644 main/02_physical/boards/board_v1_1_17/board_sweekar.h create mode 100644 main/02_physical/boards/board_v1_1_17/board_sweekar_complete_init.cc create mode 100644 main/02_physical/boards/board_v1_1_17/config.h create mode 100644 main/02_physical/boards/board_v1_1_17/io_expansion_board.cc create mode 100644 main/02_physical/boards/board_v1_1_17/io_expansion_board.h create mode 100644 main/02_physical/boards/board_v1_1_17/power_management_config.h create mode 100644 main/02_physical/boards/board_v1_1_18/board_sweekar.cc create mode 100644 main/02_physical/boards/board_v1_1_18/board_sweekar.h create mode 100644 main/02_physical/boards/board_v1_1_18/board_sweekar_complete_init.cc create mode 100644 main/02_physical/boards/board_v1_1_18/config.h create mode 100644 main/02_physical/boards/board_v1_1_18/io_expansion_board.cc create mode 100644 main/02_physical/boards/board_v1_1_18/io_expansion_board.h create mode 100644 main/02_physical/boards/board_v1_1_18/power_management_config.h create mode 100644 main/02_physical/boards/config.h create mode 100644 main/02_physical/boards/module.cmake create mode 100644 main/04_hal/audio_codec/audio_codec.cc create mode 100644 main/04_hal/audio_codec/audio_codec.h create mode 100644 main/04_hal/audio_codec/module.cmake create mode 100644 main/04_hal/base_board_hal/base_board_hal.h create mode 100644 main/04_hal/base_board_hal/base_board_hal_i2c.h create mode 100644 main/04_hal/base_board_hal/base_board_hal_uart.h create mode 100644 main/04_hal/base_board_hal/module.cmake create mode 100644 main/04_hal/stepper_driver/aw8646.cc create mode 100644 main/04_hal/stepper_driver/aw8646.h create mode 100644 main/04_hal/stepper_driver/aw8646.pdf create mode 100644 main/04_hal/stepper_driver/drv8428.cc create mode 100644 main/04_hal/stepper_driver/drv8428.h create mode 100644 main/04_hal/stepper_driver/module.cmake create mode 100644 main/04_hal/stepper_driver/stepper_driver.h create mode 100644 main/05_executors/adc_battery_monitor/adc_battery_monitor.cc create mode 100644 main/05_executors/adc_battery_monitor/adc_battery_monitor.h create mode 100644 main/05_executors/adc_battery_monitor/module.cmake create mode 100644 main/05_executors/base_board_control/base_board_control.cc create mode 100644 main/05_executors/base_board_control/base_board_control.h create mode 100644 main/05_executors/base_board_control/module.cmake create mode 100644 main/05_executors/gyroscope/gyroscope.cc create mode 100644 main/05_executors/gyroscope/gyroscope.h create mode 100644 main/05_executors/gyroscope/module.cmake create mode 100644 main/05_executors/millimeter_wave_radar/millimeter_wave_radar.cc create mode 100644 main/05_executors/millimeter_wave_radar/millimeter_wave_radar.h create mode 100644 main/05_executors/millimeter_wave_radar/module.cmake create mode 100644 main/05_executors/photo_interrupter/module.cmake create mode 100644 main/05_executors/photo_interrupter/photo_interrupter.cc create mode 100644 main/05_executors/photo_interrupter/photo_interrupter.h create mode 100644 main/CMakeLists.txt create mode 100644 main/Kconfig.modules create mode 100644 main/Kconfig.projbuild create mode 100644 main/MODULE_DEVELOPMENT_GUIDE.md create mode 100644 main/generate_kconfig_modules.py create mode 100644 main/idf_component.yml create mode 100644 main/main.cc diff --git a/main/02_physical/boards/board_sweekar.h b/main/02_physical/boards/board_sweekar.h new file mode 100644 index 0000000..7c60516 --- /dev/null +++ b/main/02_physical/boards/board_sweekar.h @@ -0,0 +1,25 @@ +#ifndef BOARD_SELECTION_H +#define BOARD_SELECTION_H + +#include "sdkconfig.h" + +// 根据menuconfig的配置选择不同的board版本 +#ifdef CONFIG_BOARD_VERSION_V1_1_11 + #include "02_physical/boards/board_v1_1_11/board_sweekar.h" +#elif defined(CONFIG_BOARD_VERSION_V1_1_12) + #include "02_physical/boards/board_v1_1_12/board_sweekar.h" +#elif defined(CONFIG_BOARD_VERSION_V1_1_13) + #include "02_physical/boards/board_v1_1_13/board_sweekar.h" +#elif defined(CONFIG_BOARD_VERSION_V1_1_14) + #include "02_physical/boards/board_v1_1_14/board_sweekar.h" +#elif defined(CONFIG_BOARD_VERSION_V1_1_16) + #include "02_physical/boards/board_v1_1_16/board_sweekar.h" +#elif defined(CONFIG_BOARD_VERSION_V1_1_17) + #include "02_physical/boards/board_v1_1_17/board_sweekar.h" +#elif defined(CONFIG_BOARD_VERSION_V1_1_18) + #include "02_physical/boards/board_v1_1_18/board_sweekar.h" +#else + #include "02_physical/boards/board_v1_1_11/board_sweekar.h" +#endif + +#endif // BOARD_SELECTION_H \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_11/board_sweekar.cc b/main/02_physical/boards/board_v1_1_11/board_sweekar.cc new file mode 100644 index 0000000..9915adf --- /dev/null +++ b/main/02_physical/boards/board_v1_1_11/board_sweekar.cc @@ -0,0 +1,261 @@ +/** + * @file board.cc + * @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +extern "C" { +#include "esp_log.h" +#include "driver/gpio.h" +#include "driver/uart.h" +#include "driver/ledc.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "hal/gpio_types.h" +#include "hal/uart_types.h" +#include "esp_check.h" +#include "sdkconfig.h" +#include "i2c_bus.h" +} + +#include "board_sweekar.h" +#include "config.h" +#include "drv8428.h" +#include "aw8646.h" + +#define TAG "board_sweekar" + +BoardSweekar::BoardSweekar() +{ +#ifdef CONFIG_STEPPER_DRIVER_AW8646 + stepper_driver_ = new Aw8646Driver(io_expansion_); +#else + stepper_driver_ = new Drv8428Driver(io_expansion_); +#endif +} + +BoardSweekar::~BoardSweekar() +{ + if (stepper_driver_) { + delete stepper_driver_; + stepper_driver_ = nullptr; + } +} + +/** + * @file board.h + * @brief 板级外设初始化类 + */ +/** + * @brief 步进电机初始化函数 + * + * 配置LEDC定时器和通道用于PWM输出,设置步进电机的工作模式、使能状态、细分模式和方向, + * 并初始化PWM占空比为50%。初始化过程中若出现错误,会通过ESP_LOGE输出错误信息及错误码。 + */ +void BoardSweekar::StepperMotorInit(void) +{ + esp_err_t err = ESP_OK; + + // 1) STEP 引脚改为普通 GPIO + gpio_config_t io_cfg; + io_cfg.pin_bit_mask = 1ULL << STEPPER_STEP_IO; + io_cfg.mode = GPIO_MODE_OUTPUT; + io_cfg.pull_up_en = GPIO_PULLUP_DISABLE; + io_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_cfg.intr_type = GPIO_INTR_DISABLE; + err = gpio_config(&io_cfg); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "步进电机 STEP GPIO 配置失败, 错误码: 0x%x", err); + } + + // 初始电平拉低 + gpio_set_level(STEPPER_STEP_IO, 0); + + // 2) 检查 I2C 总线是否已初始化 + if (bus_handle_ == nullptr) + { + ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()"); + return; + } + + // 3) 初始化驱动对象并初始化 + if (stepper_driver_) { + err = stepper_driver_->Init(); + if (err != ESP_OK) { + ESP_LOGE(TAG_BOARD, "步进电机驱动初始化失败, 错误码: 0x%x", err); + } + } else { + ESP_LOGE(TAG_BOARD, "步进电机驱动创建失败"); + } +} + +/** + * @brief 毫米波雷达串口初始化函数 + * + * 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚, + * 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免 + * 与自定义中断冲突。 + */ +void BoardSweekar::MillimeterWaveRadarUartInit(void) +{ + uart_config_t uart_config = { + .baud_rate = BAUD_RATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + }; + + // 1. 设置串口参数 + ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config)); + + // 2. 设置 UART 引脚 + ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突) + // 增加 RX/TX FIFO 深度以处理突发数据 + ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4, + 0, NULL, 0)); +} + +/** + * @brief 毫米波雷达中断引脚初始化函数 + * + * 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能 + * (如需使用中断需单独进行配置)。 + */ +void BoardSweekar::MillimeterWaveRadarGpioInit(void) +{ + // GPIO配置结构体 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚 + .mode = GPIO_MODE_INPUT, // 设置为输入模式 + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉 + .intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置) + }; + + // 配置GPIO + gpio_config(&io_conf); +} + +/** + * @brief I2C总线及从机设备初始化函数 + * + * 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。 + * 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。 + * 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。 + * + * @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因 + */ +esp_err_t BoardSweekar::I2CMasterInit(void) +{ + static const char *I2C_INIT = "I2C_INIT"; + + // 初始化IO扩展板复位引脚 + gpio_config_t reset_io_conf = { + .pin_bit_mask = (1ULL << IO_EXPAND_RSTN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉 + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&reset_io_conf); + + // 执行复位时序:先拉低100ms,再拉高并等待100ms + gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms + gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + + ESP_LOGI(I2C_INIT, "IO扩展板复位完成"); + + // 创建统一的I2C总线(使用ESP-ADF的i2c_bus) + i2c_config_t i2c_cfg = { + .mode = I2C_MODE_MASTER, + .sda_io_num = I2C0_MASTER_SDA_IO, + .scl_io_num = I2C0_MASTER_SCL_IO, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master = { + .clk_speed = 100000, + }, + }; + + // 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线) + bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg); + if (bus_handle_ == NULL) { + ESP_LOGE(TAG, "Failed to create I2C bus"); + return ESP_FAIL; + } + + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + // ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信 + + // 验证线性马达设备是否存在 + esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR); + } + // 验证IO扩展板设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err); + // 不返回错误,继续初始化其他设备 + } else { + ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR); + } + // 验证陀螺仪设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR); + } + + // 为IO扩展板设置总线句柄和设备地址(使用7位地址) + io_expansion_.bus_handle_ = bus_handle_; + io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1; + + // 为线性马达设置总线句柄和设备地址(使用7位地址) + linear_motor_.bus_handle_ = bus_handle_; + linear_motor_.device_addr_ = LINEAR_MOTOR_I2C_SLAVE_ADDR << 1; + + ESP_LOGI(I2C_INIT, "I2C总线初始化完成"); + return ESP_OK; +} + +/** + * @brief 开启VBAT to VBAT_5V + * + * 创建开启升压的电源管理单元 + * + */ +void BoardSweekar::VbatToVbat5vInit(void) +{ + // 配置VBAT_5V引脚为输出模式 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << VBAT_5V_PIN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&io_conf); + // 使能VBAT_5V + gpio_set_level(VBAT_5V_PIN, 1); +} + + + + diff --git a/main/02_physical/boards/board_v1_1_11/board_sweekar.h b/main/02_physical/boards/board_v1_1_11/board_sweekar.h new file mode 100644 index 0000000..d644169 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_11/board_sweekar.h @@ -0,0 +1,46 @@ +#ifndef __BOARD_H__ +#define __BOARD_H__ +#include "config.h" +#include "io_expansion_board.h" +#include "stepper_motor.h" +#include "stepper_driver.h" +#include "i2c_bus.h" +#include "gyroscope.h" +#include "touch_sensor.h" + +class BoardSweekar +{ +private: + i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄 + +public: + BoardSweekar(); + ~BoardSweekar(); + + IOExpansionBoard io_expansion_; // IO扩展板对象 + LinearMotor linear_motor_; // 线性马达对象 + Gyroscope gyroscope_; // 陀螺仪对象 + TouchSensor touch_sensor_; // 触摸传感器对象 + StepperDriver* stepper_driver_ = nullptr; // 步进电机驱动对象 + + StepperDriver* GetStepperDriver() const { return stepper_driver_; } + + // 初始化步进电机 + void StepperMotorInit(void); + + // 初始化串口 + void MillimeterWaveRadarUartInit(void); + + //初始化毫米波雷达的中断引脚 + void MillimeterWaveRadarGpioInit(void); + + // 初始化I2C总线 + esp_err_t I2CMasterInit(void); + + // 初始化VBAT toVBAT_5V引脚 + void VbatToVbat5vInit(void); + + // 获取I2C总线句柄 + i2c_bus_handle_t GetBusHandle() const { return bus_handle_; } +}; +#endif diff --git a/main/02_physical/boards/board_v1_1_11/config.h b/main/02_physical/boards/board_v1_1_11/config.h new file mode 100644 index 0000000..36fd4b7 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_11/config.h @@ -0,0 +1,138 @@ +/* 定义引脚分配 */ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +/** + * @file config.h + * @brief 定义了引脚的分配。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +#include "driver/gpio.h" +#include "driver/i2c_master.h" +#include "driver/i2s.h" +#include "esp_log.h" +#include "esp_rom_sys.h" // 用于 esp_rom_delay_us +#include "esp_timer.h" +#include "esp_mac.h" +#include "driver/ledc.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "driver/timer.h" +#include "esp_intr_alloc.h" +#include "soc/timer_group_struct.h" // 包含TIMERG0、TIMERG1的结构体定义 +#include "soc/timer_group_reg.h" // 包含定时器相关寄存器宏定义 +#include "driver/uart.h" +#include "esp_err.h" +#include "freertos/queue.h" +#include "soc/uart_reg.h" +#include "linear_motor.h" +#include "gyroscope.h" + +#define TAG_BOARD "SWEEKAR_ESP32" +/*I2C总线引脚定义*/ +#define I2C0_MASTER_PORT I2C_NUM_0 +#define I2C0_MASTER_SDA_IO GPIO_NUM_2 +#define I2C0_MASTER_SCL_IO GPIO_NUM_3 + +/* 步进电机引脚设置 */ +#define LEDC_OUTPUT_IO GPIO_NUM_42 // 步进电机LEDC引脚输入 + +/* 定义屏幕驱动控制引脚 */ +#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚 +#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL +#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚 +#define ST7789_PIN_CS GPIO_NUM_40 // SPI片选引脚 +#define ST7789_PIN_BL GPIO_NUM_NC // 背光引脚 +#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚 +#define LCD_BL_ACTIVE_LEVEL 0 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS) + +#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数) +#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数) + +/* 毫米波雷达配置参数 */ +/* 定义毫米波雷达的中断引脚 */ +#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35 +// UART 配置参数 +#define RADAR_UART_NUM UART_NUM_1 // 使用 UART0 +#define UART_TX_PIN GPIO_NUM_NC // GPIO43 作为 TX(根据实际硬件连接调整) +#define UART_RX_PIN GPIO_NUM_39 // GPIO44 作为 RX +#define BAUD_RATE 9600 // 波特率 +#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小 + +/* IO扩展硬件配置常量 */ +#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000) +#define I2C_IO_EXPAND_SLAVE_ADDR 0x5B // AW9523BTQR器件地址 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚 +#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值 +#define IO_EXPAND_RSTN GPIO_NUM_45 // IO扩展板复位引脚 + +/* 定义线性马达的I2C从机配置常量 */ +#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址 + +/* 定义陀螺仪的I2C从机配置常量 */ +#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址 +#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚 + +/* 原生触摸引脚配置 */ +// 触摸按键数量配置 +// #define TOUCH_BUTTON_NUM 4 +#define TOUCH_BUTTON_NUM 3 +// 触摸通道定义 +#define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11 +#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12 +#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13 +// #define TOUCH_PAD_CHANNEL_4 TOUCH_PAD_NUM14 // GPIO14 + +/* ES8311音频编解码器配置 (ESP-ADF兼容) */ +#define AUDIO_INPUT_SAMPLE_RATE 24000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 +#define AUDIO_INPUT_REFERENCE true + +/* I2S GPIO定义 */ +#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15 +#define AUDIO_I2S_GPIO_WS GPIO_NUM_4 +#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5 +#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6 +#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7 + +/* PA引脚定义 */ +#define AUDIO_CODEC_PA_PIN GPIO_NUM_8 + +/* I2C配置 */ +#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2 +#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3 +#define AUDIO_CODEC_ES8311_ADDR 0x18 +#define AUDIO_CODEC_ES7210_ADDR 0x40 + +/* WS2812 RGB LED配置 */ +#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚 +#define WS2812_NUM_LEDS 2 // WS2812 LED数量 + +/* 创建VBAT to VBAT_5V */ +#define VBAT_5V_PIN GPIO_NUM_8 // VBAT_5V引脚 + +/* 定义按键的中断引脚 */ +#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚 + +#endif // _BOARD_CONFIG_H_ + + + + + + + + + + + + + + + + diff --git a/main/02_physical/boards/board_v1_1_11/io_expansion_board.cc b/main/02_physical/boards/board_v1_1_11/io_expansion_board.cc new file mode 100644 index 0000000..3c3e978 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_11/io_expansion_board.cc @@ -0,0 +1,732 @@ +#include "io_expansion_board.h" +#include "millimeter_wave_radar.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_check.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/idf_additions.h" +#include "freertos/portable.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_rom_sys.h" +/** + * @file io_expansion_board.cc + * @brief IO扩展板功能实现类,包含I2C通信、GPIO中断配置、外设控制等功能 + * @details 实现了IO扩展板的初始化(中断引脚、复位引脚)、寄存器读写、步进电机控制(细分模式、使能、方向、睡眠状态)、 + * LCD相关引脚控制(背光、复位、片选)、毫米波雷达中断引脚配置等功能,并提供I2C数据读取任务的创建与管理 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +/** + * @brief 构造函数 + */ +IOExpansionBoard::IOExpansionBoard() + : bus_handle_(nullptr), + device_addr_(0), + i2c_task_event_group_(nullptr), + xI2CReadTaskHandle_(nullptr) +{ +} + +/** + * @brief 析构函数 + */ +IOExpansionBoard::~IOExpansionBoard() +{ + // 删除任务 + if (xI2CReadTaskHandle_) { + vTaskDelete(xI2CReadTaskHandle_); + } + + // if(pI2CReadTaskStackBuffer) { + // heap_caps_free(pI2CReadTaskStackBuffer); + // pI2CReadTaskStackBuffer = nullptr; + // } + + // if(pxI2CReadTaskBuffer) { + // vPortFree(pxI2CReadTaskBuffer); + // pxI2CReadTaskBuffer = nullptr; + // } + + // 删除事件组 + if (i2c_task_event_group_) { + vEventGroupDelete(i2c_task_event_group_); + } + + // 移除中断处理 + if (interrupt_gpio_ != GPIO_NUM_NC) { + gpio_isr_handler_remove(interrupt_gpio_); + } + + // 删除IO扩展板设备 + // 使用i2c_bus API时不需要手动删除设备句柄 + // bus_handle_由board_sweekar统一管理 +} + +/** + * @brief 静态中断处理函数 + */ +void IRAM_ATTR IOExpansionBoard::GpioIsrHandler(void* arg) +{ + IOExpansionBoard* instance = static_cast(arg); + if (!instance) return; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // 设置事件标志位 + if (instance->i2c_task_event_group_) { + xEventGroupSetBitsFromISR( + instance->i2c_task_event_group_, + BIT0, + &xHigherPriorityTaskWoken + ); + } + + // // 唤醒挂起的I2C任务 + // if (instance->xI2CReadTaskHandle_) { + // if (xTaskResumeFromISR(instance->xI2CReadTaskHandle_) == pdTRUE) { + // xHigherPriorityTaskWoken = pdTRUE; + // } + // } + + // 触发上下文切换 + if (xHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); + } +} + +/** + * @brief 初始化GPIO中断检测 + */ +esp_err_t IOExpansionBoard::InterruptGpioInit(gpio_num_t gpio_num) +{ + // 配置IO扩展板中断引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_NEGEDGE; + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + + esp_err_t err = gpio_config(&io_conf); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + // 配置中断服务 + err = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3); + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断服务安装失败,错误码: 0x%x", err); + return err; + } + // 注册中断处理函数 + err = gpio_isr_handler_add(gpio_num, GpioIsrHandler, this); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断处理函数添加失败,错误码: 0x%x", err); + return err; + } + // 创建事件组 + i2c_task_event_group_ = xEventGroupCreate(); + if (!i2c_task_event_group_) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "事件组创建失败"); + return ESP_FAIL; + } + + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d中断初始化完成", gpio_num); + return ESP_OK; +} + +/** + * @brief 初始化硬件复位引脚 + * 设置为上拉,需要复位,需要输出低电平为20us的脉冲信号 + */ +esp_err_t IOExpansionBoard::ResetGpioInit(gpio_num_t gpio_num) +{ + reset_gpio_ = gpio_num; + + // 配置复位引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + esp_err_t err = gpio_config(&io_conf); + gpio_set_level(gpio_num, 1); // 复位引脚拉高 + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d复位引脚初始化完成", gpio_num); + return err; + } +} + +/** + * @brief 复位IO扩展板 + */ +esp_err_t IOExpansionBoard::ResetIoExpand() +{ + if (reset_gpio_ == GPIO_NUM_NC) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位引脚未初始化"); + return ESP_ERR_INVALID_STATE; + } + + // 复位IO扩展板 + gpio_set_level(reset_gpio_, 0); + esp_rom_delay_us(30); + gpio_set_level(reset_gpio_, 1); + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "复位成功"); + } + return ESP_OK; +} + +/** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::IoexpandWriteReg(uint8_t reg_addr, uint8_t data) +{ + return i2c_bus_write_bytes(bus_handle_, device_addr_, ®_addr, 1, &data, 1); +} + +/** + * @brief 从寄存器读取数据 + * @param reg_addr 寄存器地址(如INPUT_PORT0、ID等) + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果(ESP_OK为成功) + */ +esp_err_t IOExpansionBoard::IoexpandReadReg(uint8_t reg_addr, uint8_t* data) +{ + if (data == nullptr){ // 检查输入参数有效性 + return ESP_ERR_INVALID_ARG; + } + + // 使用i2c_bus_read_bytes进行寄存器读取 + esp_err_t err = i2c_bus_read_bytes(bus_handle_, device_addr_, ®_addr, 1, data, 1); + if (err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "读取寄存器失败,错误码:0x%x", err); + return err; + } + + return ESP_OK; +} + +//设置IO扩展板为输入模式或是输出模式 +/* +* 这里需要根据实际情况设置IO扩展板的模式,比如输入模式还是输出模式,以及各个引脚的配置。 +* P0_0 对应NFC_RST引脚,需要设置为输出模式,低电平有效。(待测) +* P0_1 对应USB_VBUS引脚,需要设置为输出模式,低电平有效。(待测) +* P0_2 对应BTN_RIGHT_EAR引脚,需要设置为输出模式,低电平有效。(待测) +* P0_3 暂时未使用。 +* P0_4 对应步进电机方向引脚,需要设置为输出模式,根据需求设置。(待测) +* P0_5 对应CHRG引脚(待测) +* P0_6 LCD_DC引脚,需要设置为输出模式,根据需求设置电平。(待测) +* P0_7 对应步进电机的使能引脚,需要设置为输出模式,根据需求设置。(待测) +* +* +* P1_0 对应EG800K_PWR。(待测) +* P1_1 对应LCD_RST,需要设置为输出模式,低电平有效。(待测) +* P1_2 对应LCD_CS,需要设置为输出模式,低电平有效。(待测) +* P1_3 暂时未使用。 +* P1_4 对应步进电机的细分模式M1引脚。(待测) +* P1_5 对应步进电机的细分模式M0引脚。(待测) +* P1_6 对应步进电机的睡眠引脚。(待测) +* P1_7 对应RADAR_O雷达的输出引脚。(待测) +* */ +esp_err_t IOExpansionBoard::IoexpandSetMode(void) +{ + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功"); + } + // 配置P0_0-P0_7的端口为输入还是输出:0-输出;1-输入 + // err = IoexpandWriteReg(CONFIG_PORT0, 0x04); // 0000 0100 + err = IoexpandWriteReg(CONFIG_PORT0, 0x24); // 0010 0100 + // err = IoexpandWriteReg(CONFIG_PORT0, 0x2C); // 0010 1100 0-2,0-3,0-5都是输入 + + // D 1101 + // 9 1001 + + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功"); + } + // 配置P1_0-P1_7的端口输出:0-输出;1-输入 + // err = IoexpandWriteReg(CONFIG_PORT1, 0x84); + err = IoexpandWriteReg(CONFIG_PORT1, 0x80); // 1000 0000 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口成功"); + } + // 配置P0_0-P0_7的初始为高电平 + // 配置P1_0-P1_7的初始为高电平 + err = IoexpandWriteReg(OUTPUT_PORT0, 0xFD); // 1111 1101 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值成功"); + } + err = IoexpandWriteReg(OUTPUT_PORT1, 0x7E); // 0111 1110 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值成功"); + } + + err = IoexpandWriteReg(INT_PORT1, 0x7F); // 0111 1111 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能成功"); + } + + return ESP_OK; +} + +/** + * @brief 设置步进电机的细分模式 + */ +void IOExpansionBoard::SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT, uint8_t m0_pin, uint8_t m1_pin) +{ + uint8_t current_val; + switch (mode) { + case 1: //全步输出模式 低低电平 + /* code */ + printf("设置步进电机为全步模式\n"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << m0_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << m1_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 2: //非圆 1/2 高低电平 + /* code */ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << m0_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << m1_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 3: //1/4 步 低高电平 + /* code */ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << m0_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << m1_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 4: //1/8 步 高高电平 + /* code */ + printf("设置步进电机为1/8步模式\n"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << m0_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << m1_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + default: //全步输入模式 低低电平 + /* code */ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << m0_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << m1_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + } +} + +/** + * @brief 设置步进电机的使能 + */ +esp_err_t IOExpansionBoard::SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin) +{ + uint8_t current_val; + if(enable){ + // 进入工作状态mode + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << enable_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << enable_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} +/** + * @brief 设置步进电机运行方向 + */ +esp_err_t IOExpansionBoard::StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin) +{ + uint8_t current_val; + if(dir){ + // 方向为正转 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/** + * @brief 设置步进电机是否进入睡眠或者工作状态(高电平进入工作状态,低电平进入睡眠状态) + */ +esp_err_t IOExpansionBoard::SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin) +{ + uint8_t current_val; + if(mode){ + // 进入工作状态mode + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << nsleep_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << nsleep_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/*********************************************IO扩展板LCD引脚配置参数***********************************************/ +/** + * @brief 设置 LCD_BL引脚电平(高电平为命令模式,低电平为数据模式) + */ +esp_err_t IOExpansionBoard::SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin) +{ + uint8_t current_val; + if(mode){ + // 进入命令模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << bl_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入数据模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << bl_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/** + * @brief 设置 LCD_RST引脚电平(高电平为复位模式,低电平为工作模式) + */ +esp_err_t IOExpansionBoard::SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t reset_pin) +{ + uint8_t current_val; + if(mode){ + // 进入复位模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << reset_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入工作模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << reset_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/*********************************************IO扩展板的输入引脚配置以及中断引脚定义***********************************************/ +/** + * @brief 设置 毫米波雷达的中断引脚 + */ +esp_err_t IOExpansionBoard::SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin) +{ + uint8_t current_val; + if(mode){ + // 进入输入模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << interrupt_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(INPUT_PORT, current_val); + } + else{ + // 进入输出模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << interrupt_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(INPUT_PORT, current_val); + } +} + +/** + * @brief 设置 LCD_CS引脚电平(低电平为选中状态,高电平为不选中状态) + */ +esp_err_t IOExpansionBoard::SetLcdCsMode(bool mode, uint8_t OUTPUT_PORT, uint8_t cs_pin) +{ + uint8_t current_val; + if(mode){ + // 进入选中状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << cs_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入不选中状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << cs_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} +/** + * @brief I2C数据读取任务主体 + */ +void IOExpansionBoard::I2cReadTask(void* pvParameters) +{ + IOExpansionBoard* instance = static_cast(pvParameters); + if (!instance) { + vTaskDelete(nullptr); + return; + } + // 初始化复位引脚 + esp_err_t err = instance->ResetGpioInit(IO_EXPAND_RSTN); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO复位初始化失败"); + } + // 初始化IO扩展板子的中断引脚 + err = instance->InterruptGpioInit(GPIO_INPUT_PIN_SEL); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断初始化失败"); + } + // 设置IO扩展板模式 + instance->IoexpandSetMode(); + // 设置LCD屏幕背光引脚(初始为关闭) + err = instance->SetLcdBlMode(LCD_BL_HIGH, LCD_BL_PORT, LCD_BL_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕背光引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕背光引脚成功"); + } + // 设置LCD屏幕复位引脚 + err = instance->SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功"); + } + uint8_t current_val; + for (;;) { + // 等待中断事件触发 + if (instance->i2c_task_event_group_) { + xEventGroupWaitBits(instance->i2c_task_event_group_, BIT0, pdTRUE, pdFALSE, portMAX_DELAY); + } + // 读取I2C数据 + instance->IoexpandReadReg(INPUT_PORT1,¤t_val); + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "读取数据: 0x%0X", current_val); + if(current_val & (1 << 7)){ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚(P1_7)\n"); + // 调用毫米波雷达回调函数 + if (instance->radar_) { + instance->radar_->TriggerRadarDetectCallback(); + } + } + + // vTaskSuspend(nullptr); // 挂起任务等待下次唤醒 + } +} + +// bool IOExpansionBoard::AllocateStaticTaskMemory() +// { +// printf("IO拓展芯片创建任务前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); +// printf("IO拓展芯片创建任务前 Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +// // 分配任务栈(PSRAM) +// const size_t TASK_STACK_SIZE = 4096; +// pI2CReadTaskStackBuffer = (StackType_t*)heap_caps_malloc( +// TASK_STACK_SIZE * sizeof(StackType_t), +// MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT +// ); + +// if (!pI2CReadTaskStackBuffer) { +// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to allocate task stack from PSRAM"); +// return false; +// } + +// // 分配任务控制块(内部RAM) +// pxI2CReadTaskBuffer = (StaticTask_t*)pvPortMalloc(sizeof(StaticTask_t)); +// if (!pxI2CReadTaskBuffer) { +// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to allocate task TCB from internal RAM"); +// heap_caps_free(pI2CReadTaskStackBuffer); +// pI2CReadTaskStackBuffer = nullptr; +// return false; +// } + +// ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static task memory allocated successfully"); +// printf("IO拓展芯片创建任务后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); +// printf("IO拓展芯片创建任务后 Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +// return true; +// } + +// void IOExpansionBoard::FreeStaticTaskMemory() +// { +// if (pI2CReadTaskStackBuffer != nullptr) { +// heap_caps_free(pI2CReadTaskStackBuffer); +// pI2CReadTaskStackBuffer = nullptr; +// } + +// if (pxI2CReadTaskBuffer != nullptr) { +// vPortFree(pxI2CReadTaskBuffer); +// pxI2CReadTaskBuffer = nullptr; +// } + +// ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static task memory freed"); +// } + +/** + * @brief 创建I2C数据读取任务 + */ +void IOExpansionBoard::CreateI2cReadTask() +{ + printf("创建I2C读取任务之前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之前:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + if (xI2CReadTaskHandle_) { + return; // 任务已创建 + } + + xTaskCreateWithCaps( + I2cReadTask, + "i2c_read_task", + I2C_TASK_STACK, + this, + I2C_TASK_PRIORITY, + &xI2CReadTaskHandle_, + MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT + ); + + if (xI2CReadTaskHandle_ == NULL) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to create static I2C read task"); + } else { + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static I2C read task created successfully"); + } + printf("创建I2C读取任务之后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之后:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +} + +/** + * @brief 启动I2C任务 (整合初始化和任务创建) + */ +esp_err_t IOExpansionBoard::StartTask() +{ + // 再创建任务 + if (!xI2CReadTaskHandle_) { + CreateI2cReadTask(); + } + return ESP_OK; +} diff --git a/main/02_physical/boards/board_v1_1_11/io_expansion_board.h b/main/02_physical/boards/board_v1_1_11/io_expansion_board.h new file mode 100644 index 0000000..baa836d --- /dev/null +++ b/main/02_physical/boards/board_v1_1_11/io_expansion_board.h @@ -0,0 +1,284 @@ +#ifndef IO_EXPANSION_BOARD_H +#define IO_EXPANSION_BOARD_H + +#include +#include +#include +#include +#include +#include "i2c_bus.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include +#include +#include +#include +#include +#include +#include +#include "esp_err.h" +#include "config.h" +#include "portmacro.h" + +// 前向声明,避免循环引用 +class MillimeterWaveRadar; + +/* 寄存器地址 */ +#define INPUT_PORT0 0x00 // 输入端口0寄存器 +#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取) +#define OUTPUT_PORT0 0x02 // 输出端口0寄存器 +#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平 +#define CONFIG_PORT0 0x04 // 配置端口0寄存器 +#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式 +#define INT_PORT0 0x06 // 中断端口0寄存器 +#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的) +#define CTL 0x11 // 全局控制寄存器 +#define ID 0x23 // 芯片ID寄存器(0x23) + +/***********************************IO扩展板电机引脚配置参数*************************************/ +/* 设置步进电机方向 */ +#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转 +#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转 +#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4 + +/* 设置步进电机细分模式 */ +#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5 +#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4 +#define STEPPER_MOTOR_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 + + +/* 设置步进电机睡眠引脚 */ +#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式 +#define STEPPER_MOTOR_WORK true //步进电机进入工作模式 +#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6 +#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 + +/* 设置电机的使能引脚 */ +#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7 +#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平 +#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平 + +/* 设置毫米波雷达对应IO扩展板的中断引脚 */ +#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7 +#define RADAR_INTERRUPT_PORT CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口INPUT_PORT1 +#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态 +#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态 +/* 任务配置常量 */ +#define WRITE_BUF_SIZE 2 // I2C单次写入字节数 +#define READ_BUF_SIZE 2 // I2C单次读取字节数 +#define I2C_TASK_PRIORITY 2 // 任务优先级(中等) +#define I2C_TASK_STACK 4096 // 任务栈大小(4KB) + +/***********************************IO扩展板LCD引脚配置参数*************************************/ +/* 设置LCD的BL引脚 */ +#define LCD_BL_PIN 6 //LCD背光引脚 +#define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define LCD_BL_HIGH true //LCD背光引脚状态为高电平 +#define LCD_BL_LOW false //LCD背光引脚状态为低电平 + +/* 设置LCD的RST引脚 */ +#define LCD_RST_PIN 1 //LCD复位引脚 +#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define LCD_RST_HIGH true //LCD复位引脚状态为高电平 +#define LCD_RST_LOW false //LCD复位引脚状态为低电平 + +/* 设置LCD的CS引脚 */ +#define LCD_CS_PIN 2 //LCD片选引脚 +#define LCD_CS_PORT OUTPUT_PORT1 //LCD片选引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define LCD_CS_HIGH true //LCD片选引脚状态为高电平 +#define LCD_CS_LOW false //LCD片选引脚状态为低电平 + +#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签 +#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签 + +// GPIO引脚定义 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚 +#define IO_EXPAND_RSTN GPIO_NUM_45 // IO扩展板复位引脚 + +/** + * @class IOExpansionBoard + * @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作 + */ +class IOExpansionBoard +{ +public: + /** + * @brief 构造函数 + */ + IOExpansionBoard(); + + /** + * @brief 设置毫米波雷达指针 + * @param radar 毫米波雷达对象指针 + */ + void SetRadar(MillimeterWaveRadar* radar) { radar_ = radar; }; + + /** + * @brief 析构函数 + */ + ~IOExpansionBoard(); + + /** + * @brief 初始化GPIO中断检测 + * @param gpio_num 中断引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t InterruptGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetIoExpand(); + + /** + * @brief 初始化I2C主机通信 + * @return esp_err_t 初始化结果 + */ + // esp_err_t IoExpansionI2cInit(); + + /** + * @brief 创建I2C数据读取任务 + */ + void CreateI2cReadTask(); + + /** + * @brief 启动I2C任务(整合初始化和任务创建) + * @return esp_err_t 操作结果 + */ + esp_err_t StartTask(); + + /** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data); + + /** + * @brief 读寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要读出的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data); + + // /** + // * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断 + // * @param reg_addr 寄存器地址 + // * @return esp_err_t 操作结果 + // */ + // esp_err_t SetInterruptStatus(bool status); + + /** + * @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandSetMode(); + + /** + * @brief 设置步进电机的细分模式 + * @param mode 模式:1/2/4/8/16/32/64 + * @return esp_err_t 操作结果 + */ + void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT, uint8_t m0_pin, uint8_t m1_pin); + + /** + * @brief 设置步进电机的方向 + * @param dir 方向 + * @param OUTPUT_PORT 输出端口 + * @param pin 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin); + + /** + * @brief 设置步进电机的睡眠模式 + * @param 是否进入睡眠模式 + * @param 输出端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin); + + /** + * @brief 设置步进电机的使能引脚状态 + * @param 使能状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin); + + /** + * @brief 设置LCD的BL引脚状态 + * @param BL状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin); + + /** + * @brief 设置LCD的RST引脚状态 + * @param RST状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin); + + /** + * @brief 设置LCD的CS引脚状态 + * @param CS状态(低电平为选中状态,高电平为不选中状态) + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdCsMode(bool mode, uint8_t OUTPUT_PORT, uint8_t cs_pin); + + /** + * @brief 设置雷达中断引脚 + * @param 毫米波雷达的中断引脚模式 + * @param 输入端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin); + + // 公共成员变量 + i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄 + uint8_t device_addr_; // I2C设备地址 + +private: + // 静态成员函数 + MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调 + static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数 + static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数 + + // /** + // * @brief 分配静态任务所需的内存 + // * @return bool 分配是否成功 + // */ + // bool AllocateStaticTaskMemory(); + + // /** + // * @brief 释放静态任务分配的内存 + // */ + // void FreeStaticTaskMemory(); + + // 实例成员变量 + EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组 + TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄 + bool is_initialized_ = false; // 初始化状态标记(新增) + gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚 + gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚 + + // StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM) + // StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM) +}; + +#endif \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_12/board_sweekar.cc b/main/02_physical/boards/board_v1_1_12/board_sweekar.cc new file mode 100644 index 0000000..2244670 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_12/board_sweekar.cc @@ -0,0 +1,257 @@ +/** + * @file board.cc + * @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +extern "C" { +#include "esp_log.h" +#include "driver/gpio.h" +#include "driver/uart.h" +#include "driver/ledc.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "hal/gpio_types.h" +#include "hal/uart_types.h" +#include "esp_check.h" +#include "sdkconfig.h" +#include "i2c_bus.h" +} + +#include "board_sweekar.h" +#include "config.h" +#define TAG "board_sweekar" +/** + * @file board.h + * @brief 板级外设初始化类 + */ +/** + * @brief 步进电机初始化函数 + * + * 配置LEDC定时器和通道用于PWM输出,设置步进电机的工作模式、使能状态、细分模式和方向, + * 并初始化PWM占空比为50%。初始化过程中若出现错误,会通过ESP_LOGE输出错误信息及错误码。 + */ +void BoardSweekar::StepperMotorInit(void) +{ + // 配置LEDC用于PWM输出 + ledc_timer_config_t ledc_timer = { + .speed_mode = LEDC_MODE, + .duty_resolution = LEDC_DUTY_RES, + .timer_num = LEDC_TIMER, + .freq_hz = LEDC_FREQ_HZ, + .clk_cfg = LEDC_USE_APB_CLK, + }; + esp_err_t err = ledc_timer_config(&ledc_timer); + if (err != ESP_OK){ + ESP_LOGE(TAG_BOARD, "步进电机LEDC定时器配置失败,错误码: 0x%x", err); + } + + // 配置LEDC通道 + ledc_channel_config_t ledc_channel = { + .gpio_num = LEDC_OUTPUT_IO, + .speed_mode = LEDC_MODE, + .channel = LEDC_CHANNEL, + .timer_sel = LEDC_TIMER, + .duty = 0, // 初始占空比0 + .hpoint = 0 + }; + err = ledc_channel_config(&ledc_channel); + if (err != ESP_OK){ + ESP_LOGE(TAG_BOARD, "步进电机LEDC通道配置失败,错误码: 0x%x", err); + } + + // 检查I2C总线是否已初始化 + if (bus_handle_ == nullptr) { + ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()"); + return; + } + + // 设置步进电机工作模式,使能电机,设置步进电机细分模式,设置步进电机方向 + err = io_expansion_.SetMotorSleepMode(STEPPER_MOTOR_WORK, STEPPER_MOTOR_SLEEP_PORT, STEPPER_MOTOR_WORK); + if (err != ESP_OK){ + ESP_LOGE(TAG_BOARD, "步进电机初始化失败,错误码: 0x%x", err); + } + err = io_expansion_.SetMotorEnableMode(STEPPER_MOTOR_ENABLE_DISABLE, STEPPER_MOTOR_ENABLE_PORT, STEPPER_MOTOR_ENABLE_PIN); + if (err != ESP_OK){ + ESP_LOGE(TAG_BOARD, "步进电机初始化失败,错误码: 0x%x", err); + } + io_expansion_.SetStepperMicrostepMode(4, STEPPER_MOTOR_MADE_PORT, STEPPER_MOTOR_M0_PIN, STEPPER_MOTOR_M1_PIN); + err = io_expansion_.StepperMotorSetDir(STEPPER_MOTOR_LEFT, STEPPER_MOTOR_DIR_PORT, STEPPER_MOTOR_DIR_PIN); + if (err != ESP_OK){ + ESP_LOGE(TAG_BOARD, "步进电机初始化失败,错误码: 0x%x", err); + } + + // 初始PWM占空比设为0% + ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0); + ledc_update_duty(LEDC_MODE, LEDC_CHANNEL); +} + +/** + * @brief 毫米波雷达串口初始化函数 + * + * 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚, + * 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免 + * 与自定义中断冲突。 + */ +void BoardSweekar::MillimeterWaveRadarUartInit(void) +{ + uart_config_t uart_config = { + .baud_rate = RADAR_BAUD_RATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + }; + + // 1. 设置串口参数 + ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config)); + + // 2. 设置 UART 引脚 + ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突) + // 增加 RX/TX FIFO 深度以处理突发数据 + ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4, + 0, NULL, 0)); +} + +/** + * @brief 毫米波雷达中断引脚初始化函数 + * + * 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能 + * (如需使用中断需单独进行配置)。 + */ +void BoardSweekar::MillimeterWaveRadarGpioInit(void) +{ + // GPIO配置结构体 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚 + .mode = GPIO_MODE_INPUT, // 设置为输入模式 + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉 + .intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置) + }; + + // 配置GPIO + gpio_config(&io_conf); +} + +/** + * @brief I2C总线及从机设备初始化函数 + * + * 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。 + * 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。 + * 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。 + * + * @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因 + */ +esp_err_t BoardSweekar::I2CMasterInit(void) +{ + static const char *I2C_INIT = "I2C_INIT"; + + // 初始化IO扩展板复位引脚 + gpio_config_t reset_io_conf = { + .pin_bit_mask = (1ULL << IO_EXPAND_RSTN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉 + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&reset_io_conf); + + // 执行复位时序:先拉低100ms,再拉高并等待100ms + gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms + gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + + ESP_LOGI(I2C_INIT, "IO扩展板复位完成"); + + // 创建统一的I2C总线(使用ESP-ADF的i2c_bus) + i2c_config_t i2c_cfg = { + .mode = I2C_MODE_MASTER, + .sda_io_num = I2C0_MASTER_SDA_IO, + .scl_io_num = I2C0_MASTER_SCL_IO, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master = { + .clk_speed = 100000, + }, + }; + + // 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线) + bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg); + if (bus_handle_ == NULL) { + ESP_LOGE(TAG, "Failed to create I2C bus"); + return ESP_FAIL; + } + + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + // ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信 + + // 验证线性马达设备是否存在 + esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR); + } + // 验证IO扩展板设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err); + // 不返回错误,继续初始化其他设备 + } else { + ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR); + } + // 验证陀螺仪设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR); + } + + // 为IO扩展板设置总线句柄和设备地址(使用7位地址) + io_expansion_.bus_handle_ = bus_handle_; + io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1; + + // 为线性马达设置总线句柄和设备地址(使用7位地址) + linear_motor_.bus_handle_ = bus_handle_; + linear_motor_.device_addr_ = LINEAR_MOTOR_I2C_SLAVE_ADDR << 1; + + ESP_LOGI(I2C_INIT, "I2C总线初始化完成"); + return ESP_OK; +} + +/** + * @brief 开启VBAT to VBAT_5V + * + * 创建开启升压的电源管理单元 + * + */ +void BoardSweekar::VbatToVbat5vInit(void) +{ + // 配置VBAT_5V引脚为输出模式 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << VBAT_5V_PIN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&io_conf); + // 使能VBAT_5V + gpio_set_level(VBAT_5V_PIN, 1); +} + + + + diff --git a/main/02_physical/boards/board_v1_1_12/board_sweekar.h b/main/02_physical/boards/board_v1_1_12/board_sweekar.h new file mode 100644 index 0000000..72492a9 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_12/board_sweekar.h @@ -0,0 +1,38 @@ +#ifndef __BOARD_H__ +#define __BOARD_H__ +#include "config.h" +#include "io_expansion_board.h" +#include "stepper_motor.h" +#include "i2c_bus.h" +#include "gyroscope.h" +#include "touch_sensor.h" + +class BoardSweekar +{ +private: + i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄 + +public: + IOExpansionBoard io_expansion_; // IO扩展板对象 + LinearMotor linear_motor_; // 线性马达对象 + Gyroscope gyroscope_; // 陀螺仪对象 + TouchSensor touch_sensor_; // 触摸传感器对象 + // 初始化步进电机 + void StepperMotorInit(void); + + // 初始化串口 + void MillimeterWaveRadarUartInit(void); + + //初始化毫米波雷达的中断引脚 + void MillimeterWaveRadarGpioInit(void); + + // 初始化I2C总线 + esp_err_t I2CMasterInit(void); + + // 初始化VBAT toVBAT_5V引脚 + void VbatToVbat5vInit(void); + + // 获取I2C总线句柄 + i2c_bus_handle_t GetBusHandle() const { return bus_handle_; } +}; +#endif diff --git a/main/02_physical/boards/board_v1_1_12/config.h b/main/02_physical/boards/board_v1_1_12/config.h new file mode 100644 index 0000000..1f2b6ba --- /dev/null +++ b/main/02_physical/boards/board_v1_1_12/config.h @@ -0,0 +1,139 @@ +/* 定义引脚分配 */ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +/** + * @file config.h + * @brief 定义了引脚的分配。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +#include "driver/gpio.h" +#include "driver/i2c_master.h" +#include "driver/i2s.h" +#include "esp_log.h" +#include "esp_rom_sys.h" // 用于 esp_rom_delay_us +#include "esp_timer.h" +#include "esp_mac.h" +#include "driver/ledc.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "driver/timer.h" +#include "esp_intr_alloc.h" +#include "soc/timer_group_struct.h" // 包含TIMERG0、TIMERG1的结构体定义 +#include "soc/timer_group_reg.h" // 包含定时器相关寄存器宏定义 +#include "driver/uart.h" +#include "esp_err.h" +#include "freertos/queue.h" +#include "soc/uart_reg.h" +#include "linear_motor.h" +#include "gyroscope.h" + +#define TAG_BOARD "SWEEKAR_ESP32" +/*I2C总线引脚定义*/ +#define I2C0_MASTER_PORT I2C_NUM_0 +#define I2C0_MASTER_SDA_IO GPIO_NUM_2 +#define I2C0_MASTER_SCL_IO GPIO_NUM_3 + +/* 步进电机引脚设置 */ +#define LEDC_OUTPUT_IO GPIO_NUM_42 // 步进电机LEDC引脚输入 + +/* 定义屏幕驱动控制引脚 */ +#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚 +#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL +#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚 +#define ST7789_PIN_CS GPIO_NUM_46 // SPI片选引脚 +#define ST7789_PIN_BL GPIO_NUM_NC // 背光引脚 +#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚 +#define LCD_BL_ACTIVE_LEVEL 0 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS) + +#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数) +#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数) + +/* 毫米波雷达配置参数 */ +/* 定义毫米波雷达的中断引脚 */ +#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35 +// UART 配置参数 +#define RADAR_UART_NUM UART_NUM_1 // 使用 UART1 +#define UART_TX_PIN GPIO_NUM_40 // GPIO43 作为 TX(根据实际硬件连接调整) +#define UART_RX_PIN GPIO_NUM_39 // GPIO44 作为 RX +#define RADAR_BAUD_RATE 9600 // 雷达波特率 +#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小 + +/* IO扩展硬件配置常量 */ +#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000) +#define I2C_IO_EXPAND_SLAVE_ADDR 0x5B // AW9523BTQR器件地址 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚 +#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值 +#define IO_EXPAND_RSTN GPIO_NUM_45 // IO扩展板复位引脚 + +/* 定义线性马达的I2C从机配置常量 */ +#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址 + +/* 定义陀螺仪的I2C从机配置常量 */ +#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址 +#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚 + +/* 原生触摸引脚配置 */ +// 触摸按键数量配置 +// #define TOUCH_BUTTON_NUM 4 +#define TOUCH_BUTTON_NUM 3 +// 触摸通道定义 +// #define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11 +#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12 +#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13 +#define TOUCH_PAD_CHANNEL_4 TOUCH_PAD_NUM14 // GPIO14 + +/* ES8311音频编解码器配置 (ESP-ADF兼容) */ +#define AUDIO_INPUT_SAMPLE_RATE 24000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 +#define AUDIO_INPUT_REFERENCE true + +/* I2S GPIO定义 */ +#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15 +#define AUDIO_I2S_GPIO_WS GPIO_NUM_4 +#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5 +#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6 +#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7 + +/* PA引脚定义 */ +#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC + +/* I2C配置 */ +#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2 +#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3 +#define AUDIO_CODEC_ES8311_ADDR 0x18 +#define AUDIO_CODEC_ES7210_ADDR 0x40 + +/* WS2812 RGB LED配置 */ +#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚 +#define WS2812_NUM_LEDS 2 // WS2812 LED数量 + +/* 创建VBAT to VBAT_5V */ +#define VBAT_5V_PIN GPIO_NUM_NC // VBAT_5V引脚 + +/* 定义按键的中断引脚 */ +#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚 +#define RIGHT_BUTTON_PIN GPIO_NUM_8 // 按键中断引脚 + +#endif // _BOARD_CONFIG_H_ + + + + + + + + + + + + + + + + diff --git a/main/02_physical/boards/board_v1_1_12/io_expansion_board.cc b/main/02_physical/boards/board_v1_1_12/io_expansion_board.cc new file mode 100644 index 0000000..1c8a964 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_12/io_expansion_board.cc @@ -0,0 +1,724 @@ +#include "io_expansion_board.h" +#include "millimeter_wave_radar.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_check.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/idf_additions.h" +#include "freertos/portable.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_rom_sys.h" +/** + * @file io_expansion_board.cc + * @brief IO扩展板功能实现类,包含I2C通信、GPIO中断配置、外设控制等功能 + * @details 实现了IO扩展板的初始化(中断引脚、复位引脚)、寄存器读写、步进电机控制(细分模式、使能、方向、睡眠状态)、 + * LCD相关引脚控制(背光、复位、片选)、毫米波雷达中断引脚配置等功能,并提供I2C数据读取任务的创建与管理 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +/** + * @brief 构造函数 + */ +IOExpansionBoard::IOExpansionBoard() + : bus_handle_(nullptr), + device_addr_(0), + i2c_task_event_group_(nullptr), + xI2CReadTaskHandle_(nullptr) +{ +} + +/** + * @brief 析构函数 + */ +IOExpansionBoard::~IOExpansionBoard() +{ + // 删除任务 + if (xI2CReadTaskHandle_) { + vTaskDelete(xI2CReadTaskHandle_); + } + + // if(pI2CReadTaskStackBuffer) { + // heap_caps_free(pI2CReadTaskStackBuffer); + // pI2CReadTaskStackBuffer = nullptr; + // } + + // if(pxI2CReadTaskBuffer) { + // vPortFree(pxI2CReadTaskBuffer); + // pxI2CReadTaskBuffer = nullptr; + // } + + // 删除事件组 + if (i2c_task_event_group_) { + vEventGroupDelete(i2c_task_event_group_); + } + + // 移除中断处理 + if (interrupt_gpio_ != GPIO_NUM_NC) { + gpio_isr_handler_remove(interrupt_gpio_); + } + + // 删除IO扩展板设备 + // 使用i2c_bus API时不需要手动删除设备句柄 + // bus_handle_由board_sweekar统一管理 +} + +/** + * @brief 静态中断处理函数 + */ +void IRAM_ATTR IOExpansionBoard::GpioIsrHandler(void* arg) +{ + IOExpansionBoard* instance = static_cast(arg); + if (!instance) return; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // 设置事件标志位 + if (instance->i2c_task_event_group_) { + xEventGroupSetBitsFromISR( + instance->i2c_task_event_group_, + BIT0, + &xHigherPriorityTaskWoken + ); + } + + // // 唤醒挂起的I2C任务 + // if (instance->xI2CReadTaskHandle_) { + // if (xTaskResumeFromISR(instance->xI2CReadTaskHandle_) == pdTRUE) { + // xHigherPriorityTaskWoken = pdTRUE; + // } + // } + + // 触发上下文切换 + if (xHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); + } +} + +/** + * @brief 初始化GPIO中断检测 + */ +esp_err_t IOExpansionBoard::InterruptGpioInit(gpio_num_t gpio_num) +{ + // 配置IO扩展板中断引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_NEGEDGE; + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + + esp_err_t err = gpio_config(&io_conf); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + // 配置中断服务 + err = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3); + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断服务安装失败,错误码: 0x%x", err); + return err; + } + // 注册中断处理函数 + err = gpio_isr_handler_add(gpio_num, GpioIsrHandler, this); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断处理函数添加失败,错误码: 0x%x", err); + return err; + } + // 创建事件组 + i2c_task_event_group_ = xEventGroupCreate(); + if (!i2c_task_event_group_) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "事件组创建失败"); + return ESP_FAIL; + } + + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d中断初始化完成", gpio_num); + return ESP_OK; +} + +/** + * @brief 初始化硬件复位引脚 + * 设置为上拉,需要复位,需要输出低电平为20us的脉冲信号 + */ +esp_err_t IOExpansionBoard::ResetGpioInit(gpio_num_t gpio_num) +{ + reset_gpio_ = gpio_num; + + // 配置复位引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + esp_err_t err = gpio_config(&io_conf); + gpio_set_level(gpio_num, 1); // 复位引脚拉高 + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d复位引脚初始化完成", gpio_num); + return err; + } +} + +/** + * @brief 复位IO扩展板 + */ +esp_err_t IOExpansionBoard::ResetIoExpand() +{ + if (reset_gpio_ == GPIO_NUM_NC) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位引脚未初始化"); + return ESP_ERR_INVALID_STATE; + } + + // 复位IO扩展板 + gpio_set_level(reset_gpio_, 0); + esp_rom_delay_us(30); + gpio_set_level(reset_gpio_, 1); + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "复位成功"); + } + return ESP_OK; +} + +/** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::IoexpandWriteReg(uint8_t reg_addr, uint8_t data) +{ + return i2c_bus_write_bytes(bus_handle_, device_addr_, ®_addr, 1, &data, 1); +} + +/** + * @brief 从寄存器读取数据 + * @param reg_addr 寄存器地址(如INPUT_PORT0、ID等) + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果(ESP_OK为成功) + */ +esp_err_t IOExpansionBoard::IoexpandReadReg(uint8_t reg_addr, uint8_t* data) +{ + if (data == nullptr){ // 检查输入参数有效性 + return ESP_ERR_INVALID_ARG; + } + + // 使用i2c_bus_read_bytes进行寄存器读取 + esp_err_t err = i2c_bus_read_bytes(bus_handle_, device_addr_, ®_addr, 1, data, 1); + if (err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "读取寄存器失败,错误码:0x%x", err); + return err; + } + + return ESP_OK; +} + +//设置IO扩展板为输入模式或是输出模式 +/* +* 这里需要根据实际情况设置IO扩展板的模式,比如输入模式还是输出模式,以及各个引脚的配置。 +* P0_0 对应NFC_RST引脚,需要设置为输出模式,低电平有效。(待测) +* P0_1 对应USB_VBUS引脚,需要设置为输出模式,低电平有效。(待测) +* P0_2 对应BTN_RIGHT_EAR引脚,需要设置为输出模式,低电平有效。(待测) +* P0_3 暂时未使用。 +* P0_4 对应步进电机方向引脚,需要设置为输出模式,根据需求设置。(待测) +* P0_5 对应CHRG引脚(待测) +* P0_6 LCD_DC引脚,需要设置为输出模式,根据需求设置电平。(待测) +* P0_7 对应步进电机的使能引脚,需要设置为输出模式,根据需求设置。(待测) +* +* +* P1_0 对应EG800K_PWR。(待测) +* P1_1 对应LCD_RST,需要设置为输出模式,低电平有效。(待测) +* P1_2 对应LCD_CS,需要设置为输出模式,低电平有效。(待测) +* P1_3 暂时未使用。 +* P1_4 对应步进电机的细分模式M1引脚。(待测) +* P1_5 对应步进电机的细分模式M0引脚。(待测) +* P1_6 对应步进电机的睡眠引脚。(待测) +* P1_7 对应RADAR_O雷达的输出引脚。(待测) +* */ +esp_err_t IOExpansionBoard::IoexpandSetMode(void) +{ + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功"); + } + // 配置P0_0-P0_7的端口为输入还是输出:0-输出;1-输入 + // err = IoexpandWriteReg(CONFIG_PORT0, 0x04); // 0000 0100 + err = IoexpandWriteReg(CONFIG_PORT0, 0x24); // 0010 0100 + // err = IoexpandWriteReg(CONFIG_PORT0, 0x2C); // 0010 1100 0-2,0-3,0-5都是输入 + + // D 1101 + // 9 1001 + + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功"); + } + // 配置P1_0-P1_7的端口输出:0-输出;1-输入 + // err = IoexpandWriteReg(CONFIG_PORT1, 0x84); + err = IoexpandWriteReg(CONFIG_PORT1, 0x80); // 1000 0000 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口成功"); + } + // 配置P0_0-P0_7的初始为高电平 + // 配置P1_0-P1_7的初始为高电平 + err = IoexpandWriteReg(OUTPUT_PORT0, 0xFD); // 1111 1101 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值成功"); + } + err = IoexpandWriteReg(OUTPUT_PORT1, 0x7E); // 0111 1110 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值成功"); + } + + err = IoexpandWriteReg(INT_PORT1, 0x7F); // 0111 1111 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能成功"); + } + + return ESP_OK; +} + +/** + * @brief 设置步进电机的细分模式 + */ +void IOExpansionBoard::SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT, uint8_t m0_pin, uint8_t m1_pin) +{ + uint8_t current_val; + switch (mode) { + case 1: //全步输出模式 低低电平 + /* code */ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << m0_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << m1_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 2: //非圆 1/2 高低电平 + /* code */ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << m0_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << m1_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 3: //1/4 步 低高电平 + /* code */ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << m0_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << m1_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 4: //1/8 步 高高电平 + /* code */ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << m0_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << m1_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + default: //全步输入模式 低低电平 + /* code */ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << m0_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << m1_pin); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + } +} + +/** + * @brief 设置步进电机的使能 + */ +esp_err_t IOExpansionBoard::SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin) +{ + uint8_t current_val; + if(enable){ + // 进入工作状态mode + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << enable_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << enable_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} +/** + * @brief 设置步进电机运行方向 + */ +esp_err_t IOExpansionBoard::StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin) +{ + uint8_t current_val; + if(dir){ + // 方向为正转 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/** + * @brief 设置步进电机是否进入睡眠或者工作状态(高电平进入工作状态,低电平进入睡眠状态) + */ +esp_err_t IOExpansionBoard::SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin) +{ + uint8_t current_val; + if(mode){ + // 进入工作状态mode + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << nsleep_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << nsleep_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/*********************************************IO扩展板LCD引脚配置参数***********************************************/ +/** + * @brief 设置 LCD_BL引脚电平(高电平为命令模式,低电平为数据模式) + */ +esp_err_t IOExpansionBoard::SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin) +{ + uint8_t current_val; + if(mode){ + // 进入命令模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << bl_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入数据模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << bl_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/** + * @brief 设置 LCD_RST引脚电平(高电平为复位模式,低电平为工作模式) + */ +esp_err_t IOExpansionBoard::SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t reset_pin) +{ + uint8_t current_val; + if(mode){ + // 进入复位模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << reset_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入工作模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << reset_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/*********************************************IO扩展板的输入引脚配置以及中断引脚定义***********************************************/ +/** + * @brief 设置 毫米波雷达的中断引脚 + */ +esp_err_t IOExpansionBoard::SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin) +{ + uint8_t current_val; + if(mode){ + // 进入输入模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << interrupt_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(INPUT_PORT, current_val); + } + else{ + // 进入输出模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << interrupt_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(INPUT_PORT, current_val); + } +} + +/** + * @brief 设置 LCD_CS引脚电平(低电平为选中状态,高电平为不选中状态) + */ +esp_err_t IOExpansionBoard::SetLcdCsMode(bool mode, uint8_t OUTPUT_PORT, uint8_t cs_pin) +{ + uint8_t current_val; + if(mode){ + // 进入选中状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val &= ~(1 << cs_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入不选中状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val); + current_val |= (1 << cs_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} +/** + * @brief I2C数据读取任务主体 + */ +void IOExpansionBoard::I2cReadTask(void* pvParameters) +{ + IOExpansionBoard* instance = static_cast(pvParameters); + if (!instance) { + vTaskDelete(nullptr); + return; + } + // 初始化复位引脚 + esp_err_t err = instance->ResetGpioInit(IO_EXPAND_RSTN); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO复位初始化失败"); + } + // 初始化IO扩展板子的中断引脚 + err = instance->InterruptGpioInit(GPIO_INPUT_PIN_SEL); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断初始化失败"); + } + // 设置IO扩展板模式 + instance->IoexpandSetMode(); + + // 设置LCD屏幕复位引脚 + err = instance->SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功"); + } + instance->IoexpandWriteReg(OUTPUT_PORT0, 0xff); + uint8_t current_val; + for (;;) { + // 等待中断事件触发 + if (instance->i2c_task_event_group_) { + xEventGroupWaitBits(instance->i2c_task_event_group_, BIT0, pdTRUE, pdFALSE, portMAX_DELAY); + } + // 读取I2C数据 + instance->IoexpandReadReg(INPUT_PORT1,¤t_val); + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "读取数据: 0x%0X", current_val); + if(current_val & (1 << 7)){ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚(P1_7)\n"); + // 调用毫米波雷达回调函数 + if (instance->radar_) { + instance->radar_->TriggerRadarDetectCallback(); + } + } + + // vTaskSuspend(nullptr); // 挂起任务等待下次唤醒 + } +} + +// bool IOExpansionBoard::AllocateStaticTaskMemory() +// { +// printf("IO拓展芯片创建任务前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); +// printf("IO拓展芯片创建任务前 Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +// // 分配任务栈(PSRAM) +// const size_t TASK_STACK_SIZE = 4096; +// pI2CReadTaskStackBuffer = (StackType_t*)heap_caps_malloc( +// TASK_STACK_SIZE * sizeof(StackType_t), +// MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT +// ); + +// if (!pI2CReadTaskStackBuffer) { +// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to allocate task stack from PSRAM"); +// return false; +// } + +// // 分配任务控制块(内部RAM) +// pxI2CReadTaskBuffer = (StaticTask_t*)pvPortMalloc(sizeof(StaticTask_t)); +// if (!pxI2CReadTaskBuffer) { +// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to allocate task TCB from internal RAM"); +// heap_caps_free(pI2CReadTaskStackBuffer); +// pI2CReadTaskStackBuffer = nullptr; +// return false; +// } + +// ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static task memory allocated successfully"); +// printf("IO拓展芯片创建任务后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); +// printf("IO拓展芯片创建任务后 Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +// return true; +// } + +// void IOExpansionBoard::FreeStaticTaskMemory() +// { +// if (pI2CReadTaskStackBuffer != nullptr) { +// heap_caps_free(pI2CReadTaskStackBuffer); +// pI2CReadTaskStackBuffer = nullptr; +// } + +// if (pxI2CReadTaskBuffer != nullptr) { +// vPortFree(pxI2CReadTaskBuffer); +// pxI2CReadTaskBuffer = nullptr; +// } + +// ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static task memory freed"); +// } + +/** + * @brief 创建I2C数据读取任务 + */ +void IOExpansionBoard::CreateI2cReadTask() +{ + printf("创建I2C读取任务之前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之前:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + if (xI2CReadTaskHandle_) { + return; // 任务已创建 + } + + xTaskCreateWithCaps( + I2cReadTask, + "i2c_read_task", + I2C_TASK_STACK, + this, + I2C_TASK_PRIORITY, + &xI2CReadTaskHandle_, + MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT + ); + + if (xI2CReadTaskHandle_ == NULL) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to create static I2C read task"); + } else { + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static I2C read task created successfully"); + } + printf("创建I2C读取任务之后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之后:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +} + +/** + * @brief 启动I2C任务 (整合初始化和任务创建) + */ +esp_err_t IOExpansionBoard::StartTask() +{ + // 再创建任务 + if (!xI2CReadTaskHandle_) { + CreateI2cReadTask(); + } + return ESP_OK; +} diff --git a/main/02_physical/boards/board_v1_1_12/io_expansion_board.h b/main/02_physical/boards/board_v1_1_12/io_expansion_board.h new file mode 100644 index 0000000..0a3f47b --- /dev/null +++ b/main/02_physical/boards/board_v1_1_12/io_expansion_board.h @@ -0,0 +1,284 @@ +#ifndef IO_EXPANSION_BOARD_H +#define IO_EXPANSION_BOARD_H + +#include +#include +#include +#include +#include +#include "i2c_bus.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include +#include +#include +#include +#include +#include +#include +#include "esp_err.h" +#include "config.h" +#include "portmacro.h" + +// 前向声明,避免循环引用 +class MillimeterWaveRadar; + +/* 寄存器地址 */ +#define INPUT_PORT0 0x00 // 输入端口0寄存器 +#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取) +#define OUTPUT_PORT0 0x02 // 输出端口0寄存器 +#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平 +#define CONFIG_PORT0 0x04 // 配置端口0寄存器 +#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式 +#define INT_PORT0 0x06 // 中断端口0寄存器 +#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的) +#define CTL 0x11 // 全局控制寄存器 +#define ID 0x23 // 芯片ID寄存器(0x23) + +/***********************************IO扩展板电机引脚配置参数*************************************/ +/* 设置步进电机方向 */ +#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转 +#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转 +#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4 + +/* 设置步进电机细分模式 */ +#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5 +#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4 +#define STEPPER_MOTOR_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 + + +/* 设置步进电机睡眠引脚 */ +#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式 +#define STEPPER_MOTOR_WORK true //步进电机进入工作模式 +#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6 +#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 + +/* 设置电机的使能引脚 */ +#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7 +#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平 +#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平 + +/* 设置毫米波雷达对应IO扩展板的中断引脚 */ +#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7 +#define RADAR_INTERRUPT_PORT CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口INPUT_PORT1 +#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态 +#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态 +/* 任务配置常量 */ +#define WRITE_BUF_SIZE 2 // I2C单次写入字节数 +#define READ_BUF_SIZE 2 // I2C单次读取字节数 +#define I2C_TASK_PRIORITY 2 // 任务优先级(中等) +#define I2C_TASK_STACK 4096 // 任务栈大小(4KB) + +/***********************************IO扩展板LCD引脚配置参数*************************************/ +/* 设置LCD的BL引脚 */ +#define LCD_BL_PIN 6 //LCD背光引脚 +#define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define LCD_BL_HIGH true //LCD背光引脚状态为高电平 +#define LCD_BL_LOW false //LCD背光引脚状态为低电平 + +/* 设置LCD的RST引脚 */ +#define LCD_RST_PIN 1 //LCD复位引脚 +#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define LCD_RST_HIGH true //LCD复位引脚状态为高电平 +#define LCD_RST_LOW false //LCD复位引脚状态为低电平 + +/* 设置LCD的CS引脚 */ +#define LCD_CS_PIN 2 //LCD片选引脚 +#define LCD_CS_PORT OUTPUT_PORT1 //LCD片选引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define LCD_CS_HIGH true //LCD片选引脚状态为高电平 +#define LCD_CS_LOW false //LCD片选引脚状态为低电平 + +#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签 +#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签 + +// GPIO引脚定义 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚 +#define IO_EXPAND_RSTN GPIO_NUM_45 // IO扩展板复位引脚 + +/** + * @class IOExpansionBoard + * @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作 + */ +class IOExpansionBoard +{ +public: + /** + * @brief 构造函数 + */ + IOExpansionBoard(); + + /** + * @brief 设置毫米波雷达指针 + * @param radar 毫米波雷达对象指针 + */ + void setRadar(MillimeterWaveRadar* radar) { radar_ = radar; }; + + /** + * @brief 析构函数 + */ + ~IOExpansionBoard(); + + /** + * @brief 初始化GPIO中断检测 + * @param gpio_num 中断引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t InterruptGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetIoExpand(); + + /** + * @brief 初始化I2C主机通信 + * @return esp_err_t 初始化结果 + */ + // esp_err_t IoExpansionI2cInit(); + + /** + * @brief 创建I2C数据读取任务 + */ + void CreateI2cReadTask(); + + /** + * @brief 启动I2C任务(整合初始化和任务创建) + * @return esp_err_t 操作结果 + */ + esp_err_t StartTask(); + + /** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data); + + /** + * @brief 读寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要读出的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data); + + // /** + // * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断 + // * @param reg_addr 寄存器地址 + // * @return esp_err_t 操作结果 + // */ + // esp_err_t SetInterruptStatus(bool status); + + /** + * @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandSetMode(); + + /** + * @brief 设置步进电机的细分模式 + * @param mode 模式:1/2/4/8/16/32/64 + * @return esp_err_t 操作结果 + */ + void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT, uint8_t m0_pin, uint8_t m1_pin); + + /** + * @brief 设置步进电机的方向 + * @param dir 方向 + * @param OUTPUT_PORT 输出端口 + * @param pin 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin); + + /** + * @brief 设置步进电机的睡眠模式 + * @param 是否进入睡眠模式 + * @param 输出端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin); + + /** + * @brief 设置步进电机的使能引脚状态 + * @param 使能状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin); + + /** + * @brief 设置LCD的BL引脚状态 + * @param BL状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin); + + /** + * @brief 设置LCD的RST引脚状态 + * @param RST状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin); + + /** + * @brief 设置LCD的CS引脚状态 + * @param CS状态(低电平为选中状态,高电平为不选中状态) + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdCsMode(bool mode, uint8_t OUTPUT_PORT, uint8_t cs_pin); + + /** + * @brief 设置雷达中断引脚 + * @param 毫米波雷达的中断引脚模式 + * @param 输入端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin); + + // 公共成员变量 + i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄 + uint8_t device_addr_; // I2C设备地址 + +private: + // 静态成员函数 + MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调 + static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数 + static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数 + + // /** + // * @brief 分配静态任务所需的内存 + // * @return bool 分配是否成功 + // */ + // bool AllocateStaticTaskMemory(); + + // /** + // * @brief 释放静态任务分配的内存 + // */ + // void FreeStaticTaskMemory(); + + // 实例成员变量 + EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组 + TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄 + bool is_initialized_ = false; // 初始化状态标记(新增) + gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚 + gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚 + + // StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM) + // StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM) +}; + +#endif \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_13/board_sweekar.cc b/main/02_physical/boards/board_v1_1_13/board_sweekar.cc new file mode 100644 index 0000000..88a1db3 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_13/board_sweekar.cc @@ -0,0 +1,311 @@ +/** + * @file board.cc + * @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +extern "C" { +#include "esp_log.h" +#include "driver/gpio.h" +#include "driver/uart.h" +#include "driver/ledc.h" +#include "driver/gptimer.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "hal/gpio_types.h" +#include "hal/uart_types.h" +#include "esp_check.h" +#include "sdkconfig.h" +#include "i2c_bus.h" +} + +#include "board_sweekar.h" +#include "config.h" +#define TAG "board_sweekar" + +/*========================== 步进电机相关驱动 ==========================*/ + +/** + * @brief 步进电机初始化函数 + * 配置步进电机所需的GPIO引脚模式,通过IO扩展板设置步进驱动芯片的工作模式 + * 在 stepper_motor.cc 中完成 GPTimer + GPIO 翻转 STEP 脉冲的初始化 + */ +void BoardSweekar::StepperMotorInit(void) +{ + esp_err_t err = ESP_OK; + + // 1) STEP 引脚改为普通 GPIO(不再用 LEDC) + gpio_config_t io_cfg; + io_cfg.pin_bit_mask = 1ULL << STEPPER_STEP_IO; + io_cfg.mode = GPIO_MODE_OUTPUT; + io_cfg.pull_up_en = GPIO_PULLUP_DISABLE; + io_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_cfg.intr_type = GPIO_INTR_DISABLE; + err = gpio_config(&io_cfg); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "步进电机 STEP GPIO 配置失败, 错误码: 0x%x", err); + } + + // 初始电平拉低,保证上电不乱跳 + gpio_set_level(STEPPER_STEP_IO, 0); + + // 2) 检查 I2C 总线是否已初始化 + if (bus_handle_ == nullptr) + { + ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()"); + return; + } + + // 3) 通过 IO 扩展板配置步进驱动芯片:睡眠/使能/细分/方向 + err = io_expansion_.SetMotorSleepMode( + STEPPER_MOTOR_WORK, + STEPPER_MOTOR_SLEEP_PORT, + STEPPER_MOTOR_WORK + ); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "步进电机睡眠模式配置失败, 错误码: 0x%x", err); + } + + err = io_expansion_.SetMotorEnableMode( + STEPPER_MOTOR_ENABLE_DISABLE, + STEPPER_MOTOR_ENABLE_PORT, + STEPPER_MOTOR_ENABLE_PIN + ); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "步进电机使能配置失败, 错误码: 0x%x", err); + } + + // 细分设置:这里仍然用原来的 1/8 细分 + io_expansion_.SetStepperMicrostepMode( + 4, + STEPPER_MOTOR_M0_MADE_PORT, + STEPPER_MOTOR_M0_PIN, + STEPPER_MOTOR_M1_MADE_PORT, + STEPPER_MOTOR_M1_PIN + ); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "步进电机细分模式配置失败, 错误码: 0x%x", err); + } + + // 默认方向先设一个(比如“上升”方向) + err = io_expansion_.StepperMotorSetDir( + STEPPER_MOTOR_LEFT, + STEPPER_MOTOR_DIR_PORT, + STEPPER_MOTOR_DIR_PIN + ); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "步进电机方向配置失败, 错误码: 0x%x", err); + } +} + +/*========================== 毫米波雷达相关驱动 ==========================*/ + +/** + * @brief 毫米波雷达串口初始化函数 + * + * 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚, + * 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免 + * 与自定义中断冲突。 + */ +void BoardSweekar::MillimeterWaveRadarUartInit(void) +{ + uart_config_t uart_config = { + .baud_rate = RADAR_BAUD_RATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + }; + + // 1. 设置串口参数 + ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config)); + + // 2. 设置 UART 引脚 + ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突) + // 增加 RX/TX FIFO 深度以处理突发数据 + ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4, + 0, NULL, 0)); +} + +/** + * @brief 毫米波雷达中断引脚初始化函数 + * + * 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能 + * (如需使用中断需单独进行配置)。 + */ +void BoardSweekar::MillimeterWaveRadarGpioInit(void) +{ + // GPIO配置结构体 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚 + .mode = GPIO_MODE_INPUT, // 设置为输入模式 + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉 + .intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置) + }; + + // 配置GPIO + gpio_config(&io_conf); +} + +/*========================== I2C总线及挂载的从设备相关驱动 ==========================*/ + +/** + * @brief I2C总线及从机设备初始化函数 + * + * 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。 + * 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。 + * 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。 + * + * @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因 + */ +esp_err_t BoardSweekar::I2CMasterInit(void) +{ + static const char *I2C_INIT = "I2C_INIT"; + + // 初始化IO扩展板复位引脚 + gpio_config_t reset_io_conf = { + .pin_bit_mask = (1ULL << IO_EXPAND_RSTN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉 + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&reset_io_conf); + + // 执行复位时序:先拉低100ms,再拉高并等待100ms + gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms + gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + + ESP_LOGI(I2C_INIT, "IO扩展板复位完成"); + + // 创建统一的I2C总线(使用ESP-ADF的i2c_bus) + i2c_config_t i2c_cfg = { + .mode = I2C_MODE_MASTER, + .sda_io_num = I2C0_MASTER_SDA_IO, + .scl_io_num = I2C0_MASTER_SCL_IO, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master = { + .clk_speed = 100000, + }, + }; + + // 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线) + bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg); + if (bus_handle_ == NULL) { + ESP_LOGE(TAG, "Failed to create I2C bus"); + return ESP_FAIL; + } + + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + // ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信 + + // 验证线性马达设备是否存在 + esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR); + } + // 验证IO扩展板设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err); + // 不返回错误,继续初始化其他设备 + } else { + ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR); + } + // 验证陀螺仪设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR); + } + + // 为IO扩展板设置总线句柄和设备地址(使用7位地址) + io_expansion_.bus_handle_ = bus_handle_; + io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1; + + // 为线性马达设置总线句柄和设备地址(使用7位地址) + linear_motor_.bus_handle_ = bus_handle_; + linear_motor_.device_addr_ = LINEAR_MOTOR_I2C_SLAVE_ADDR << 1; + + ESP_LOGI(I2C_INIT, "I2C总线初始化完成"); + return ESP_OK; +} + +/*========================== VBAT to VBAT_5V相关驱动 ==========================*/ + +/** + * @brief 开启VBAT to VBAT_5V + * + * 创建开启升压的电源管理单元 + * + */ +void BoardSweekar::VbatToVbat5vInit(void) +{ + // 配置VBAT_5V引脚为输出模式 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << VBAT_5V_PIN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&io_conf); + // 使能VBAT_5V + gpio_set_level(VBAT_5V_PIN, 1); +} + +/*========================== 底座控制串口相关驱动 ==========================*/ + +/** + * @brief 底座控制命令串口初始化函数 + */ +void BoardSweekar::BaseBoardControlUartInit(void) +{ + uart_config_t uart_config = { + .baud_rate = BASE_BOARD_CTL_UART_BAUDRATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + }; + + // 1. 设置串口参数 + ESP_ERROR_CHECK(uart_param_config(BASE_BOARD_CTL_UART_PORT, &uart_config)); + + // 2. 设置 UART 引脚 + ESP_ERROR_CHECK(uart_set_pin(BASE_BOARD_CTL_UART_PORT, BASE_BOARD_CTL_UART_TX_PIN, BASE_BOARD_CTL_UART_RX_PIN, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 3. 安装 UART 驱动 + ESP_ERROR_CHECK(uart_driver_install(BASE_BOARD_CTL_UART_PORT, + BASE_BOARD_CTL_UART_BUF_SIZE, + BASE_BOARD_CTL_UART_BUF_SIZE, + 0, NULL, 0)); + + base_board_control_.SetUartPort(BASE_BOARD_CTL_UART_PORT); +} + + + diff --git a/main/02_physical/boards/board_v1_1_13/board_sweekar.h b/main/02_physical/boards/board_v1_1_13/board_sweekar.h new file mode 100644 index 0000000..ba6e3c4 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_13/board_sweekar.h @@ -0,0 +1,45 @@ +#ifndef __BOARD_H__ +#define __BOARD_H__ +#include "config.h" +#include "io_expansion_board.h" +#include "stepper_motor.h" +#include "i2c_bus.h" +#include "gyroscope.h" +#include "touch_sensor.h" +#include "base_board_control.h" + +class BoardSweekar +{ +private: + i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄 + +public: + IOExpansionBoard io_expansion_; // IO扩展板对象 + LinearMotor linear_motor_; // 线性马达对象 + Gyroscope gyroscope_; // 陀螺仪对象 + TouchSensor touch_sensor_; // 触摸传感器对象 + BaseBoardControl base_board_control_; // 底座控制对象 + + + // 初始化步进电机 + void StepperMotorInit(void); + + // 初始化串口 + void MillimeterWaveRadarUartInit(void); + + //初始化毫米波雷达的中断引脚 + void MillimeterWaveRadarGpioInit(void); + + // 初始化I2C总线 + esp_err_t I2CMasterInit(void); + + // 初始化VBAT toVBAT_5V引脚 + void VbatToVbat5vInit(void); + + // 初始化底座控制串口 + void BaseBoardControlUartInit(void); + + // 获取I2C总线句柄 + i2c_bus_handle_t GetBusHandle() const { return bus_handle_; } +}; +#endif diff --git a/main/02_physical/boards/board_v1_1_13/config.h b/main/02_physical/boards/board_v1_1_13/config.h new file mode 100644 index 0000000..525c6d3 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_13/config.h @@ -0,0 +1,145 @@ +/* 定义引脚分配 */ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +/** + * @file config.h + * @brief 定义了引脚的分配。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +#include "driver/gpio.h" +#include "driver/i2c_master.h" +#include "driver/i2s.h" +#include "esp_log.h" +#include "esp_rom_sys.h" // 用于 esp_rom_delay_us +#include "esp_timer.h" +#include "esp_mac.h" +#include "driver/ledc.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "driver/timer.h" +#include "esp_intr_alloc.h" +#include "soc/timer_group_struct.h" // 包含TIMERG0、TIMERG1的结构体定义 +#include "soc/timer_group_reg.h" // 包含定时器相关寄存器宏定义 +#include "driver/uart.h" +#include "esp_err.h" +#include "freertos/queue.h" +#include "soc/uart_reg.h" +#include "linear_motor.h" +#include "gyroscope.h" + +#define TAG_BOARD "SWEEKAR_ESP32" +/*I2C总线引脚定义*/ +#define I2C0_MASTER_PORT I2C_NUM_0 +#define I2C0_MASTER_SDA_IO GPIO_NUM_2 +#define I2C0_MASTER_SCL_IO GPIO_NUM_3 + +/* 步进电机配置 */ +#define STEPPER_STEP_IO GPIO_NUM_42 // 步进电机脉冲输入引脚 +#define STEPPER_TIMER_RES_HZ 1000000 // 步进电机定时器分辨率 1 MHz(1 us 步进) + +/* 定义屏幕驱动控制引脚 */ +#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚 +#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL +#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚 +#define ST7789_PIN_CS GPIO_NUM_46 // SPI片选引脚 +#define ST7789_PIN_BL GPIO_NUM_NC // 背光引脚 +#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚 +#define LCD_BL_ACTIVE_LEVEL 0 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS) + +#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数) +#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数) + +/* 毫米波雷达配置参数 */ +/* 定义毫米波雷达的中断引脚 */ +#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35 +// UART 配置参数 +#define RADAR_UART_NUM UART_NUM_1 // 使用 UART1 +#define UART_TX_PIN GPIO_NUM_40 // GPIO40 作为 TX(根据实际硬件连接调整) +#define UART_RX_PIN GPIO_NUM_39 // GPIO39 作为 RX +#define RADAR_BAUD_RATE 9600 // 雷达波特率 +#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小 + +/* IO扩展硬件配置常量 */ +#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000) +#define I2C_IO_EXPAND_SLAVE_ADDR 0x58 // AW9523BTQR器件地址,v1_1_13的addr1和addr0是0 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚 +#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值 +#define IO_EXPAND_RSTN GPIO_NUM_45 // IO扩展板复位引脚 + +/* 定义线性马达的I2C从机配置常量 */ +#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址 + +/* 定义陀螺仪的I2C从机配置常量 */ +#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址 +#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚 + +/* 原生触摸引脚配置 */ +// 触摸按键数量配置 +#define TOUCH_BUTTON_NUM 3 +// 触摸通道定义 +#define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11 +#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12 +#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13 + +/* ES8311音频编解码器配置 (ESP-ADF兼容) */ +#define AUDIO_INPUT_SAMPLE_RATE 24000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 +#define AUDIO_INPUT_REFERENCE true + +/* I2S GPIO定义 */ +#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15 +#define AUDIO_I2S_GPIO_WS GPIO_NUM_4 +#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5 +#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6 +#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7 + +/* PA引脚定义 */ +#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC + +/* I2C配置 */ +#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2 +#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3 +#define AUDIO_CODEC_ES8311_ADDR 0x18 +#define AUDIO_CODEC_ES7210_ADDR 0x40 + +/* WS2812 RGB LED配置 */ +#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚 +#define WS2812_NUM_LEDS 2 // WS2812 LED数量 + +/* 创建VBAT to VBAT_5V */ +#define VBAT_5V_PIN GPIO_NUM_NC // VBAT_5V引脚 + +/* 定义按键的中断引脚 */ +#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚 +#define RIGHT_BUTTON_PIN GPIO_NUM_8 // 按键中断引脚 + +/* 底座控制命令串口配置 */ +#define BASE_BOARD_CTL_UART_PORT UART_NUM_0 +#define BASE_BOARD_CTL_UART_TX_PIN GPIO_NUM_43 +#define BASE_BOARD_CTL_UART_RX_PIN GPIO_NUM_44 +#define BASE_BOARD_CTL_UART_BAUDRATE 115200 +#define BASE_BOARD_CTL_UART_BUF_SIZE 256 + +#endif // _BOARD_CONFIG_H_ + + + + + + + + + + + + + + + + diff --git a/main/02_physical/boards/board_v1_1_13/io_expansion_board.cc b/main/02_physical/boards/board_v1_1_13/io_expansion_board.cc new file mode 100644 index 0000000..dc31200 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_13/io_expansion_board.cc @@ -0,0 +1,1053 @@ +#include "io_expansion_board.h" +#include "millimeter_wave_radar.h" +#include "photo_interrupter.h" +#include "adc_battery_monitor.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_check.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/idf_additions.h" +#include "freertos/portable.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_rom_sys.h" +/** + * @file io_expansion_board.cc + * @brief IO扩展板功能实现类,包含I2C通信、GPIO中断配置、外设控制等功能 + * @details 实现了IO扩展板的初始化(中断引脚、复位引脚)、寄存器读写、步进电机控制(细分模式、使能、方向、睡眠状态)、 + * LCD相关引脚控制(背光、复位、片选)、毫米波雷达中断引脚配置等功能,并提供I2C数据读取任务的创建与管理 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +/** + * @brief 构造函数 + */ +IOExpansionBoard::IOExpansionBoard() + : bus_handle_(nullptr), + device_addr_(0), + last_port0_state_(0), + last_port1_state_(0), + radar_last_state_(false), + i2c_task_event_group_(nullptr), + xI2CReadTaskHandle_(nullptr), + is_initialized_(false), + interrupt_gpio_(GPIO_NUM_NC), + reset_gpio_(GPIO_NUM_NC) +{ +} + +/** + * @brief 析构函数 + */ +IOExpansionBoard::~IOExpansionBoard() +{ + // 删除任务 + if (xI2CReadTaskHandle_) { + vTaskDelete(xI2CReadTaskHandle_); + } + + // if(pI2CReadTaskStackBuffer) { + // heap_caps_free(pI2CReadTaskStackBuffer); + // pI2CReadTaskStackBuffer = nullptr; + // } + + // if(pxI2CReadTaskBuffer) { + // vPortFree(pxI2CReadTaskBuffer); + // pxI2CReadTaskBuffer = nullptr; + // } + + // 删除事件组 + if (i2c_task_event_group_) { + vEventGroupDelete(i2c_task_event_group_); + } + + // 移除中断处理 + if (interrupt_gpio_ != GPIO_NUM_NC) { + gpio_isr_handler_remove(interrupt_gpio_); + } + + // 删除IO扩展板设备 + // 使用i2c_bus API时不需要手动删除设备句柄 + // bus_handle_由board_sweekar统一管理 +} + +/** + * @brief 静态中断处理函数 + */ +void IRAM_ATTR IOExpansionBoard::GpioIsrHandler(void* arg) +{ + IOExpansionBoard* instance = static_cast(arg); + if (!instance) return; + + // 调试:记录中断触发 + // ESP_EARLY_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "中断触发!"); // IRAM函数中不能使用普通日志 + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // 设置事件标志位 + if (instance->i2c_task_event_group_) { + xEventGroupSetBitsFromISR( + instance->i2c_task_event_group_, + BIT0, + &xHigherPriorityTaskWoken + ); + } + + // 触发上下文切换 + if (xHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); + } +} + +/** + * @brief 初始化GPIO中断检测 + */ +esp_err_t IOExpansionBoard::InterruptGpioInit(gpio_num_t gpio_num) +{ + // 配置IO扩展板中断引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_ANYEDGE; // 改为双沿触发,检测上升沿和下降沿 + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + // io_conf.pull_up_en = GPIO_PULLUP_DISABLE; + // io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE; + + + esp_err_t err = gpio_config(&io_conf); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + // 配置中断服务 + err = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3); + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断服务安装失败,错误码: 0x%x", err); + return err; + } + // 注册中断处理函数 + err = gpio_isr_handler_add(gpio_num, GpioIsrHandler, this); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断处理函数添加失败,错误码: 0x%x", err); + return err; + } + // 创建事件组 + i2c_task_event_group_ = xEventGroupCreate(); + if (!i2c_task_event_group_) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "事件组创建失败"); + return ESP_FAIL; + } + + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d中断初始化完成", gpio_num); + return ESP_OK; +} + +/** + * @brief 初始化硬件复位引脚 + * 设置为上拉,需要复位,需要输出低电平为20us的脉冲信号 + */ +esp_err_t IOExpansionBoard::ResetGpioInit(gpio_num_t gpio_num) +{ + reset_gpio_ = gpio_num; + + // 配置复位引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + esp_err_t err = gpio_config(&io_conf); + gpio_set_level(gpio_num, 1); // 复位引脚拉高 + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d复位引脚初始化完成", gpio_num); + return err; + } +} + +/** + * @brief 计算Port0的字节值,用于配置输入还是输出模式(0为输出模式,1为输入模式) + * @return uint8_t 操作结果 + */ +uint8_t IOExpansionBoard::ByteCalculatePort0() +{ + uint8_t byte_val = 0x00; // 初始化为所有引脚为输出模式(0),然后根据配置设置为输入模式(1) + + // 输入模式配置:将对应位置位(1为输入模式) + if(RADAR_INTERRUPT_CONFIG == CONFIG_PORT0){ //雷达中断引脚 + byte_val |= (1 << RADAR_INTERRUPT_PIN); + } + if(START_PHOTO_INTERRUPTER_CONFIG == CONFIG_PORT0){ //起始光学传感器 + byte_val |= (1 << START_PHOTO_INTERRUPTER_PIN); + } + if(END_PHOTO_INTERRUPTER_PORT_CONFIG == CONFIG_PORT0){ //结束光学传感器 + byte_val |= (1 << END_PHOTO_INTERRUPTER_PIN); + } + if(BATTERY_FULL_CONFIG == CONFIG_PORT0){ //电池充满检测 + byte_val |= (1 << BATTERY_FULL_PIN); + } + if(BATTERY_CHRG_CONFIG == CONFIG_PORT0){ //电池充电检测 + byte_val |= (1 << BATTERY_CHRG_PIN); + } + + return byte_val; +} + +/** + * @brief 计算Port1的字节值,用于配置输入还是输出模式(0为输出模式,1为输入模式) + * @return uint8_t 操作结果 + */ +uint8_t IOExpansionBoard::ByteCalculatePort1() +{ + uint8_t byte_val = 0x00; // 初始化为所有引脚为输出模式(0),然后根据配置设置为输入模式(1) + + // 输入模式配置:将对应位置位(1为输入模式) + if(RADAR_INTERRUPT_CONFIG == CONFIG_PORT1){ //雷达中断引脚 + byte_val |= (1 << RADAR_INTERRUPT_PIN); + } + if(START_PHOTO_INTERRUPTER_CONFIG == CONFIG_PORT1){ //起始光学传感器 + byte_val |= (1 << START_PHOTO_INTERRUPTER_PIN); + } + if(END_PHOTO_INTERRUPTER_PORT_CONFIG == CONFIG_PORT1){ //结束光学传感器 + byte_val |= (1 << END_PHOTO_INTERRUPTER_PIN); + } + if(BATTERY_FULL_CONFIG == CONFIG_PORT1){ //电池充满检测 + byte_val |= (1 << BATTERY_FULL_PIN); + } + if(BATTERY_CHRG_CONFIG == CONFIG_PORT1){ //电池充电检测 + byte_val |= (1 << BATTERY_CHRG_PIN); + } + + return byte_val; +} + +/** + * @brief 复位IO扩展板 + */ +esp_err_t IOExpansionBoard::ResetIoExpand() +{ + if (reset_gpio_ == GPIO_NUM_NC) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位引脚未初始化"); + return ESP_ERR_INVALID_STATE; + } + + // 复位IO扩展板 + gpio_set_level(reset_gpio_, 0); + esp_rom_delay_us(30); + gpio_set_level(reset_gpio_, 1); + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "复位成功"); + } + return ESP_OK; +} + +/** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::IoexpandWriteReg(uint8_t reg_addr, uint8_t data) +{ + return i2c_bus_write_bytes(bus_handle_, device_addr_, ®_addr, 1, &data, 1); +} + +/** + * @brief 从寄存器读取数据 + * @param reg_addr 寄存器地址(如INPUT_PORT0、ID等) + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果(ESP_OK为成功) + */ +esp_err_t IOExpansionBoard::IoexpandReadReg(uint8_t reg_addr, uint8_t* data) +{ + if (data == nullptr){ // 检查输入参数有效性 + return ESP_ERR_INVALID_ARG; + } + + // 使用i2c_bus_read_bytes进行寄存器读取 + esp_err_t err = i2c_bus_read_bytes(bus_handle_, device_addr_, ®_addr, 1, data, 1); + if (err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "读取寄存器失败,错误码:0x%x", err); + return err; + } + + return ESP_OK; +} + +/** + * @brief 读取输入端口0寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::ReadInputPort0(uint8_t* data) +{ + return IoexpandReadReg(INPUT_PORT0, data); +} + +/** + * @brief 读取输入端口1寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::ReadInputPort1(uint8_t* data) +{ + return IoexpandReadReg(INPUT_PORT1, data); +} + +//设置IO扩展板为输入模式或是输出模式 +/* +* 这里需要根据实际情况设置IO扩展板的模式,比如输入模式还是输出模式,以及各个引脚的配置。 +* P0_0 对应NFC_RST引脚,需要设置为输出模式,低电平有效。(待测) +* P0_1 对应USB_VBUS引脚,需要设置为输出模式,低电平有效。(待测) +* P0_2 对应BTN_RIGHT_EAR引脚,需要设置为输出模式,低电平有效。(待测) +* P0_3 暂时未使用。 +* P0_4 对应步进电机方向引脚,需要设置为输出模式,根据需求设置。(待测) +* P0_5 对应CHRG引脚(待测) +* P0_6 LCD_DC引脚,需要设置为输出模式,根据需求设置电平。(待测) +* P0_7 对应步进电机的使能引脚,需要设置为输出模式,根据需求设置。(待测) +* +* +* P1_0 对应EG800K_PWR。(待测) +* P1_1 对应LCD_RST,需要设置为输出模式,低电平有效。(待测) +* P1_2 对应LCD_CS,需要设置为输出模式,低电平有效。(待测) +* P1_3 暂时未使用。 +* P1_4 对应步进电机的细分模式M1引脚。(待测) +* P1_5 对应步进电机的细分模式M0引脚。(待测) +* P1_6 对应步进电机的睡眠引脚。(待测) +* P1_7 对应RADAR_O雷达的输出引脚。(待测) +* */ +esp_err_t IOExpansionBoard::IoexpandSetMode(void) +{ + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功"); + } + + err = IoexpandWriteReg(CONFIG_PORT0, ByteCalculatePort0()); + + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + // 打印BytecalculatePort0()结果 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功, 0x%02X", ByteCalculatePort0()); + } + + err = IoexpandWriteReg(CONFIG_PORT1, ByteCalculatePort1()); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口失败,错误码:0x%x", err); + return err; + } + else{ + // 打印BytecalculatePort1()结果 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口成功, 0x%02X", ByteCalculatePort1()); + } + // 配置P0_0-P0_7的初始为高电平 + // 配置P1_0-P1_7的初始为高电平 + err = IoexpandWriteReg(OUTPUT_PORT0, 0x40); // 0100 0000 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值成功"); + } + err = IoexpandWriteReg(OUTPUT_PORT1, 0x04); // 0000 0100 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值成功"); + } + + + // AW9523B中断使能配置:0为使能中断,1为禁止中断 + // 使能P0_5(充电检测)和P1_3(充满检测)的中断 + uint8_t int_enable_port0 = 0x00; // 0x00 = 使能所有P0引脚中断 + uint8_t int_enable_port1 = 0x00; // 0x00 = 使能所有P1引脚中断 + + err = IoexpandWriteReg(INT_PORT0, int_enable_port0); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口中断使能失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口中断使能成功: 0x%02X (0=使能)", int_enable_port0); + } + + err = IoexpandWriteReg(INT_PORT1, int_enable_port1); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能成功: 0x%02X (0=使能)", int_enable_port1); + } + + return ESP_OK; +} + +/** + * @brief 设置步进电机的细分模式 + */ +void IOExpansionBoard::SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin) +{ + uint8_t current_val; + switch (mode) { + case 1: //全步输出模式 低低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 2: //非圆 1/2 高低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val |= (1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 3: //1/4 步 低高电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val |= (1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 4: //1/8 步 高高电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val |= (1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val |= (1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + default: //全步输入模式 低低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + } +} + +/** + * @brief 设置步进电机的使能 + */ +esp_err_t IOExpansionBoard::SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin) +{ + uint8_t current_val; + if(enable){ + // 进入工作状态mode + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << enable_pin); + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << enable_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} +/** + * @brief 设置步进电机运行方向 + */ +esp_err_t IOExpansionBoard::StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin) +{ + uint8_t current_val; + if(dir){ + // 方向为正转 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/** + * @brief 设置步进电机是否进入睡眠或者工作状态(高电平进入工作状态,低电平进入睡眠状态) + */ +esp_err_t IOExpansionBoard::SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin) +{ + uint8_t current_val; + if(mode){ + // 进入工作状态mode + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << nsleep_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << nsleep_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/*********************************************IO扩展板LCD引脚配置参数***********************************************/ +/** + * @brief 设置 LCD_BL引脚电平(高电平为命令模式,低电平为数据模式) + */ +esp_err_t IOExpansionBoard::SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin) +{ + uint8_t current_val; + if(mode){ + // 进入命令模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << bl_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入数据模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << bl_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/** + * @brief 设置 LCD_RST引脚电平(高电平为复位模式,低电平为工作模式) + */ +esp_err_t IOExpansionBoard::SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t reset_pin) +{ + uint8_t current_val; + if(mode){ + // 进入复位模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << reset_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入工作模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << reset_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/*********************************************IO扩展板的输入引脚配置以及中断引脚定义***********************************************/ +/** + * @brief 设置 毫米波雷达的中断引脚 + */ +esp_err_t IOExpansionBoard::SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin) +{ + uint8_t current_val; + if(mode){ + // 进入输入模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + current_val |= (1 << interrupt_pin); + return IoexpandWriteReg(INPUT_PORT, current_val); + } + else{ + // 进入输出模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + current_val &= ~(1 << interrupt_pin); + return IoexpandWriteReg(INPUT_PORT, current_val); + } +} + +/** + * @brief 设置 PA_CTRL引脚电平 + */ +esp_err_t IOExpansionBoard::SetPaCtrlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t pa_ctrl_pin) +{ + uint8_t current_val; + if(mode){ + // 进入高电平状态 + ESP_LOGI("io_ex:", "read reg"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << pa_ctrl_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入低电平状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << pa_ctrl_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + + +/** + * @brief I2C数据读取任务主体 + */ +void IOExpansionBoard::I2cReadTask(void* pvParameters) +{ + IOExpansionBoard* instance = static_cast(pvParameters); + if (!instance) { + vTaskDelete(nullptr); + return; + } + // 初始化复位引脚 + esp_err_t err = instance->ResetGpioInit(IO_EXPAND_RSTN); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO复位初始化失败"); + } + + // 执行硬件复位 - 这是解决中断引脚持续拉低的关键 + err = instance->ResetIoExpand(); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板硬件复位失败"); + } else { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板硬件复位成功"); + + // 检查复位后的中断引脚状态 + int interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "复位后中断引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + } + + // 初始化IO扩展板子的中断引脚 + err = instance->InterruptGpioInit(GPIO_INPUT_PIN_SEL); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断初始化失败"); + } + // 设置IO扩展板模式 - 复位后必须重新配置寄存器! + err = instance->IoexpandSetMode(); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板模式配置失败"); + } else { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板模式配置成功"); + } + // 设置LCD屏幕背光引脚(初始为关闭) + err = instance->SetLcdBlMode(LCD_BL_HIGH, LCD_BL_PORT, LCD_BL_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕背光引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕背光引脚成功"); + } + // 设置LCD屏幕复位引脚 + err = instance->SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功"); + } + // 设置LCD屏幕复位引脚为低电平 + err = instance->SetLcdResetMode(LCD_RST_LOW, LCD_RST_PORT, LCD_RST_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功"); + } + + uint8_t current_val_port0_ = 0,current_val_port1_ = 0,current_temp_ = 0; + for (;;) { + // 等待中断事件触发 + if (instance->i2c_task_event_group_) { + xEventGroupWaitBits(instance->i2c_task_event_group_, BIT0, pdTRUE, pdFALSE, portMAX_DELAY); + } + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板中断触发"); + + // 检查中断触发时的引脚状态 + int interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "中断触发时引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + + // AW9523B中断处理说明(根据数据手册): + // 1. 当输入引脚状态变化时,AW9523B会拉低INT引脚(连接到ESP32的GPIO10) + // 2. 通过读取输入端口寄存器(00H, 01H)来清除对应端口的中断 + // 3. 无独立的中断状态寄存器,需要通过输入电平变化来判断中断源 + // 4. 读取INPUT_PORT0 (00H) 清除P0口中断,读取INPUT_PORT1 (01H) 清除P1口中断 + + // 一次性读取两个端口的输入寄存器,避免重复读取和错误的OR操作 + instance->IoexpandReadReg(INPUT_PORT0, ¤t_val_port0_); + instance->IoexpandReadReg(INPUT_PORT1, ¤t_val_port1_); + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "读取端口状态 - Port0: 0x%02X, Port1: 0x%02X", current_val_port0_, current_val_port1_); + + // 检查读取寄存器后中断引脚是否被清除(应该恢复高电平) + interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "读取寄存器后中断引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + + //判断是否有中断来自雷达引脚 + if((RADAR_INTERRUPT_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << RADAR_INTERRUPT_PIN))){ + // 检查雷达引脚状态是否发生了变化,避免重复触发 + bool current_radar_state = (current_val_port0_ & (1 << RADAR_INTERRUPT_PIN)) != 0; + if (current_radar_state != instance->radar_last_state_) { + instance->radar_last_state_ = current_radar_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用毫米波雷达回调函数 + if (instance->radar_) { + instance->radar_->TriggerRadarDetectCallback(); + } + // 调用雷达回调函数(新接口) + if (instance->radar_callback_) { + instance->radar_callback_(); + } + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((RADAR_INTERRUPT_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << RADAR_INTERRUPT_PIN))){ + // 检查雷达引脚状态是否发生了变化,避免重复触发 + bool current_radar_state = (current_val_port1_ & (1 << RADAR_INTERRUPT_PIN)) != 0; + if (current_radar_state != instance->radar_last_state_) { + instance->radar_last_state_ = current_radar_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚1\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用毫米波雷达回调函数 + if (instance->radar_) { + instance->radar_->TriggerRadarDetectCallback(); + } + // 调用雷达回调函数(新接口) + if (instance->radar_callback_) { + instance->radar_callback_(); + } + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + // else{ + // ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "未检测到雷达引脚中断\n"); + // } + + //判断是否有中断来自初始光学传感器引脚 + if((START_PHOTO_INTERRUPTER_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << START_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port0_ & (1 << START_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port0_state_ & (1 << START_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自初始光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用初始光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerStartCallback(); + } + // 调用光学传感器开始回调函数(新接口) + if (instance->photo_start_callback_) { + instance->photo_start_callback_(); + } + // 更新状态 + instance->last_port0_state_ = current_val_port0_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((START_PHOTO_INTERRUPTER_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << START_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port1_ & (1 << START_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port1_state_ & (1 << START_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自初始光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用初始光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerStartCallback(); + } + // 调用光学传感器开始回调函数(新接口) + if (instance->photo_start_callback_) { + instance->photo_start_callback_(); + } + // 更新状态 + instance->last_port1_state_ = current_val_port1_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + // else{ + // // ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "未检测到初始光学传感器引脚中断\n"); + // } + + //判断是否有中断来自结束光学传感器引脚 + if((END_PHOTO_INTERRUPTER_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << END_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port0_ & (1 << END_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port0_state_ & (1 << END_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自结束光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用结束光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerEndCallback(); + } + // 调用光学传感器结束回调函数(新接口) + if (instance->photo_end_callback_) { + instance->photo_end_callback_(); + } + // 更新状态 + instance->last_port0_state_ = current_val_port0_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((END_PHOTO_INTERRUPTER_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << END_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port1_ & (1 << END_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port1_state_ & (1 << END_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自结束光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用结束光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerEndCallback(); + } + // 调用光学传感器结束回调函数(新接口) + if (instance->photo_end_callback_) { + instance->photo_end_callback_(); + } + // 更新状态 + instance->last_port1_state_ = current_val_port1_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + + //CHRG引脚充电前为高电平 充电中为低电平 充满电为高电平 + //FULL未充满为高电平 充满电为低电平 + //判断是否有中断来自电池充电引脚 + //根据配置:BATTERY_CHRG_INPUT = INPUT_PORT0, BATTERY_FULL_INPUT = INPUT_PORT1 + + // AW9523B没有独立的中断状态寄存器,需要通过比较前后状态变化来判断中断源 + // 由于读取输入端口会清除中断,我们需要先保存当前状态,然后与上次状态比较 + + //获取当前电池状态 + bool current_charging_state = !(current_val_port0_ & (1 << BATTERY_CHRG_PIN)); // CHRG低电平表示充电中 + bool current_full_state = !(current_val_port1_ & (1 << BATTERY_FULL_PIN)); // FULL低电平表示已充满 + + // 详细的调试信息 + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - Port0: 0x%02X, Port1: 0x%02X", current_val_port0_, current_val_port1_); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - CHRG_PIN: %d (bit %d), FULL_PIN: %d (bit %d)", + (current_val_port0_ & (1 << BATTERY_CHRG_PIN)) ? 1 : 0, BATTERY_CHRG_PIN, + (current_val_port1_ & (1 << BATTERY_FULL_PIN)) ? 1 : 0, BATTERY_FULL_PIN); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - 充电状态: %s, 充满状态: %s", + current_charging_state ? "充电中" : "未充电", + current_full_state ? "已充满" : "未充满"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - 上次充电状态: %s, 上次充满状态: %s", + instance->battery_charging_last_state_ ? "充电中" : "未充电", + instance->battery_full_last_state_ ? "已充满" : "未充满"); + + //检查充电状态是否发生变化 + if (current_charging_state != instance->battery_charging_last_state_) { + instance->battery_charging_last_state_ = current_charging_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "电池充电状态变化: %s", current_charging_state ? "充电中" : "未充电"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "充电状态变化详情 - 从 %s 到 %s", + instance->battery_charging_last_state_ ? "未充电" : "充电中", + current_charging_state ? "充电中" : "未充电"); + + if (current_charging_state) { + // 进入充电状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到开始充电"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerChrgCallback(); + } + if (instance->battery_charging_callback_) { + instance->battery_charging_callback_(); + } + } else { + // 退出充电状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到停止充电"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerNotChrgCallback(); + } + if (instance->battery_not_charging_callback_) { + instance->battery_not_charging_callback_(); + } + } + } + + //检查充满状态是否发生变化 + if (current_full_state != instance->battery_full_last_state_) { + instance->battery_full_last_state_ = current_full_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "电池充满状态变化: %s", current_full_state ? "已充满" : "未充满"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "充满状态变化详情 - 从 %s 到 %s", + instance->battery_full_last_state_ ? "未充满" : "已充满", + current_full_state ? "已充满" : "未充满"); + + if (current_full_state) { + // 进入充满状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到电池已充满"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerFullCallback(); + } + if (instance->battery_full_callback_) { + instance->battery_full_callback_(); + } + } + + } + + // 根据AW9523B数据手册:读取输入端口寄存器清除对应端口的中断 + // 读取INPUT_PORT0 (00H) 清除P0口中断,读取INPUT_PORT1 (01H) 清除P1口中断 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "中断处理完成,已读取输入端口寄存器清除中断标志"); + } +} + +// bool IOExpansionBoard::AllocateStaticTaskMemory() +// { +// printf("IO拓展芯片创建任务前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); +// printf("IO拓展芯片创建任务前 Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +// // 分配任务栈(PSRAM) +// const size_t TASK_STACK_SIZE = 4096; +// pI2CReadTaskStackBuffer = (StackType_t*)heap_caps_malloc( +// TASK_STACK_SIZE * sizeof(StackType_t), +// MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT +// ); + +// if (!pI2CReadTaskStackBuffer) { +// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to allocate task stack from PSRAM"); +// return false; +// } + +// // 分配任务控制块(内部RAM) +// pxI2CReadTaskBuffer = (StaticTask_t*)pvPortMalloc(sizeof(StaticTask_t)); +// if (!pxI2CReadTaskBuffer) +// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to allocate task TCB from internal RAM"); +// heap_caps_free(pI2CReadTaskStackBuffer); +// pI2CReadTaskStackBuffer = nullptr; +// return false; +// } + +// ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static task memory allocated successfully"); +// printf("IO拓展芯片创建任务后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); +// printf("IO拓展芯片创建任务后 Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +// return true; +// } + +// void IOExpansionBoard::FreeStaticTaskMemory() +// { +// if (pI2CReadTaskStackBuffer != nullptr) { +// heap_caps_free(pI2CReadTaskStackBuffer); +// pI2CReadTaskStackBuffer = nullptr; +// } + +// if (pxI2CReadTaskBuffer != nullptr) { +// vPortFree(pxI2CReadTaskBuffer); +// pxI2CReadTaskBuffer = nullptr; +// } + +// ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static task memory freed"); +// } + +/** + * @brief 创建I2C数据读取任务 + */ +void IOExpansionBoard::CreateI2cReadTask() +{ + printf("创建I2C读取任务之前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之前:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + if (xI2CReadTaskHandle_) { + return; // 任务已创建 + } + + xTaskCreateWithCaps( + I2cReadTask, + "i2c_read_task", + I2C_TASK_STACK, + this, + I2C_TASK_PRIORITY, + &xI2CReadTaskHandle_, + MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT + ); + + if (xI2CReadTaskHandle_ == NULL) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to create static I2C read task"); + } else { + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static I2C read task created successfully"); + } + printf("创建I2C读取任务之后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之后:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +} + +/** + * @brief 启动I2C任务 (整合初始化和任务创建) + */ +esp_err_t IOExpansionBoard::StartTask() +{ + // 再创建任务 + if (!xI2CReadTaskHandle_) { + CreateI2cReadTask(); + } + return ESP_OK; +} diff --git a/main/02_physical/boards/board_v1_1_13/io_expansion_board.h b/main/02_physical/boards/board_v1_1_13/io_expansion_board.h new file mode 100644 index 0000000..3951893 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_13/io_expansion_board.h @@ -0,0 +1,419 @@ +#ifndef IO_EXPANSION_BOARD_H +#define IO_EXPANSION_BOARD_H + +#include +#include +#include +#include +#include +#include +#include "i2c_bus.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include +#include +#include +#include +#include +#include +#include +#include "esp_err.h" +#include "config.h" +#include "portmacro.h" + +// 前向声明,避免循环引用 +class MillimeterWaveRadar; +class PhotoInterrupter; +class AdcBatteryMonitor; + +// 回调函数类型定义 +typedef std::function RadarCallback; +typedef std::function PhotoInterrupterStartCallback; +typedef std::function PhotoInterrupterEndCallback; +typedef std::function BatteryChargingCallback; +typedef std::function BatteryFullCallback; +typedef std::function BatteryNotChargingCallback; + +/* 寄存器地址 */ +#define INPUT_PORT0 0x00 // 输入端口0寄存器 +#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取) +#define OUTPUT_PORT0 0x02 // 输出端口0寄存器 +#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平 +#define CONFIG_PORT0 0x04 // 配置端口0寄存器 +#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式 +#define INT_PORT0 0x06 // 中断端口0寄存器 +#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的) +#define CTL 0x11 // 全局控制寄存器 +#define ID 0x23 // 芯片ID寄存器(0x23) + +/***********************************IO扩展板电机引脚配置参数*************************************/ +/* 设置步进电机方向 */ +#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转 +#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转 +#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4 +#define STEPPER_MOTOR_DIR_CONFIG CONFIG_PORT0 //步进电机方向引脚配置在P0_4 + +/* 设置步进电机细分模式 */ +#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5 +#define STEPPER_MOTOR_M0_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define STEPPER_MOTOR_M0_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_5 + +#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4 +#define STEPPER_MOTOR_M1_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define STEPPER_MOTOR_M1_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_4 + +/* 设置步进电机睡眠引脚 */ +#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式 +#define STEPPER_MOTOR_WORK true //步进电机进入工作模式 +#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6 +#define STEPPER_MOTOR_SLEEP_CONFIG CONFIG_PORT1 //步进电机睡眠引脚配置在P1_6 +#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 + +/* 设置电机的使能引脚 */ +#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7 +#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_ENABLE_CONFIG CONFIG_PORT0 //电机使能引脚配置在P0_7 +#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平 +#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平 + +/* 设置毫米波雷达对应IO扩展板的中断引脚 */ +#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7 +#define RADAR_INTERRUPT_CONFIG CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口 +#define RADAR_INTERRUPT_INPUT INPUT_PORT1 //毫米波雷达中断引脚输入状态检测在INPUT_PORT1 +#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态 +#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态 +/* 任务配置常量 */ +#define WRITE_BUF_SIZE 2 // I2C单次写入字节数 +#define READ_BUF_SIZE 2 // I2C单次读取字节数 +#define I2C_TASK_PRIORITY 2 // 任务优先级(中等) +#define I2C_TASK_STACK 4096 // 任务栈大小(4KB) + +// 光学传感器引脚定义 +#define START_PHOTO_INTERRUPTER_PIN 2 // 光学传感器引脚(P0_2) +#define START_PHOTO_INTERRUPTER_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口 +#define START_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0 +#define START_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平 +#define START_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平 + +#define END_PHOTO_INTERRUPTER_PIN 3 // 光学传感器引脚(P0_3) +#define END_PHOTO_INTERRUPTER_PORT_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口 +#define END_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0 +#define END_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平 +#define END_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平 + +/***********************************IO扩展板LCD引脚配置参数*************************************/ +/* 设置LCD的BL引脚 */ +#define LCD_BL_PIN 6 //LCD背光引脚对应IO扩展板引脚P0_6 +#define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define LCD_BL_CONFIG CONFIG_PORT0 //LCD背光引脚配置在P0_6 +#define LCD_BL_HIGH true //LCD背光引脚状态为高电平 +#define LCD_BL_LOW false //LCD背光引脚状态为低电平 + +/* 设置LCD的RST引脚 */ +#define LCD_RST_PIN 1 //LCD复位引脚对应IO扩展板引脚P1_1 +#define LCD_RST_CONFIG CONFIG_PORT1 //LCD复位引脚配置在P1_1 +#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define LCD_RST_HIGH true //LCD复位引脚状态为高电平 +#define LCD_RST_LOW false //LCD复位引脚状态为低电平 + +/* 设置PA控制引脚 */ +#define PA_CTRL_PIN 2 //PA控制引脚对应IO扩展板引脚P1_2 +#define PA_CTRL_CONFIG CONFIG_PORT1 //PA控制引脚配置在P1_2 +#define PA_CTRL_PORT OUTPUT_PORT1 //PA控制引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define PA_CTRL_HIGH true //PA控制引脚状态为高电平 +#define PA_CTRL_LOW false //PA控制引脚状态为低电平 + +// 电池充电检测引脚定义 +#define BATTERY_FULL_INPUT INPUT_PORT1 // 电池充满检测引脚挂载在IO扩展板的输入端口 +#define BATTERY_FULL_PIN 3 // 电池充满检测引脚对应IO扩展板引脚P1_3 +#define BATTERY_FULL_CONFIG CONFIG_PORT1 // 电池充满检测引脚配置在P1_3 + +#define BATTERY_CHRG_INPUT INPUT_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口 +#define BATTERY_CHRG_PIN 5 // 充电检测引脚(P0_5) +#define BATTERY_CHRG_CONFIG CONFIG_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口 + +#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签 +#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签 + +// GPIO引脚定义 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚 +#define IO_EXPAND_RSTN GPIO_NUM_45 // IO扩展板复位引脚 + +/** + * @class IOExpansionBoard + * @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作 + */ +class IOExpansionBoard +{ +public: + /** + * @brief 构造函数 + */ + IOExpansionBoard(); + + /** + * @brief 设置毫米波雷达指针 + * @param radar 毫米波雷达对象指针 + */ + void SetRadar(MillimeterWaveRadar* radar) { radar_ = radar; }; + + /** + * @brief 设置限位开关指针 + * @param photo_interrupter 限位开关对象指针 + */ + void setPhotoInterrupter(PhotoInterrupter* photo_interrupter) { photo_interrupter_ = photo_interrupter; }; + + /** + * @brief 设置电池监控器指针 + * @param battery_monitor 电池监控器对象指针 + */ + void setBatteryMonitor(AdcBatteryMonitor* battery_monitor) { battery_monitor_ = battery_monitor; }; + + /** + * @brief 析构函数 + */ + ~IOExpansionBoard(); + + /** + * @brief 初始化GPIO中断检测 + * @param gpio_num 中断引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t InterruptGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetIoExpand(); + + /** + * @brief 初始化I2C主机通信 + * @return esp_err_t 初始化结果 + */ + // esp_err_t IoExpansionI2cInit(); + + /** + * @brief 创建I2C数据读取任务 + */ + void CreateI2cReadTask(); + + /** + * @brief 启动I2C任务(整合初始化和任务创建) + * @return esp_err_t 操作结果 + */ + esp_err_t StartTask(); + + /** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data); + + /** + * @brief 读寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要读出的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data); + + /** + * @brief 读取输入端口0寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t ReadInputPort0(uint8_t *data); + + /** + * @brief 读取输入端口1寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t ReadInputPort1(uint8_t *data); + + // /** + // * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断 + // * @param reg_addr 寄存器地址 + // * @return esp_err_t 操作结果 + // */ + // esp_err_t SetInterruptStatus(bool status); + + /** + * @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandSetMode(); + + /** + * @brief 设置步进电机的细分模式 + * @param mode 模式:1/2/4/8/16/32/64 + * @return esp_err_t 操作结果 + */ + void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin); + + /** + * @brief 设置步进电机的方向 + * @param dir 方向 + * @param OUTPUT_PORT 输出端口 + * @param pin 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin); + + /** + * @brief 设置步进电机的睡眠模式 + * @param 是否进入睡眠模式 + * @param 输出端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin); + + /** + * @brief 设置步进电机的使能引脚状态 + * @param 使能状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin); + + /** + * @brief 设置LCD的BL引脚状态 + * @param BL状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin); + + /** + * @brief 设置LCD的RST引脚状态 + * @param RST状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin); + + /** + * @brief 设置PA控制引脚状态 + * @param PA_CTRL状态(低电平为选中状态,高电平为不选中状态) + * @return esp_err_t 操作结果 + */ + esp_err_t SetPaCtrlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t pa_ctrl_pin); + + /** + * @brief 设置雷达中断引脚 + * @param 毫米波雷达的中断引脚模式 + * @param 输入端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin); + + /** + * @brief 计算Port0的字节值 + * @return uint8_t 操作结果 + */ + uint8_t ByteCalculatePort0(); + + /** + * @brief 计算Port1的字节值 + * @return uint8_t 操作结果 + */ + uint8_t ByteCalculatePort1(); + + /** + * @brief 设置雷达中断回调函数 + * @param callback 雷达中断回调函数 + */ + void SetRadarCallback(RadarCallback callback) { radar_callback_ = callback; } + + /** + * @brief 设置光学传感器开始中断回调函数 + * @param callback 光学传感器开始中断回调函数 + */ + void SetPhotoInterrupterStartCallback(PhotoInterrupterStartCallback callback) { photo_start_callback_ = callback; } + + /** + * @brief 设置光学传感器结束中断回调函数 + * @param callback 光学传感器结束中断回调函数 + */ + void SetPhotoInterrupterEndCallback(PhotoInterrupterEndCallback callback) { photo_end_callback_ = callback; } + + /** + * @brief 设置电池充电中断回调函数 + * @param callback 电池充电中断回调函数 + */ + void SetBatteryChargingCallback(BatteryChargingCallback callback) { battery_charging_callback_ = callback; } + + /** + * @brief 设置电池充满中断回调函数 + * @param callback 电池充满中断回调函数 + */ + void SetBatteryFullCallback(BatteryFullCallback callback) { battery_full_callback_ = callback; } + + /** + * @brief 设置电池非充电中断回调函数 + * @param callback 电池非充电中断回调函数 + */ + void SetBatteryNotChargingCallback(BatteryNotChargingCallback callback) { battery_not_charging_callback_ = callback; } + + // 公共成员变量 + i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄 + uint8_t device_addr_; // I2C设备地址 + +private: + // 静态成员函数 + MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调 + PhotoInterrupter* photo_interrupter_ = nullptr; // 限位开关指针,用于触发回调 + AdcBatteryMonitor* battery_monitor_ = nullptr; // 电池监控器指针,用于触发回调 + static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数 + static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数 + + // 成员变量用于状态跟踪 + uint8_t last_port0_state_ = 0; // 上次检测到的Port0状态 + uint8_t last_port1_state_ = 0; // 上次检测到的Port1状态 + bool radar_last_state_ = false; // 雷达引脚上一次的状态 + bool battery_charging_last_state_ = false; // 电池充电状态上一次的状态 + bool battery_full_last_state_ = false; // 电池充满状态上一次的状态 + + // 回调函数成员变量 + RadarCallback radar_callback_ = nullptr; + PhotoInterrupterStartCallback photo_start_callback_ = nullptr; + PhotoInterrupterEndCallback photo_end_callback_ = nullptr; + BatteryChargingCallback battery_charging_callback_ = nullptr; + BatteryFullCallback battery_full_callback_ = nullptr; + BatteryNotChargingCallback battery_not_charging_callback_ = nullptr; + + // PhotoInterrupter* photo_interrupter_ = nullptr; // 光学传感器指针,用于触发回调 + // /** + // * @brief 分配静态任务所需的内存 + // * @return bool 分配是否成功 + // */ + // bool AllocateStaticTaskMemory(); + + // /** + // * @brief 释放静态任务分配的内存 + // */ + // void FreeStaticTaskMemory(); + + // 实例成员变量 + EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组 + TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄 + bool is_initialized_ = false; // 初始化状态标记(新增) + gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚 + gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚 + + // StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM) + // StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM) +}; + +#endif \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_14/board_sweekar.cc b/main/02_physical/boards/board_v1_1_14/board_sweekar.cc new file mode 100644 index 0000000..1237ebe --- /dev/null +++ b/main/02_physical/boards/board_v1_1_14/board_sweekar.cc @@ -0,0 +1,702 @@ +/** + * @file board.cc + * @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +extern "C" { +#include "esp_log.h" +#include "driver/gpio.h" +#include "driver/uart.h" +#include "driver/ledc.h" +#include "driver/gptimer.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "hal/gpio_types.h" +#include "hal/uart_types.h" +#include "esp_check.h" +#include "sdkconfig.h" +#include "i2c_bus.h" +#include "esp_peripherals.h" +#include "periph_sdcard.h" +#include "esp_sleep.h" +#include "driver/rtc_io.h" +} + +#include "board_sweekar.h" +#include "config.h" +#include "board.h" // 添加board.h以获取audio_board_sdcard_init函数声明 +#include "drv8428.h" +#include "aw8646.h" + +#define TAG "board_sweekar" + +BoardSweekar::BoardSweekar() + : base_board_hal_uart_(BASE_BOARD_CTL_UART_PORT) +{ +#ifdef CONFIG_STEPPER_DRIVER_AW8646 + stepper_driver_ = new Aw8646Driver(io_expansion_); +#else + stepper_driver_ = new Drv8428Driver(io_expansion_); +#endif +} + +BoardSweekar::~BoardSweekar() +{ + if (stepper_driver_) { + delete stepper_driver_; + stepper_driver_ = nullptr; + } +} + + +/*========================== 步进电机相关驱动 ==========================*/ + +/** + * @brief 步进电机初始化函数 + * 配置步进电机所需的GPIO引脚模式,通过IO扩展板设置步进驱动芯片的工作模式 + * 在 stepper_motor.cc 中完成 GPTimer + GPIO 翻转 STEP 脉冲的初始化 + */ +void BoardSweekar::StepperMotorInit(void) +{ + esp_err_t err = ESP_OK; + + // 1) STEP 引脚改为普通 GPIO(不再用 LEDC) + gpio_config_t io_cfg; + io_cfg.pin_bit_mask = 1ULL << STEPPER_STEP_IO; + io_cfg.mode = GPIO_MODE_OUTPUT; + io_cfg.pull_up_en = GPIO_PULLUP_DISABLE; + io_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_cfg.intr_type = GPIO_INTR_DISABLE; + err = gpio_config(&io_cfg); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "步进电机 STEP GPIO 配置失败, 错误码: 0x%x", err); + } + + // 初始电平拉低,保证上电不乱跳 + gpio_set_level(STEPPER_STEP_IO, 0); + + // 2) 检查 I2C 总线是否已初始化 + if (bus_handle_ == nullptr) + { + ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()"); + return; + } + + // 3) 初始化驱动对象并初始化 + if (stepper_driver_) { + err = stepper_driver_->Init(); + if (err != ESP_OK) { + ESP_LOGE(TAG_BOARD, "步进电机驱动初始化失败, 错误码: 0x%x", err); + } + } else { + ESP_LOGE(TAG_BOARD, "步进电机驱动创建失败"); + } +} + +/** + * @brief LCD IO引脚初始化函数(消除与步进电机的耦合) + * + * 配置LCD所需的IO扩展板寄存器,确保LCD复位引脚正常工作 + * 此函数独立于步进电机初始化,专门处理LCD相关的IO配置 + */ +void BoardSweekar::LcdIoInit(void) +{ + esp_err_t err = ESP_OK; + + // 1) 检查I2C总线是否已初始化 + if (bus_handle_ == nullptr) + { + ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()"); + return; + } + + // 2) 执行硬件复位,确保IO扩展板处于已知状态 + err = io_expansion_.ResetIoExpand(); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "IO扩展板硬件复位失败, 错误码: 0x%x", err); + return; + } + else + { + ESP_LOGI(TAG_BOARD, "IO扩展板硬件复位成功"); + } + + // 3) 配置IO扩展板模式(端口方向等) + err = io_expansion_.IoexpandSetMode(); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "IO扩展板模式配置失败, 错误码: 0x%x", err); + return; + } + else + { + ESP_LOGI(TAG_BOARD, "IO扩展板模式配置成功"); + } + + // 4) 初始化LCD复位引脚:设置为高电平 + err = io_expansion_.SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "LCD复位引脚高电平设置失败, 错误码: 0x%x", err); + return; + } + else + { + ESP_LOGI(TAG_BOARD, "LCD复位引脚高电平设置成功"); + } + + io_expansion_.SetLedEnMode(true); +} + +/*========================== 毫米波雷达相关驱动 ==========================*/ + +/** + * @brief 毫米波雷达串口初始化函数 + * + * 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚, + * 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免 + * 与自定义中断冲突。 + */ +void BoardSweekar::MillimeterWaveRadarUartInit(void) +{ + uart_config_t uart_config = { + .baud_rate = RADAR_BAUD_RATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 122, + .source_clk = UART_SCLK_DEFAULT, + .flags = { + .allow_pd = 0, + .backup_before_sleep = 0, + }, + }; + + // 1. 设置串口参数 + ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config)); + + // 2. 设置 UART 引脚 + ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突) + // 增加 RX/TX FIFO 深度以处理突发数据 + ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4, + 0, NULL, 0)); +} + +/** + * @brief 毫米波雷达中断引脚初始化函数 + * + * 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能 + * (如需使用中断需单独进行配置)。 + */ +void BoardSweekar::MillimeterWaveRadarGpioInit(void) +{ + // GPIO配置结构体 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚 + .mode = GPIO_MODE_INPUT, // 设置为输入模式 + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉 + .intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置) + }; + + // 配置GPIO + gpio_config(&io_conf); +} + +/*========================== I2C总线及挂载的从设备相关驱动 ==========================*/ + +/** + * @brief I2C总线及从机设备初始化函数 + * + * 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。 + * 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。 + * 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。 + * + * @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因 + */ +esp_err_t BoardSweekar::I2CMasterInit(void) +{ + static const char *I2C_INIT = "I2C_INIT"; + + // 初始化IO扩展板复位引脚 + gpio_config_t reset_io_conf = { + .pin_bit_mask = (1ULL << IO_EXPAND_RSTN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉 + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&reset_io_conf); + + // 执行复位时序:先拉低100ms,再拉高并等待100ms + gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms + gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + + ESP_LOGI(I2C_INIT, "IO扩展板复位完成"); + + // 创建统一的I2C总线(使用ESP-ADF的i2c_bus) + i2c_config_t i2c_cfg = { + .mode = I2C_MODE_MASTER, + .sda_io_num = I2C0_MASTER_SDA_IO, + .scl_io_num = I2C0_MASTER_SCL_IO, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master = { + .clk_speed = 100000, + }, + .clk_flags = 0, + }; + + // 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线) + bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg); + if (bus_handle_ == NULL) { + ESP_LOGE(TAG, "Failed to create I2C bus"); + return ESP_FAIL; + } + + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + // ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信 + + // 验证线性马达设备是否存在 + esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR); + } + // 验证IO扩展板设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err); + // 不返回错误,继续初始化其他设备 + } else { + ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR); + } + // 验证陀螺仪设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR); + } + + // 为IO扩展板设置总线句柄和设备地址(使用7位地址) + io_expansion_.bus_handle_ = bus_handle_; + io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1; + + // 线性马达的初始化已移至 InitializeAllHardware 中统一调用 Init 方法 + // linear_motor_ 的参数传递将在那里完成,不再此处直接赋值,提高内聚性 + + ESP_LOGI(I2C_INIT, "I2C总线初始化完成"); + return ESP_OK; +} + +/*========================== VBAT to VBAT_5V相关驱动 ==========================*/ + +/** + * @brief 开启VBAT to VBAT_5V + * + * 创建开启升压的电源管理单元 + * + */ +void BoardSweekar::VbatToVbat5vInit(void) +{ + if (VBAT_5V_PIN == GPIO_NUM_NC) { + return; + } + // 配置VBAT_5V引脚为输出模式 + gpio_config_t io_conf = { + .pin_bit_mask = (VBAT_5V_PIN != GPIO_NUM_NC) ? (1ULL << VBAT_5V_PIN) : 0, + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&io_conf); + // 使能VBAT_5V + gpio_set_level(VBAT_5V_PIN, 1); +} + +/*========================== 底座控制串口相关驱动 ==========================*/ + +/** + * @brief 底座控制命令串口初始化函数 + */ +void BoardSweekar::BaseBoardControlUartInit(void) +{ + uart_config_t uart_config = { + .baud_rate = BASE_BOARD_CTL_UART_BAUDRATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 122, + .source_clk = UART_SCLK_DEFAULT, + .flags = { + .allow_pd = 0, + .backup_before_sleep = 0, + }, + }; + + // 1. 设置串口参数 + ESP_ERROR_CHECK(uart_param_config(BASE_BOARD_CTL_UART_PORT, &uart_config)); + + // 2. 设置 UART 引脚 + ESP_ERROR_CHECK(uart_set_pin(BASE_BOARD_CTL_UART_PORT, BASE_BOARD_CTL_UART_TX_PIN, BASE_BOARD_CTL_UART_RX_PIN, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 3. 安装 UART 驱动 + ESP_ERROR_CHECK(uart_driver_install(BASE_BOARD_CTL_UART_PORT, + BASE_BOARD_CTL_UART_BUF_SIZE, + BASE_BOARD_CTL_UART_BUF_SIZE, + 0, NULL, 0)); + + base_board_control_.Init(&base_board_hal_uart_); +} + +/*========================== SD卡相关驱动 ==========================*/ + +/** + * @brief SD卡初始化函数 + * + * 初始化SD卡外设,使用1线模式进行通信。该函数负责初始化外设管理器 + * 并配置SD卡,为后续的文件系统操作做准备。 + * + * @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示失败原因 + */ +esp_err_t BoardSweekar::InitializeSdcard(void) +{ + static const char *SDCARD_TAG = "SDCARD_INIT"; + esp_err_t ret; + + ESP_LOGI(SDCARD_TAG, "Initializing SD card"); + + if (is_sdcard_initialized_) { + ESP_LOGW(SDCARD_TAG, "SD card already initialized"); + return ESP_OK; + } + + // 初始化外设管理 + esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG(); + periph_cfg.extern_stack = true; // 将任务栈分配到 PSRAM 以节省 Internal SRAM + periph_set_ = esp_periph_set_init(&periph_cfg); + if (!periph_set_) { + ESP_LOGE(SDCARD_TAG, "Failed to initialize peripheral set"); + return ESP_FAIL; + } + + // 初始化SD卡外设 + ret = audio_board_sdcard_init(periph_set_, SD_MODE_1_LINE); + if (ret != ESP_OK) { + ESP_LOGE(SDCARD_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret)); + return ret; + } + + is_sdcard_initialized_ = true; + ESP_LOGI(SDCARD_TAG, "SD card initialized successfully"); + return ESP_OK; +} + +/** + * @brief 统一的硬件初始化接口实现 + * + * 按照依赖关系顺序初始化所有硬件资源: + * 1. I2C总线(最基础,其他设备可能依赖) + * 2. IO扩展板(可能影响其他设备) + * 3. SD卡(文件系统,供显示和音频使用) + * 4. 其他外设 + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ +esp_err_t BoardSweekar::InitializeAllHardware(void) +{ + static const char *HW_INIT_TAG = "HW_INIT"; + esp_err_t ret; + + ESP_LOGI(HW_INIT_TAG, "Starting unified hardware initialization..."); + + // 1. 初始化I2C总线(最基础) + ret = I2CMasterInit(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret)); + return ret; + } + ESP_LOGI(HW_INIT_TAG, "I2C master initialized"); + + // 2. 创建I2C读任务(IO扩展板需要) + io_expansion_.CreateI2cReadTask(); + ESP_LOGI(HW_INIT_TAG, "I2C read task created"); + + // 3. 初始化SD卡(文件系统,供显示和音频使用) + ret = InitializeSdcard(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret)); + // SD卡失败不是致命错误,继续初始化其他硬件 + ESP_LOGW(HW_INIT_TAG, "SD card initialization failed, but continuing with other hardware"); + } else { + ESP_LOGI(HW_INIT_TAG, "SD card initialized"); + } + + // 4. 初始化LCD IO引脚 + LcdIoInit(); + ESP_LOGI(HW_INIT_TAG, "LCD IO pins initialized"); + + // 5. 初始化触摸传感器 + touch_sensor_.SetI2cHandle(bus_handle_); + touch_sensor_.Begin(); + ESP_LOGI(HW_INIT_TAG, "Touch sensor initialized"); + + // 6. 初始化其他必要外设 + // BaseBoardControlUartInit(); // 底座控制串口(demo5需要) + // ESP_LOGI(HW_INIT_TAG, "Base board control UART initialized"); + + // 初始化底座控制 + // base_board_control_.Init(); + // ESP_LOGI(HW_INIT_TAG, "Base board control initialized"); + + // 可选外设(根据具体应用需求) + // MillimeterWaveRadarUartInit(); + // MillimeterWaveRadarGpioInit(); + StepperMotorInit(); + + + + ESP_LOGI(HW_INIT_TAG, "Unified hardware initialization completed successfully"); + return ESP_OK; +} + +/** + * @brief 进入低功耗模式 + * + * 根据指定的功耗模式,执行相应的功耗优化策略: + * - IDLE模式:关闭非必要外设,保持快速响应 + * - LIGHT_SLEEP模式:进入轻度睡眠,CPU暂停,外设断电 + * - DEEP_SLEEP模式:深度睡眠,仅RTC运行,功耗最低 + */ +esp_err_t BoardSweekar::EnterLowPowerMode(power_mode_t mode) { + static const char *POWER_TAG = "POWER_MGMT"; + esp_err_t ret = ESP_OK; + + ESP_LOGI(POWER_TAG, "Entering power mode: %d", mode); + + if (mode == current_power_mode_) { + ESP_LOGW(POWER_TAG, "Already in power mode %d", mode); + return ESP_OK; + } + + // 保存当前模式,以便恢复 + power_mode_t previous_mode = current_power_mode_; + + switch (mode) { + case POWER_MODE_NORMAL: + // 正常模式,不需要特殊处理 + break; + + case POWER_MODE_IDLE: + // 空闲模式:关闭非必要外设 + ESP_LOGI(POWER_TAG, "Idle mode: disabling non-essential peripherals"); + + // 关闭SD卡(如果正在使用,需要先卸载) + if (is_sdcard_initialized_) { + // 注意:这里只是示例,实际应用中需要确保没有文件操作 + ESP_LOGW(POWER_TAG, "SD card still active in idle mode"); + } + + // 关闭显示背光 + // 关闭非必要GPIO的上拉/下拉 + // 降低I2C时钟频率 + break; + + case POWER_MODE_LIGHT_SLEEP: + // 轻度睡眠 + ESP_LOGI(POWER_TAG, "Light sleep mode: preparing for sleep"); + + // 设置唤醒源(需要根据具体需求配置) + // esp_sleep_enable_timer_wakeup(1000000); // 1秒后唤醒 + // esp_sleep_enable_ext0_wakeup(GPIO_NUM_XX, 0); // 外部中断唤醒 + + // 进入轻度睡眠 + // ret = esp_light_sleep_start(); + if (ret != ESP_OK) { + ESP_LOGE(POWER_TAG, "Failed to enter light sleep: %s", esp_err_to_name(ret)); + current_power_mode_ = previous_mode; + return ret; + } + break; + + case POWER_MODE_DEEP_SLEEP: + // 深度睡眠 + ESP_LOGI(POWER_TAG, "Deep sleep mode: system will restart after wake-up"); + + // 保存必要的RTC数据 + // rtc_gpio_isolate(GPIO_NUM_XX); // 隔离GPIO + + // 设置深度睡眠唤醒源 + // esp_sleep_enable_timer_wakeup(60000000); // 60秒后唤醒 + + // 进入深度睡眠 + // esp_deep_sleep_start(); + // 注意:深度睡眠后系统会重启,不会返回 + break; + + default: + ESP_LOGE(POWER_TAG, "Invalid power mode: %d", mode); + return ESP_ERR_INVALID_ARG; + } + + current_power_mode_ = mode; + ESP_LOGI(POWER_TAG, "Successfully entered power mode: %d", mode); + return ret; +} + +/** + * @brief 退出低功耗模式 + * + * 从低功耗模式恢复到正常运行模式,重新初始化必要的硬件资源。 + */ +esp_err_t BoardSweekar::ExitLowPowerMode(void) { + static const char *POWER_TAG = "POWER_MGMT"; + + ESP_LOGI(POWER_TAG, "Exiting low power mode"); + + if (current_power_mode_ == POWER_MODE_NORMAL) { + ESP_LOGW(POWER_TAG, "Already in normal mode"); + return ESP_OK; + } + + // 根据之前的功耗模式执行相应的恢复操作 + switch (current_power_mode_) { + case POWER_MODE_IDLE: + // 恢复空闲模式 + ESP_LOGI(POWER_TAG, "Restoring from idle mode"); + + // 重新初始化必要的外设 + // 恢复I2C时钟频率 + // 重新开启显示背光 + break; + + case POWER_MODE_LIGHT_SLEEP: + // 轻度睡眠唤醒后会自动继续执行 + ESP_LOGI(POWER_TAG, "Woken up from light sleep"); + + // 重新配置时钟(如果需要) + // 重新初始化外设 + break; + + case POWER_MODE_DEEP_SLEEP: + // 深度睡眠后系统会重启,不会执行到这里 + ESP_LOGW(POWER_TAG, "Deep sleep recovery should not reach here"); + break; + + default: + break; + } + + // 恢复到正常模式 + current_power_mode_ = POWER_MODE_NORMAL; + ESP_LOGI(POWER_TAG, "Successfully exited low power mode"); + + return ESP_OK; +} + +/** + * @brief 设置硬件模块电源状态 + * + * 提供精细化的电源管理,可以单独控制各个硬件模块的电源状态。 + */ +esp_err_t BoardSweekar::SetModulePower(hardware_module_t module, bool enable) { + static const char *POWER_TAG = "POWER_MODULE"; + esp_err_t ret = ESP_OK; + + ESP_LOGI(POWER_TAG, "%s module %d", enable ? "Enabling" : "Disabling", module); + + // 更新电源状态位图 + if (enable) { + power_state_flags_ |= (1 << module); + } else { + power_state_flags_ &= ~(1 << module); + } + + switch (module) { + case HW_MODULE_I2C: + if (!enable && bus_handle_) { + // 注意:I2C总线通常不建议完全关闭,可能影响多个设备 + ESP_LOGW(POWER_TAG, "I2C bus power control not recommended"); + } + break; + + case HW_MODULE_SDCARD: + if (enable && !is_sdcard_initialized_) { + ret = InitializeSdcard(); + } else if (!enable && is_sdcard_initialized_) { + // 卸载SD卡文件系统 + // 注意:需要确保没有打开的文件 + ESP_LOGW(POWER_TAG, "SD card power down requires file system cleanup"); + } + break; + + case HW_MODULE_LCD: + // LCD背光控制 + // LCD电源引脚控制(如果有) + break; + + case HW_MODULE_AUDIO: + // 音频编解码器电源控制 + // 需要与AudioPlayer协调 + break; + + case HW_MODULE_MOTOR: + // 步进电机驱动器电源控制 + // 电机睡眠模式 + break; + + case HW_MODULE_GYROSCOPE: + // 陀螺仪电源控制 + // 设置陀螺仪为低功耗模式 + break; + + case HW_MODULE_TOUCH: + // 触摸传感器电源控制 + // 设置触摸传感器为睡眠模式 + break; + + case HW_MODULE_RADAR: + // 毫米波雷达电源控制 + // 设置雷达为低功耗模式 + break; + + case HW_MODULE_IO_EXPAND: + // IO扩展板电源控制 + // 设置扩展板为低功耗模式 + break; + + default: + ESP_LOGE(POWER_TAG, "Unknown hardware module: %d", module); + return ESP_ERR_INVALID_ARG; + } + + if (ret == ESP_OK) { + ESP_LOGI(POWER_TAG, "Module %d power %s successfully", module, enable ? "enabled" : "disabled"); + } else { + ESP_LOGE(POWER_TAG, "Failed to %s module %d: %s", enable ? "enable" : "disable", module, esp_err_to_name(ret)); + } + + return ret; +} + + + diff --git a/main/02_physical/boards/board_v1_1_14/board_sweekar.h b/main/02_physical/boards/board_v1_1_14/board_sweekar.h new file mode 100644 index 0000000..fa1db66 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_14/board_sweekar.h @@ -0,0 +1,171 @@ +#ifndef __BOARD_H__ +#define __BOARD_H__ +#include "config.h" +#include "io_expansion_board.h" +#include "stepper_motor.h" +#include "stepper_driver.h" +#include "i2c_bus.h" +#include "gyroscope.h" +#include "touch_sensor.h" +#include "base_board_control.h" +#include "base_board_hal_uart.h" +#include "esp_peripherals.h" +#include "periph_sdcard.h" +#include "esp_sleep.h" +#include "driver/rtc_io.h" + +/** + * @brief 功耗模式枚举 + */ +typedef enum { + POWER_MODE_NORMAL, // 正常运行模式,所有硬件可用 + POWER_MODE_IDLE, // 空闲模式,关闭非必要外设 + POWER_MODE_LIGHT_SLEEP, // 轻度睡眠,快速唤醒 + POWER_MODE_DEEP_SLEEP, // 深度睡眠,仅RTC运行 +} power_mode_t; + +/** + * @brief 硬件模块枚举,用于精细化电源管理 + */ +typedef enum { + HW_MODULE_I2C, // I2C总线 + HW_MODULE_SDCARD, // SD卡 + HW_MODULE_LCD, // LCD显示 + HW_MODULE_AUDIO, // 音频编解码器 + HW_MODULE_MOTOR, // 步进电机 + HW_MODULE_GYROSCOPE, // 陀螺仪 + HW_MODULE_TOUCH, // 触摸传感器 + HW_MODULE_RADAR, // 毫米波雷达 + HW_MODULE_IO_EXPAND, // IO扩展板 +} hardware_module_t; + +/** + * @brief 硬件板级管理器 + * + * 采用高内聚低耦合设计原则,统一管理所有硬件资源。 + * 提供统一的硬件初始化接口和资源访问,避免各模块重复初始化。 + */ +class BoardSweekar +{ +private: + i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄 + esp_periph_set_handle_t periph_set_ = nullptr; // 外设管理句柄 + bool is_sdcard_initialized_ = false; // SD卡初始化状态 + power_mode_t current_power_mode_ = POWER_MODE_NORMAL; // 当前功耗模式 + uint32_t power_state_flags_ = 0xFFFFFFFF; // 各模块电源状态位图(1为开启) + +public: + BoardSweekar(); + ~BoardSweekar(); + + IOExpansionBoard io_expansion_; // IO扩展板对象 + Gyroscope gyroscope_; // 陀螺仪对象 + TouchSensor touch_sensor_; // 触摸传感器对象 + BaseBoardHalUart base_board_hal_uart_; // 底座控制HAL对象 + BaseBoardControl base_board_control_; // 底座控制对象 + StepperDriver* stepper_driver_ = nullptr; // 步进电机驱动对象 + + StepperDriver* GetStepperDriver() const { return stepper_driver_; } + + // 初始化步进电机 + void StepperMotorInit(void); + + // 初始化LCD IO引脚(消除与步进电机的耦合) + void LcdIoInit(void); + + // 初始化串口 + void MillimeterWaveRadarUartInit(void); + + //初始化毫米波雷达的中断引脚 + void MillimeterWaveRadarGpioInit(void); + + // 初始化I2C总线 + esp_err_t I2CMasterInit(void); + + // 初始化VBAT toVBAT_5V引脚 + void VbatToVbat5vInit(void); + + // 初始化底座控制串口 + void BaseBoardControlUartInit(void); + + // 初始化SD卡(推荐使用统一的硬件初始化) + esp_err_t InitializeSdcard(void); + + // 获取SD卡初始化状态 + bool IsSdcardInitialized() const { return is_sdcard_initialized_; } + + // 获取外设管理句柄(供需要访问SD卡的模块使用) + esp_periph_set_handle_t GetPeriphSet() const { return periph_set_; } + + // 获取I2C总线句柄 + i2c_bus_handle_t GetBusHandle() const { return bus_handle_; } + + /** + * @brief 统一的硬件初始化接口 + * + * 按照依赖关系顺序初始化所有硬件资源,确保各模块可以安全使用。 + * 推荐在主程序启动时调用此函数,而不是分别调用各个初始化函数。 + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ + esp_err_t InitializeAllHardware(void); + + /** + * @brief 完整的统一硬件初始化接口(专为复杂应用优化) + * + * 包含所有必要外设的完整初始化,适用于demo5等复杂应用场景。 + * 这个函数会初始化:I2C总线、IO扩展板、SD卡、LCD IO、底座控制等。 + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ + esp_err_t InitializeAllHardwareComplete(void); + + /** + * @brief 针对特定应用的硬件初始化配置 + * + * 为不同类型的应用提供专门的初始化配置,优化启动流程。 + * + * @param app_type 应用类型(demo5、音频播放器、显示应用等) + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ + esp_err_t InitializeHardwareForApplication(int app_type); + + /** + * @brief 功耗管理接口 - 进入低功耗模式 + * + * 根据指定的功耗模式,关闭非必要硬件、设置GPIO为低功耗状态、 + * 调整时钟频率等。支持多种功耗模式以适应不同应用场景。 + * + * @param mode 功耗模式 + * @return esp_err_t 操作结果 + */ + esp_err_t EnterLowPowerMode(power_mode_t mode); + + /** + * @brief 功耗管理接口 - 退出低功耗模式 + * + * 从低功耗模式恢复,重新初始化必要的硬件资源。 + * + * @return esp_err_t 操作结果 + */ + esp_err_t ExitLowPowerMode(void); + + /** + * @brief 获取当前功耗模式 + * + * @return power_mode_t 当前功耗模式 + */ + power_mode_t GetPowerMode(void) const { return current_power_mode_; } + + /** + * @brief 设置硬件模块电源状态 + * + * 单独控制某个硬件模块的电源状态,用于精细化的功耗管理。 + * + * @param module 硬件模块 + * @param enable true为开启,false为关闭 + * @return esp_err_t 操作结果 + */ + esp_err_t SetModulePower(hardware_module_t module, bool enable); +}; +#endif diff --git a/main/02_physical/boards/board_v1_1_14/board_sweekar_complete_init.cc b/main/02_physical/boards/board_v1_1_14/board_sweekar_complete_init.cc new file mode 100644 index 0000000..37a454a --- /dev/null +++ b/main/02_physical/boards/board_v1_1_14/board_sweekar_complete_init.cc @@ -0,0 +1,186 @@ +/** + * @file board_sweekar_complete_init.cc + * @brief 完整的统一硬件初始化实现 + * + * 这个文件提供了完整的统一硬件初始化函数,包含所有必要的硬件初始化步骤。 + * 专为demo5等复杂应用场景设计。 + */ + +/** + * @brief 完整的统一硬件初始化接口(专为demo5优化) + * + * 按照依赖关系顺序初始化所有硬件资源: + * 1. I2C总线(最基础,其他设备依赖) + * 2. IO扩展板(控制其他外设) + * 3. SD卡(文件系统,供显示和音频使用) + * 4. LCD IO引脚(显示相关) + * 5. 底座控制串口(通信) + * 6. 底座控制模块(业务逻辑) + * 7. 其他外设(根据应用需求) + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ +esp_err_t BoardSweekar::InitializeAllHardwareComplete(void) +{ + static const char *HW_INIT_TAG = "HW_INIT_COMPLETE"; + esp_err_t ret; + + ESP_LOGI(HW_INIT_TAG, "Starting complete hardware initialization..."); + + // 1. 初始化I2C总线(最基础,其他设备依赖) + ret = I2CMasterInit(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret)); + return ret; + } + ESP_LOGI(HW_INIT_TAG, "✓ I2C master initialized"); + + // 2. 创建I2C读任务(IO扩展板需要) + io_expansion_.CreateI2cReadTask(); + ESP_LOGI(HW_INIT_TAG, "✓ I2C read task created"); + + // 3. 初始化SD卡(文件系统,供显示和音频使用) + ret = InitializeSdcard(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret)); + // SD卡失败不是致命错误,继续初始化其他硬件 + ESP_LOGW(HW_INIT_TAG, "⚠ SD card initialization failed, but continuing with other hardware"); + } else { + ESP_LOGI(HW_INIT_TAG, "✓ SD card initialized"); + } + + // 4. 初始化LCD IO引脚(显示相关) + LcdIoInit(); + ESP_LOGI(HW_INIT_TAG, "✓ LCD IO pins initialized"); + + // 5. 初始化底座控制串口(demo5需要) + BaseBoardControlUartInit(); + ESP_LOGI(HW_INIT_TAG, "✓ Base board control UART initialized"); + + // 6. 初始化底座控制模块 + base_board_control_.Init(); + ESP_LOGI(HW_INIT_TAG, "✓ Base board control initialized"); + + // 7. 设置IO扩展板的PA控制模式(demo5需要) + io_expansion_.SetPaCtrlMode(true); + ESP_LOGI(HW_INIT_TAG, "✓ IO expansion PA control mode set"); + + // 8. 可选外设(根据具体应用需求启用) + // ESP_LOGI(HW_INIT_TAG, "Initializing optional peripherals..."); + // + // // 毫米波雷达(如需要) + // MillimeterWaveRadarUartInit(); + // MillimeterWaveRadarGpioInit(); + // ESP_LOGI(HW_INIT_TAG, "✓ Millimeter wave radar initialized"); + // + // // VBAT升压(如需要) + // VbatToVbat5vInit(); + // ESP_LOGI(HW_INIT_TAG, "✓ VBAT to 5V booster initialized"); + // + // // 步进电机(如需要) + // StepperMotorInit(); + // ESP_LOGI(HW_INIT_TAG, "✓ Stepper motor initialized"); + + ESP_LOGI(HW_INIT_TAG, "=== Complete hardware initialization finished successfully ==="); + return ESP_OK; +} + +/** + * @brief 针对特定应用的硬件初始化配置 + * + * 为不同类型的应用提供专门的初始化配置 + */ +esp_err_t BoardSweekar::InitializeHardwareForApplication(application_type_t app_type) { + static const char *APP_INIT_TAG = "APP_HW_INIT"; + + ESP_LOGI(APP_INIT_TAG, "Initializing hardware for application type: %d", app_type); + + // 基础硬件初始化(所有应用都需要) + esp_err_t ret = InitializeAllHardwareComplete(); + if (ret != ESP_OK) { + ESP_LOGE(APP_INIT_TAG, "Basic hardware initialization failed"); + return ret; + } + + switch (app_type) { + case APP_TYPE_DEMO5: // 宠物游戏demo + ESP_LOGI(APP_INIT_TAG, "Configuring for Demo5 (Pet Game)..."); + + // Demo5需要的额外初始化 + // 触摸传感器、陀螺仪、RGB LED等会在应用层初始化 + + ESP_LOGI(APP_INIT_TAG, "✓ Demo5 hardware configuration complete"); + break; + + case APP_TYPE_AUDIO_PLAYER: // 音频播放器 + ESP_LOGI(APP_INIT_TAG, "Configuring for Audio Player..."); + + // 音频应用需要确保音频编解码器正确初始化 + // 这部分通常在AudioPlayer类中处理 + + ESP_LOGI(APP_INIT_TAG, "✓ Audio player hardware configuration complete"); + break; + + case APP_TYPE_DISPLAY_ONLY: // 纯显示应用 + ESP_LOGI(APP_INIT_TAG, "Configuring for Display Only..."); + + // 显示应用需要确保LCD相关硬件正确配置 + // 这部分通常在Display类中处理 + + ESP_LOGI(APP_INIT_TAG, "✓ Display-only hardware configuration complete"); + break; + + case APP_TYPE_MINIMAL: // 最小化应用 + ESP_LOGI(APP_INIT_TAG, "Configuring for Minimal Application..."); + + // 最小化配置,只保留最基本的功能 + // 关闭非必要外设以节省功耗 + + ESP_LOGI(APP_INIT_TAG, "✓ Minimal hardware configuration complete"); + break; + + default: + ESP_LOGW(APP_INIT_TAG, "Unknown application type, using default configuration"); + break; + } + + return ESP_OK; +} + +/** + * @brief 硬件初始化状态报告 + * + * 提供详细的硬件初始化状态报告,便于调试和问题排查 + */ +void BoardSweekar::ReportHardwareStatus(void) { + static const char *STATUS_TAG = "HW_STATUS"; + + ESP_LOGI(STATUS_TAG, "=== Hardware Initialization Status Report ==="); + + // I2C总线状态 + ESP_LOGI(STATUS_TAG, "I2C Bus: %s", (bus_handle_ != nullptr) ? "✓ Initialized" : "✗ Not initialized"); + + // SD卡状态 + ESP_LOGI(STATUS_TAG, "SD Card: %s", (is_sdcard_initialized_) ? "✓ Initialized" : "✗ Not initialized"); + if (is_sdcard_initialized_) { + ESP_LOGI(STATUS_TAG, " Peripheral Set: %s", (periph_set_ != nullptr) ? "✓ Available" : "✗ Not available"); + } + + // IO扩展板状态 + ESP_LOGI(STATUS_TAG, "IO Expansion Board: %s", (io_expansion_.bus_handle_ != nullptr) ? "✓ Configured" : "✗ Not configured"); + + // 底座控制状态 + ESP_LOGI(STATUS_TAG, "Base Board Control: %s", (base_board_control_.GetUartPort() != 0) ? "✓ Initialized" : "✗ Not initialized"); + + // 功耗管理状态 + ESP_LOGI(STATUS_TAG, "Power Management: %s", (current_power_mode_ == POWER_MODE_NORMAL) ? "✓ Normal mode" : "⚠ Low power mode"); + ESP_LOGI(STATUS_TAG, " Current Mode: %d", current_power_mode_); + ESP_LOGI(STATUS_TAG, " Module Power States: 0x%08X", power_state_flags_); + + // 内存状态 + ESP_LOGI(STATUS_TAG, "Memory Status:"); + ESP_LOGI(STATUS_TAG, " Internal RAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + ESP_LOGI(STATUS_TAG, " PSRAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + + ESP_LOGI(STATUS_TAG, "=== End of Hardware Status Report ==="); +} \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_14/config.h b/main/02_physical/boards/board_v1_1_14/config.h new file mode 100644 index 0000000..0eed794 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_14/config.h @@ -0,0 +1,132 @@ +/* 定义引脚分配 */ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +/** + * @file config.h + * @brief 定义了引脚的分配。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +#include "driver/gpio.h" +#include "driver/i2c_master.h" +#include "driver/i2s.h" +#include "esp_log.h" +#include "esp_rom_sys.h" // 用于 esp_rom_delay_us +#include "esp_timer.h" +#include "esp_mac.h" +#include "driver/ledc.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "driver/timer.h" +#include "esp_intr_alloc.h" +#include "soc/timer_group_struct.h" // 包含TIMERG0、TIMERG1的结构体定义 +#include "soc/timer_group_reg.h" // 包含定时器相关寄存器宏定义 +#include "driver/uart.h" +#include "esp_err.h" +#include "freertos/queue.h" +#include "soc/uart_reg.h" +#include "linear_motor.h" +#include "gyroscope.h" + +#define TAG_BOARD "SWEEKAR_ESP32" +/*I2C总线引脚定义*/ +#define I2C0_MASTER_PORT I2C_NUM_0 +#define I2C0_MASTER_SDA_IO GPIO_NUM_2 +#define I2C0_MASTER_SCL_IO GPIO_NUM_3 + +/* 步进电机配置 */ +#define STEPPER_STEP_IO GPIO_NUM_42 // 步进电机脉冲输入引脚 +#define STEPPER_TIMER_RES_HZ 1000000 // 步进电机定时器分辨率 1 MHz(1 us 步进) + +/* 定义屏幕驱动控制引脚 */ +#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚 +#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL +#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚 +#define ST7789_PIN_CS GPIO_NUM_46 // SPI片选引脚 +#define ST7789_PIN_BL GPIO_NUM_45 // 背光引脚 +#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚 +#define LCD_BL_ACTIVE_LEVEL 0 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS) + +#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数) +#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数) + +/* 毫米波雷达配置参数 */ +/* 定义毫米波雷达的中断引脚 */ +#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35 +// UART 配置参数 +#define RADAR_UART_NUM UART_NUM_1 // 使用 UART1 +#define UART_TX_PIN GPIO_NUM_40 // GPIO40 作为 TX(根据实际硬件连接调整) +#define UART_RX_PIN GPIO_NUM_39 // GPIO39 作为 RX +#define RADAR_BAUD_RATE 9600 // 雷达波特率 +#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小 + +/* IO扩展硬件配置常量 */ +#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000) +#define I2C_IO_EXPAND_SLAVE_ADDR 0x58 // AW9523BTQR器件地址,v1_1_13的addr1和addr0是0 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚 +#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值 +#define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚 + +/* 定义线性马达的I2C从机配置常量 */ +#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址 + +/* 定义陀螺仪的I2C从机配置常量 */ +#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址 +#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚 + +/* 原生触摸引脚配置 */ +// 触摸按键数量配置 +#define TOUCH_BUTTON_NUM 3 +// 触摸通道定义 +#define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11 +#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12 +#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13 + +/* ES8311音频编解码器配置 (ESP-ADF兼容) */ +#define AUDIO_INPUT_SAMPLE_RATE 24000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 +#define AUDIO_INPUT_REFERENCE true + +/* I2S GPIO定义 */ +#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15 +#define AUDIO_I2S_GPIO_WS GPIO_NUM_4 +#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5 +#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6 +#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7 + +/* PA引脚定义 */ +#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC + +/* I2C配置 */ +#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2 +#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3 +#define AUDIO_CODEC_ES8311_ADDR 0x18 +#define AUDIO_CODEC_ES7210_ADDR 0x40 + +/* WS2812 RGB LED配置 */ +#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚 +#define WS2812_NUM_LEDS 2 // WS2812 LED数量 + +/* 创建VBAT to VBAT_5V */ +#define VBAT_5V_PIN GPIO_NUM_NC // VBAT_5V引脚 + +/* 定义按键的中断引脚 */ +#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚 +#define RIGHT_BUTTON_PIN GPIO_NUM_8 // 按键中断引脚 + +/* 底座控制命令串口配置 */ +#define BASE_BOARD_CTL_UART_PORT UART_NUM_0 +#define BASE_BOARD_CTL_UART_TX_PIN GPIO_NUM_43 +#define BASE_BOARD_CTL_UART_RX_PIN GPIO_NUM_44 +#define BASE_BOARD_CTL_UART_BAUDRATE 115200 +#define BASE_BOARD_CTL_UART_BUF_SIZE 256 + +/* 背光控制引脚配置 */ +#define BL_PIN GPIO_NUM_45 + +#endif // _BOARD_CONFIG_H_ diff --git a/main/02_physical/boards/board_v1_1_14/io_expansion_board.cc b/main/02_physical/boards/board_v1_1_14/io_expansion_board.cc new file mode 100644 index 0000000..a4a345c --- /dev/null +++ b/main/02_physical/boards/board_v1_1_14/io_expansion_board.cc @@ -0,0 +1,1023 @@ +#include "io_expansion_board.h" +#include "millimeter_wave_radar.h" +#include "photo_interrupter.h" +#include "adc_battery_monitor.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_check.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/idf_additions.h" +#include "freertos/portable.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_rom_sys.h" +/** + * @file io_expansion_board.cc + * @brief IO扩展板功能实现类,包含I2C通信、GPIO中断配置、外设控制等功能 + * @details 实现了IO扩展板的初始化(中断引脚、复位引脚)、寄存器读写、步进电机控制(细分模式、使能、方向、睡眠状态)、 + * LCD相关引脚控制(背光、复位、片选)、毫米波雷达中断引脚配置等功能,并提供I2C数据读取任务的创建与管理 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +/** + * @brief 构造函数 + */ +IOExpansionBoard::IOExpansionBoard() + : bus_handle_(nullptr), + device_addr_(0), + last_port0_state_(0), + last_port1_state_(0), + radar_last_state_(false), + i2c_task_event_group_(nullptr), + xI2CReadTaskHandle_(nullptr), + is_initialized_(false), + interrupt_gpio_(GPIO_NUM_NC), + reset_gpio_(GPIO_NUM_NC) +{ +} + +/** + * @brief 析构函数 + */ +IOExpansionBoard::~IOExpansionBoard() +{ + // 删除任务 + if (xI2CReadTaskHandle_) { + vTaskDelete(xI2CReadTaskHandle_); + } + + // if(pI2CReadTaskStackBuffer) { + // heap_caps_free(pI2CReadTaskStackBuffer); + // pI2CReadTaskStackBuffer = nullptr; + // } + + // if(pxI2CReadTaskBuffer) { + // vPortFree(pxI2CReadTaskBuffer); + // pxI2CReadTaskBuffer = nullptr; + // } + + // 删除事件组 + if (i2c_task_event_group_) { + vEventGroupDelete(i2c_task_event_group_); + } + + // 移除中断处理 + if (interrupt_gpio_ != GPIO_NUM_NC) { + gpio_isr_handler_remove(interrupt_gpio_); + } + + // 删除IO扩展板设备 + // 使用i2c_bus API时不需要手动删除设备句柄 + // bus_handle_由board_sweekar统一管理 +} + +/** + * @brief 静态中断处理函数 + */ +void IRAM_ATTR IOExpansionBoard::GpioIsrHandler(void* arg) +{ + IOExpansionBoard* instance = static_cast(arg); + if (!instance) return; + + // 调试:记录中断触发 + // ESP_EARLY_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "中断触发!"); // IRAM函数中不能使用普通日志 + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // 设置事件标志位 + if (instance->i2c_task_event_group_) { + xEventGroupSetBitsFromISR( + instance->i2c_task_event_group_, + BIT0, + &xHigherPriorityTaskWoken + ); + } + + // 触发上下文切换 + if (xHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); + } +} + +/** + * @brief 初始化GPIO中断检测 + */ +esp_err_t IOExpansionBoard::InterruptGpioInit(gpio_num_t gpio_num) +{ + // 配置IO扩展板中断引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_ANYEDGE; // 改为双沿触发,检测上升沿和下降沿 + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + // io_conf.pull_up_en = GPIO_PULLUP_DISABLE; + // io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE; + + + esp_err_t err = gpio_config(&io_conf); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + // 配置中断服务 + err = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3); + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断服务安装失败,错误码: 0x%x", err); + return err; + } + // 注册中断处理函数 + err = gpio_isr_handler_add(gpio_num, GpioIsrHandler, this); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断处理函数添加失败,错误码: 0x%x", err); + return err; + } + // 创建事件组 + i2c_task_event_group_ = xEventGroupCreate(); + if (!i2c_task_event_group_) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "事件组创建失败"); + return ESP_FAIL; + } + + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d中断初始化完成", gpio_num); + return ESP_OK; +} + +/** + * @brief 初始化硬件复位引脚 + * 设置为上拉,需要复位,需要输出低电平为20us的脉冲信号 + */ +esp_err_t IOExpansionBoard::ResetGpioInit(gpio_num_t gpio_num) +{ + reset_gpio_ = gpio_num; + + // 配置复位引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + esp_err_t err = gpio_config(&io_conf); + gpio_set_level(gpio_num, 1); // 复位引脚拉高 + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d复位引脚初始化完成", gpio_num); + return err; + } +} + +/** + * @brief 计算Port0的字节值,用于配置输入还是输出模式(0为输出模式,1为输入模式) + * @return uint8_t 操作结果 + */ +uint8_t IOExpansionBoard::ByteCalculatePort0() +{ + uint8_t byte_val = 0x00; // 初始化为所有引脚为输出模式(0),然后根据配置设置为输入模式(1) + + // 输入模式配置:将对应位置位(1为输入模式) + if(RADAR_INTERRUPT_CONFIG == CONFIG_PORT0){ //雷达中断引脚 + byte_val |= (1 << RADAR_INTERRUPT_PIN); + } + if(START_PHOTO_INTERRUPTER_CONFIG == CONFIG_PORT0){ //起始光学传感器 + byte_val |= (1 << START_PHOTO_INTERRUPTER_PIN); + } + if(END_PHOTO_INTERRUPTER_PORT_CONFIG == CONFIG_PORT0){ //结束光学传感器 + byte_val |= (1 << END_PHOTO_INTERRUPTER_PIN); + } + if(BATTERY_FULL_CONFIG == CONFIG_PORT0){ //电池充满检测 + byte_val |= (1 << BATTERY_FULL_PIN); + } + if(BATTERY_CHRG_CONFIG == CONFIG_PORT0){ //电池充电检测 + byte_val |= (1 << BATTERY_CHRG_PIN); + } + + return byte_val; +} + +/** + * @brief 计算Port1的字节值,用于配置输入还是输出模式(0为输出模式,1为输入模式) + * @return uint8_t 操作结果 + */ +uint8_t IOExpansionBoard::ByteCalculatePort1() +{ + uint8_t byte_val = 0x00; // 初始化为所有引脚为输出模式(0),然后根据配置设置为输入模式(1) + + // 输入模式配置:将对应位置位(1为输入模式) + if(RADAR_INTERRUPT_CONFIG == CONFIG_PORT1){ //雷达中断引脚 + byte_val |= (1 << RADAR_INTERRUPT_PIN); + } + if(START_PHOTO_INTERRUPTER_CONFIG == CONFIG_PORT1){ //起始光学传感器 + byte_val |= (1 << START_PHOTO_INTERRUPTER_PIN); + } + if(END_PHOTO_INTERRUPTER_PORT_CONFIG == CONFIG_PORT1){ //结束光学传感器 + byte_val |= (1 << END_PHOTO_INTERRUPTER_PIN); + } + if(BATTERY_FULL_CONFIG == CONFIG_PORT1){ //电池充满检测 + byte_val |= (1 << BATTERY_FULL_PIN); + } + if(BATTERY_CHRG_CONFIG == CONFIG_PORT1){ //电池充电检测 + byte_val |= (1 << BATTERY_CHRG_PIN); + } + + return byte_val; +} + +/** + * @brief 复位IO扩展板 + */ +esp_err_t IOExpansionBoard::ResetIoExpand() +{ + if (reset_gpio_ == GPIO_NUM_NC) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位引脚未初始化"); + return ESP_ERR_INVALID_STATE; + } + + // 复位IO扩展板 + gpio_set_level(reset_gpio_, 0); + esp_rom_delay_us(30); + gpio_set_level(reset_gpio_, 1); + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "复位成功"); + } + return ESP_OK; +} + +/** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::IoexpandWriteReg(uint8_t reg_addr, uint8_t data) +{ + return i2c_bus_write_bytes(bus_handle_, device_addr_, ®_addr, 1, &data, 1); +} + +/** + * @brief 从寄存器读取数据 + * @param reg_addr 寄存器地址(如INPUT_PORT0、ID等) + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果(ESP_OK为成功) + */ +esp_err_t IOExpansionBoard::IoexpandReadReg(uint8_t reg_addr, uint8_t* data) +{ + if (data == nullptr){ // 检查输入参数有效性 + return ESP_ERR_INVALID_ARG; + } + + // 使用i2c_bus_read_bytes进行寄存器读取 + esp_err_t err = i2c_bus_read_bytes(bus_handle_, device_addr_, ®_addr, 1, data, 1); + if (err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "读取寄存器失败,错误码:0x%x", err); + return err; + } + + return ESP_OK; +} + +/** + * @brief 读取输入端口0寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::ReadInputPort0(uint8_t* data) +{ + return IoexpandReadReg(INPUT_PORT0, data); +} + +/** + * @brief 读取输入端口1寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::ReadInputPort1(uint8_t* data) +{ + return IoexpandReadReg(INPUT_PORT1, data); +} + +//设置IO扩展板为输入模式或是输出模式 +/* +* 这里需要根据实际情况设置IO扩展板的模式,比如输入模式还是输出模式,以及各个引脚的配置。 +* P0_0 对应NFC_RST引脚,需要设置为输出模式,低电平有效。(待测) +* P0_1 对应USB_VBUS引脚,需要设置为输出模式,低电平有效。(待测) +* P0_2 对应BTN_RIGHT_EAR引脚,需要设置为输出模式,低电平有效。(待测) +* P0_3 暂时未使用。 +* P0_4 对应步进电机方向引脚,需要设置为输出模式,根据需求设置。(待测) +* P0_5 对应CHRG引脚(待测) +* P0_6 LCD_DC引脚,需要设置为输出模式,根据需求设置电平。(待测) +* P0_7 对应步进电机的使能引脚,需要设置为输出模式,根据需求设置。(待测) +* +* +* P1_0 对应EG800K_PWR。(待测) +* P1_1 对应LCD_RST,需要设置为输出模式,低电平有效。(待测) +* P1_2 对应LCD_CS,需要设置为输出模式,低电平有效。(待测) +* P1_3 暂时未使用。 +* P1_4 对应步进电机的细分模式M1引脚。(待测) +* P1_5 对应步进电机的细分模式M0引脚。(待测) +* P1_6 对应步进电机的睡眠引脚。(待测) +* P1_7 对应RADAR_O雷达的输出引脚。(待测) +* */ +esp_err_t IOExpansionBoard::IoexpandSetMode(void) +{ + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功"); + } + + err = IoexpandWriteReg(CONFIG_PORT0, ByteCalculatePort0()); + + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + // 打印BytecalculatePort0()结果 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功, 0x%02X", ByteCalculatePort0()); + } + + err = IoexpandWriteReg(CONFIG_PORT1, ByteCalculatePort1()); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口失败,错误码:0x%x", err); + return err; + } + else{ + // 打印BytecalculatePort1()结果 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口成功, 0x%02X", ByteCalculatePort1()); + } + // 配置P0_0-P0_7的初始为高电平 + // 配置P1_0-P1_7的初始为高电平 + err = IoexpandWriteReg(OUTPUT_PORT0, 0x40); // 0100 0000 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值成功"); + } + err = IoexpandWriteReg(OUTPUT_PORT1, 0x04); // 0000 0100 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值成功"); + } + + + // AW9523B中断使能配置:0为使能中断,1为禁止中断 + // 使能P0_5(充电检测)和P1_3(充满检测)的中断 + uint8_t int_enable_port0 = 0x00; // 0x00 = 使能所有P0引脚中断 + uint8_t int_enable_port1 = 0x00; // 0x00 = 使能所有P1引脚中断 + + err = IoexpandWriteReg(INT_PORT0, int_enable_port0); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口中断使能失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口中断使能成功: 0x%02X (0=使能)", int_enable_port0); + } + + err = IoexpandWriteReg(INT_PORT1, int_enable_port1); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能成功: 0x%02X (0=使能)", int_enable_port1); + } + + return ESP_OK; +} + +/** + * @brief 设置步进电机的细分模式 + */ +void IOExpansionBoard::SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin) +{ + uint8_t current_val; + switch (mode) { + case 1: //全步输出模式 低低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 2: //非圆 1/2 高低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val |= (1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 3: //1/4 步 低高电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val |= (1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 4: //1/8 步 高高电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val |= (1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val |= (1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + default: //全步输入模式 低低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + } +} + +/** + * @brief 设置步进电机的使能 + */ +esp_err_t IOExpansionBoard::SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin) +{ + uint8_t current_val; + if(enable){ + // 进入工作状态mode + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << enable_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << enable_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} +/** + * @brief 设置步进电机运行方向 + */ +esp_err_t IOExpansionBoard::StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin) +{ + uint8_t current_val; + if(dir){ + // 方向为正转 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/** + * @brief 设置步进电机是否进入睡眠或者工作状态(高电平进入工作状态,低电平进入睡眠状态) + */ +esp_err_t IOExpansionBoard::SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin) +{ + uint8_t current_val; + if(mode){ + // 进入工作状态mode + // ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入工作状态"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "电机睡眠输出寄存器: 0x%x", current_val); + current_val |= (1 << nsleep_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置电机睡眠输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + // ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入睡眠状态"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "电机睡眠输出寄存器: 0x%x", current_val); + current_val &= ~(1 << nsleep_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置电机睡眠输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/*********************************************IO扩展板LCD引脚配置参数***********************************************/ +/** + * @brief 设置 LCD_BL引脚电平(高电平为命令模式,低电平为数据模式) + */ +esp_err_t IOExpansionBoard::SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin) +{ + uint8_t current_val; + if(mode){ + // 进入命令模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << bl_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入数据模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << bl_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +esp_err_t IOExpansionBoard::SetLedEnMode(bool mode) +{ + return ESP_OK; +} + +/** + * @brief 设置 LCD_RST引脚电平(高电平为复位模式,低电平为工作模式) + */ +esp_err_t IOExpansionBoard::SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t reset_pin) +{ + uint8_t current_val; + if(mode){ + // 进入复位模式 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入复位模式"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "LCD复位输出寄存器: 0x%x", current_val); + current_val |= (1 << reset_pin); + //打印设置后的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置LCD复位输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入工作模式 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入工作模式"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "LCD复位输出寄存器: 0x%x", current_val); + current_val &= ~(1 << reset_pin); + //打印设置后的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置LCD复位输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/*********************************************IO扩展板的输入引脚配置以及中断引脚定义***********************************************/ +/** + * @brief 设置 毫米波雷达的中断引脚 + */ +esp_err_t IOExpansionBoard::SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin) +{ + uint8_t current_val; + if(mode){ + // 进入输入模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + current_val |= (1 << interrupt_pin); + return IoexpandWriteReg(INPUT_PORT, current_val); + } + else{ + // 进入输出模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + current_val &= ~(1 << interrupt_pin); + return IoexpandWriteReg(INPUT_PORT, current_val); + } +} + +/** + * @brief 设置 PA_CTRL引脚电平 + */ +esp_err_t IOExpansionBoard::SetPaCtrlMode(bool mode) +{ + uint8_t current_val; + if(mode){ + // 进入高电平状态 + ESP_LOGI("io_ex:", "read reg"); + IoexpandReadReg(PA_CTRL_PORT, ¤t_val); + current_val |= (1 << PA_CTRL_PIN); + return IoexpandWriteReg(PA_CTRL_PORT, current_val); + } + else{ + // 进入低电平状态 + IoexpandReadReg(PA_CTRL_PORT, ¤t_val); + current_val &= ~(1 << PA_CTRL_PIN); + return IoexpandWriteReg(PA_CTRL_PORT, current_val); + } +} + + + +/** + * @brief I2C数据读取任务主体 + */ +void IOExpansionBoard::I2cReadTask(void* pvParameters) +{ + IOExpansionBoard* instance = static_cast(pvParameters); + if (!instance) { + vTaskDelete(nullptr); + return; + } + // 初始化复位引脚 + esp_err_t err = instance->ResetGpioInit(IO_EXPAND_RSTN); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO复位初始化失败"); + } + + // 执行硬件复位 - 这是解决中断引脚持续拉低的关键 + err = instance->ResetIoExpand(); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板硬件复位失败"); + } else { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板硬件复位成功"); + + // 检查复位后的中断引脚状态 + int interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "复位后中断引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + } + + // 初始化IO扩展板子的中断引脚 + err = instance->InterruptGpioInit(GPIO_INPUT_PIN_SEL); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断初始化失败"); + } + // 设置IO扩展板模式 - 复位后必须重新配置寄存器! + err = instance->IoexpandSetMode(); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板模式配置失败"); + } else { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板模式配置成功"); + } + // 设置LCD屏幕复位引脚 + err = instance->SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功"); + } + // 设置LCD屏幕复位引脚为低电平 + err = instance->SetLcdResetMode(LCD_RST_LOW, LCD_RST_PORT, LCD_RST_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功"); + } + + uint8_t current_val_port0_ = 0,current_val_port1_ = 0,current_temp_ = 0; + for (;;) { + // 等待中断事件触发 + if (instance->i2c_task_event_group_) { + xEventGroupWaitBits(instance->i2c_task_event_group_, BIT0, pdTRUE, pdFALSE, portMAX_DELAY); + } + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板中断触发"); + + // 检查中断触发时的引脚状态 + int interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "中断触发时引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + + // AW9523B中断处理说明(根据数据手册): + // 1. 当输入引脚状态变化时,AW9523B会拉低INT引脚(连接到ESP32的GPIO10) + // 2. 通过读取输入端口寄存器(00H, 01H)来清除对应端口的中断 + // 3. 无独立的中断状态寄存器,需要通过输入电平变化来判断中断源 + // 4. 读取INPUT_PORT0 (00H) 清除P0口中断,读取INPUT_PORT1 (01H) 清除P1口中断 + + // 一次性读取两个端口的输入寄存器,避免重复读取和错误的OR操作 + instance->IoexpandReadReg(INPUT_PORT0, ¤t_val_port0_); + instance->IoexpandReadReg(INPUT_PORT1, ¤t_val_port1_); + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "读取端口状态 - Port0: 0x%02X, Port1: 0x%02X", current_val_port0_, current_val_port1_); + + // 检查读取寄存器后中断引脚是否被清除(应该恢复高电平) + interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "读取寄存器后中断引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + + //判断是否有中断来自雷达引脚 + if((RADAR_INTERRUPT_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << RADAR_INTERRUPT_PIN))){ + // 检查雷达引脚状态是否发生了变化,避免重复触发 + bool current_radar_state = (current_val_port0_ & (1 << RADAR_INTERRUPT_PIN)) != 0; + if (current_radar_state != instance->radar_last_state_) { + instance->radar_last_state_ = current_radar_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用毫米波雷达回调函数 + if (instance->radar_) { + instance->radar_->TriggerRadarDetectCallback(); + } + // 调用雷达回调函数(新接口) + if (instance->radar_callback_) { + instance->radar_callback_(); + } + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((RADAR_INTERRUPT_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << RADAR_INTERRUPT_PIN))){ + // 检查雷达引脚状态是否发生了变化,避免重复触发 + bool current_radar_state = (current_val_port1_ & (1 << RADAR_INTERRUPT_PIN)) != 0; + if (current_radar_state != instance->radar_last_state_) { + instance->radar_last_state_ = current_radar_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚1\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用毫米波雷达回调函数 + if (instance->radar_) { + instance->radar_->TriggerRadarDetectCallback(); + } + // 调用雷达回调函数(新接口) + if (instance->radar_callback_) { + instance->radar_callback_(); + } + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + // else{ + // ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "未检测到雷达引脚中断\n"); + // } + + //判断是否有中断来自初始光学传感器引脚 + if((START_PHOTO_INTERRUPTER_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << START_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port0_ & (1 << START_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port0_state_ & (1 << START_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自初始光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用初始光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerStartCallback(); + } + // 调用光学传感器开始回调函数(新接口) + if (instance->photo_start_callback_) { + instance->photo_start_callback_(); + } + // 更新状态 + instance->last_port0_state_ = current_val_port0_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((START_PHOTO_INTERRUPTER_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << START_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port1_ & (1 << START_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port1_state_ & (1 << START_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自初始光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用初始光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerStartCallback(); + } + // 调用光学传感器开始回调函数(新接口) + if (instance->photo_start_callback_) { + instance->photo_start_callback_(); + } + // 更新状态 + instance->last_port1_state_ = current_val_port1_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + // else{ + // // ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "未检测到初始光学传感器引脚中断\n"); + // } + + //判断是否有中断来自结束光学传感器引脚 + if((END_PHOTO_INTERRUPTER_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << END_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port0_ & (1 << END_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port0_state_ & (1 << END_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自结束光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用结束光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerEndCallback(); + } + // 调用光学传感器结束回调函数(新接口) + if (instance->photo_end_callback_) { + instance->photo_end_callback_(); + } + // 更新状态 + instance->last_port0_state_ = current_val_port0_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((END_PHOTO_INTERRUPTER_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << END_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port1_ & (1 << END_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port1_state_ & (1 << END_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自结束光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用结束光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerEndCallback(); + } + // 调用光学传感器结束回调函数(新接口) + if (instance->photo_end_callback_) { + instance->photo_end_callback_(); + } + // 更新状态 + instance->last_port1_state_ = current_val_port1_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + + //CHRG引脚充电前为高电平 充电中为低电平 充满电为高电平 + //FULL未充满为高电平 充满电为低电平 + //判断是否有中断来自电池充电引脚 + //根据配置:BATTERY_CHRG_INPUT = INPUT_PORT0, BATTERY_FULL_INPUT = INPUT_PORT1 + + // AW9523B没有独立的中断状态寄存器,需要通过比较前后状态变化来判断中断源 + // 由于读取输入端口会清除中断,我们需要先保存当前状态,然后与上次状态比较 + + //获取当前电池状态 + bool current_charging_state = !(current_val_port0_ & (1 << BATTERY_CHRG_PIN)); // CHRG低电平表示充电中 + bool current_full_state = !(current_val_port1_ & (1 << BATTERY_FULL_PIN)); // FULL低电平表示已充满 + + // 详细的调试信息 + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - Port0: 0x%02X, Port1: 0x%02X", current_val_port0_, current_val_port1_); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - CHRG_PIN: %d (bit %d), FULL_PIN: %d (bit %d)", + (current_val_port0_ & (1 << BATTERY_CHRG_PIN)) ? 1 : 0, BATTERY_CHRG_PIN, + (current_val_port1_ & (1 << BATTERY_FULL_PIN)) ? 1 : 0, BATTERY_FULL_PIN); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - 充电状态: %s, 充满状态: %s", + current_charging_state ? "充电中" : "未充电", + current_full_state ? "已充满" : "未充满"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - 上次充电状态: %s, 上次充满状态: %s", + instance->battery_charging_last_state_ ? "充电中" : "未充电", + instance->battery_full_last_state_ ? "已充满" : "未充满"); + + //检查充电状态是否发生变化 + if (current_charging_state != instance->battery_charging_last_state_) { + instance->battery_charging_last_state_ = current_charging_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "电池充电状态变化: %s", current_charging_state ? "充电中" : "未充电"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "充电状态变化详情 - 从 %s 到 %s", + instance->battery_charging_last_state_ ? "未充电" : "充电中", + current_charging_state ? "充电中" : "未充电"); + + if (current_charging_state) { + // 进入充电状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到开始充电"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerChrgCallback(); + } + if (instance->battery_charging_callback_) { + instance->battery_charging_callback_(); + } + } else { + // 退出充电状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到停止充电"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerNotChrgCallback(); + } + if (instance->battery_not_charging_callback_) { + instance->battery_not_charging_callback_(); + } + } + } + + //检查充满状态是否发生变化 + if (current_full_state != instance->battery_full_last_state_) { + instance->battery_full_last_state_ = current_full_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "电池充满状态变化: %s", current_full_state ? "已充满" : "未充满"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "充满状态变化详情 - 从 %s 到 %s", + instance->battery_full_last_state_ ? "未充满" : "已充满", + current_full_state ? "已充满" : "未充满"); + + if (current_full_state) { + // 进入充满状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到电池已充满"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerFullCallback(); + } + if (instance->battery_full_callback_) { + instance->battery_full_callback_(); + } + } + + } + + // 根据AW9523B数据手册:读取输入端口寄存器清除对应端口的中断 + // 读取INPUT_PORT0 (00H) 清除P0口中断,读取INPUT_PORT1 (01H) 清除P1口中断 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "中断处理完成,已读取输入端口寄存器清除中断标志"); + } +} + + +/** + * @brief 创建I2C数据读取任务 + */ +void IOExpansionBoard::CreateI2cReadTask() +{ + printf("创建I2C读取任务之前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之前:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + if (xI2CReadTaskHandle_) { + return; // 任务已创建 + } + + xTaskCreateWithCaps( + I2cReadTask, + "i2c_read_task", + I2C_TASK_STACK, + this, + I2C_TASK_PRIORITY, + &xI2CReadTaskHandle_, + MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT + ); + + if (xI2CReadTaskHandle_ == NULL) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to create static I2C read task"); + } else { + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static I2C read task created successfully"); + } + printf("创建I2C读取任务之后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之后:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +} + +/** + * @brief 启动I2C任务 (整合初始化和任务创建) + */ +esp_err_t IOExpansionBoard::StartTask() +{ + // 再创建任务 + if (!xI2CReadTaskHandle_) { + CreateI2cReadTask(); + } + return ESP_OK; +} diff --git a/main/02_physical/boards/board_v1_1_14/io_expansion_board.h b/main/02_physical/boards/board_v1_1_14/io_expansion_board.h new file mode 100644 index 0000000..f2c0c3c --- /dev/null +++ b/main/02_physical/boards/board_v1_1_14/io_expansion_board.h @@ -0,0 +1,421 @@ +#ifndef IO_EXPANSION_BOARD_H +#define IO_EXPANSION_BOARD_H + +#include +#include +#include +#include +#include +#include +#include "i2c_bus.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include +#include +#include +#include +#include +#include +#include +#include "esp_err.h" +#include "config.h" +#include "portmacro.h" + +// 前向声明,避免循环引用 +class MillimeterWaveRadar; +class PhotoInterrupter; +class AdcBatteryMonitor; + +// 回调函数类型定义 +typedef std::function RadarCallback; +typedef std::function PhotoInterrupterStartCallback; +typedef std::function PhotoInterrupterEndCallback; +typedef std::function BatteryChargingCallback; +typedef std::function BatteryFullCallback; +typedef std::function BatteryNotChargingCallback; + +/* 寄存器地址 */ +#define INPUT_PORT0 0x00 // 输入端口0寄存器 +#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取) +#define OUTPUT_PORT0 0x02 // 输出端口0寄存器 +#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平 +#define CONFIG_PORT0 0x04 // 配置端口0寄存器 +#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式 +#define INT_PORT0 0x06 // 中断端口0寄存器 +#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的) +#define CTL 0x11 // 全局控制寄存器 +#define ID 0x23 // 芯片ID寄存器(0x23) + +/***********************************IO扩展板电机引脚配置参数*************************************/ +/* 设置步进电机方向 */ +#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转 +#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转 +#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4 +#define STEPPER_MOTOR_DIR_CONFIG CONFIG_PORT0 //步进电机方向引脚配置在P0_4 + +/* 设置步进电机细分模式 */ +#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5 +#define STEPPER_MOTOR_M0_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define STEPPER_MOTOR_M0_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_5 + +#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4 +#define STEPPER_MOTOR_M1_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define STEPPER_MOTOR_M1_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_4 + +/* 设置步进电机睡眠引脚 */ +#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式 +#define STEPPER_MOTOR_WORK true //步进电机进入工作模式 +#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6 +#define STEPPER_MOTOR_SLEEP_CONFIG CONFIG_PORT1 //步进电机睡眠引脚配置在P1_6 +#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 + +/* 设置电机的使能引脚 */ +#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7 +#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_ENABLE_CONFIG CONFIG_PORT0 //电机使能引脚配置在P0_7 +#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平 +#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平 + +/* 设置毫米波雷达对应IO扩展板的中断引脚 */ +#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7 +#define RADAR_INTERRUPT_CONFIG CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口 +#define RADAR_INTERRUPT_INPUT INPUT_PORT1 //毫米波雷达中断引脚输入状态检测在INPUT_PORT1 +#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态 +#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态 +/* 任务配置常量 */ +#define WRITE_BUF_SIZE 2 // I2C单次写入字节数 +#define READ_BUF_SIZE 2 // I2C单次读取字节数 +#define I2C_TASK_PRIORITY 2 // 任务优先级(中等) +#define I2C_TASK_STACK 4096 // 任务栈大小(4KB) + +// 光学传感器引脚定义 +#define START_PHOTO_INTERRUPTER_PIN 2 // 光学传感器引脚(P0_2) +#define START_PHOTO_INTERRUPTER_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口 +#define START_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0 +#define START_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平 +#define START_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平 + +#define END_PHOTO_INTERRUPTER_PIN 3 // 光学传感器引脚(P0_3) +#define END_PHOTO_INTERRUPTER_PORT_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口 +#define END_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0 +#define END_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平 +#define END_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平 + +/***********************************IO扩展板LCD引脚配置参数*************************************/ +// /* 设置LCD的BL引脚 */ +// #define LCD_BL_PIN 6 //LCD背光引脚对应IO扩展板引脚P0_6 +// #define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +// #define LCD_BL_CONFIG CONFIG_PORT0 //LCD背光引脚配置在P0_6 +// #define LCD_BL_HIGH true //LCD背光引脚状态为高电平 +// #define LCD_BL_LOW false //LCD背光引脚状态为低电平 + +/* 设置LCD的RST引脚 */ +#define LCD_RST_PIN 1 //LCD复位引脚对应IO扩展板引脚P1_1 +#define LCD_RST_CONFIG CONFIG_PORT1 //LCD复位引脚配置在P1_1 +#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define LCD_RST_HIGH true //LCD复位引脚状态为高电平 +#define LCD_RST_LOW false //LCD复位引脚状态为低电平 + +/* 设置PA控制引脚 */ +#define PA_CTRL_PIN 2 //PA控制引脚对应IO扩展板引脚P1_2 +#define PA_CTRL_CONFIG CONFIG_PORT1 //PA控制引脚配置在P1_2 +#define PA_CTRL_PORT OUTPUT_PORT1 //PA控制引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define PA_CTRL_HIGH true //PA控制引脚状态为高电平 +#define PA_CTRL_LOW false //PA控制引脚状态为低电平 + +// 电池充电检测引脚定义 +#define BATTERY_FULL_INPUT INPUT_PORT1 // 电池充满检测引脚挂载在IO扩展板的输入端口 +#define BATTERY_FULL_PIN 3 // 电池充满检测引脚对应IO扩展板引脚P1_3 +#define BATTERY_FULL_CONFIG CONFIG_PORT1 // 电池充满检测引脚配置在P1_3 + +#define BATTERY_CHRG_INPUT INPUT_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口 +#define BATTERY_CHRG_PIN 5 // 充电检测引脚(P0_5) +#define BATTERY_CHRG_CONFIG CONFIG_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口 + +#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签 +#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签 + +// GPIO引脚定义 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚 +// #define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚 + +/** + * @class IOExpansionBoard + * @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作 + */ +class IOExpansionBoard +{ +public: + /** + * @brief 构造函数 + */ + IOExpansionBoard(); + + /** + * @brief 设置毫米波雷达指针 + * @param radar 毫米波雷达对象指针 + */ + void SetRadar(MillimeterWaveRadar* radar) { radar_ = radar; }; + + /** + * @brief 设置限位开关指针 + * @param photo_interrupter 限位开关对象指针 + */ + void setPhotoInterrupter(PhotoInterrupter* photo_interrupter) { photo_interrupter_ = photo_interrupter; }; + + /** + * @brief 设置电池监控器指针 + * @param battery_monitor 电池监控器对象指针 + */ + void setBatteryMonitor(AdcBatteryMonitor* battery_monitor) { battery_monitor_ = battery_monitor; }; + + /** + * @brief 析构函数 + */ + ~IOExpansionBoard(); + + /** + * @brief 初始化GPIO中断检测 + * @param gpio_num 中断引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t InterruptGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetIoExpand(); + + /** + * @brief 初始化I2C主机通信 + * @return esp_err_t 初始化结果 + */ + // esp_err_t IoExpansionI2cInit(); + + /** + * @brief 创建I2C数据读取任务 + */ + void CreateI2cReadTask(); + + /** + * @brief 启动I2C任务(整合初始化和任务创建) + * @return esp_err_t 操作结果 + */ + esp_err_t StartTask(); + + /** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data); + + /** + * @brief 读寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要读出的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data); + + /** + * @brief 读取输入端口0寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t ReadInputPort0(uint8_t *data); + + /** + * @brief 读取输入端口1寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t ReadInputPort1(uint8_t *data); + + // /** + // * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断 + // * @param reg_addr 寄存器地址 + // * @return esp_err_t 操作结果 + // */ + // esp_err_t SetInterruptStatus(bool status); + + /** + * @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandSetMode(); + + /** + * @brief 设置步进电机的细分模式 + * @param mode 模式:1/2/4/8/16/32/64 + * @return esp_err_t 操作结果 + */ + void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin); + + /** + * @brief 设置步进电机的方向 + * @param dir 方向 + * @param OUTPUT_PORT 输出端口 + * @param pin 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin); + + /** + * @brief 设置步进电机的睡眠模式 + * @param 是否进入睡眠模式 + * @param 输出端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin); + + /** + * @brief 设置步进电机的使能引脚状态 + * @param 使能状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin); + + /** + * @brief 设置LCD的BL引脚状态 + * @param BL状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin); + + esp_err_t SetLedEnMode(bool mode); + + /** + * @brief 设置LCD的RST引脚状态 + * @param RST状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin); + + /** + * @brief 设置PA控制引脚状态 + * @param mode PA_CTRL状态(true为高电平,false为低电平) + * @return esp_err_t 操作结果 + */ + esp_err_t SetPaCtrlMode(bool mode); + + /** + * @brief 设置雷达中断引脚 + * @param 毫米波雷达的中断引脚模式 + * @param 输入端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin); + + /** + * @brief 计算Port0的字节值 + * @return uint8_t 操作结果 + */ + uint8_t ByteCalculatePort0(); + + /** + * @brief 计算Port1的字节值 + * @return uint8_t 操作结果 + */ + uint8_t ByteCalculatePort1(); + + /** + * @brief 设置雷达中断回调函数 + * @param callback 雷达中断回调函数 + */ + void SetRadarCallback(RadarCallback callback) { radar_callback_ = callback; } + + /** + * @brief 设置光学传感器开始中断回调函数 + * @param callback 光学传感器开始中断回调函数 + */ + void SetPhotoInterrupterStartCallback(PhotoInterrupterStartCallback callback) { photo_start_callback_ = callback; } + + /** + * @brief 设置光学传感器结束中断回调函数 + * @param callback 光学传感器结束中断回调函数 + */ + void SetPhotoInterrupterEndCallback(PhotoInterrupterEndCallback callback) { photo_end_callback_ = callback; } + + /** + * @brief 设置电池充电中断回调函数 + * @param callback 电池充电中断回调函数 + */ + void SetBatteryChargingCallback(BatteryChargingCallback callback) { battery_charging_callback_ = callback; } + + /** + * @brief 设置电池充满中断回调函数 + * @param callback 电池充满中断回调函数 + */ + void SetBatteryFullCallback(BatteryFullCallback callback) { battery_full_callback_ = callback; } + + /** + * @brief 设置电池非充电中断回调函数 + * @param callback 电池非充电中断回调函数 + */ + void SetBatteryNotChargingCallback(BatteryNotChargingCallback callback) { battery_not_charging_callback_ = callback; } + + // 公共成员变量 + i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄 + uint8_t device_addr_; // I2C设备地址 + +private: + // 静态成员函数 + MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调 + PhotoInterrupter* photo_interrupter_ = nullptr; // 限位开关指针,用于触发回调 + AdcBatteryMonitor* battery_monitor_ = nullptr; // 电池监控器指针,用于触发回调 + static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数 + static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数 + + // 成员变量用于状态跟踪 + uint8_t last_port0_state_ = 0; // 上次检测到的Port0状态 + uint8_t last_port1_state_ = 0; // 上次检测到的Port1状态 + bool radar_last_state_ = false; // 雷达引脚上一次的状态 + bool battery_charging_last_state_ = false; // 电池充电状态上一次的状态 + bool battery_full_last_state_ = false; // 电池充满状态上一次的状态 + + // 回调函数成员变量 + RadarCallback radar_callback_ = nullptr; + PhotoInterrupterStartCallback photo_start_callback_ = nullptr; + PhotoInterrupterEndCallback photo_end_callback_ = nullptr; + BatteryChargingCallback battery_charging_callback_ = nullptr; + BatteryFullCallback battery_full_callback_ = nullptr; + BatteryNotChargingCallback battery_not_charging_callback_ = nullptr; + + // PhotoInterrupter* photo_interrupter_ = nullptr; // 光学传感器指针,用于触发回调 + // /** + // * @brief 分配静态任务所需的内存 + // * @return bool 分配是否成功 + // */ + // bool AllocateStaticTaskMemory(); + + // /** + // * @brief 释放静态任务分配的内存 + // */ + // void FreeStaticTaskMemory(); + + // 实例成员变量 + EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组 + TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄 + bool is_initialized_ = false; // 初始化状态标记(新增) + gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚 + gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚 + + // StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM) + // StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM) +}; + +#endif diff --git a/main/02_physical/boards/board_v1_1_14/power_management_config.h b/main/02_physical/boards/board_v1_1_14/power_management_config.h new file mode 100644 index 0000000..da609fb --- /dev/null +++ b/main/02_physical/boards/board_v1_1_14/power_management_config.h @@ -0,0 +1,178 @@ +/** + * @file power_management_config.h + * @brief 功耗管理配置和策略定义 + * @author Embedded Software Expert + * @date 2025年1月 + * + * 这个文件定义了功耗管理的配置参数、策略和优化建议, + * 为系统提供灵活的功耗管理方案。 + */ + +#ifndef POWER_MANAGEMENT_CONFIG_H +#define POWER_MANAGEMENT_CONFIG_H + +#include "esp_sleep.h" +#include "driver/rtc_io.h" +#include "esp32/rom/rtc.h" + +/** + * @brief 功耗管理配置结构体 + */ +typedef struct { + // 睡眠模式配置 + uint64_t light_sleep_duration_us; // 轻度睡眠持续时间(微秒) + uint64_t deep_sleep_duration_us; // 深度睡眠持续时间(微秒) + + // 唤醒源配置 + bool enable_timer_wakeup; // 启用定时器唤醒 + bool enable_gpio_wakeup; // 启用GPIO唤醒 + bool enable_touch_wakeup; // 启用触摸唤醒 + gpio_num_t wakeup_gpio_num; // 唤醒GPIO编号 + int wakeup_level; // 唤醒电平(0或1) + + // 功耗优化配置 + bool disable_bt_in_sleep; // 睡眠时关闭蓝牙 + bool disable_wifi_in_sleep; // 睡眠时关闭WiFi + bool reduce_cpu_frequency; // 降低CPU频率 + uint32_t cpu_frequency_hz; // CPU频率(Hz) + + // 外设功耗配置 + bool power_down_sdcard; // 睡眠时关闭SD卡电源 + bool power_down_display; // 睡眠时关闭显示电源 + bool power_down_audio; // 睡眠时关闭音频电源 + bool power_down_motor; // 睡眠时关闭电机电源 + + // RTC内存配置 + bool preserve_rtc_memory; // 保留RTC内存 + size_t rtc_memory_size; // RTC内存大小 +} power_management_config_t; + +/** + * @brief 默认功耗管理配置 + */ +#define DEFAULT_POWER_CONFIG { \ + .light_sleep_duration_us = 1000000, /* 1秒 */ \ + .deep_sleep_duration_us = 30000000, /* 30秒 */ \ + .enable_timer_wakeup = true, /* 启用定时器唤醒 */ \ + .enable_gpio_wakeup = false, /* 不启用GPIO唤醒 */ \ + .enable_touch_wakeup = false, /* 不启用触摸唤醒 */ \ + .wakeup_gpio_num = GPIO_NUM_NC, /* 无GPIO唤醒 */ \ + .wakeup_level = 0, /* 低电平唤醒 */ \ + .disable_bt_in_sleep = true, /* 睡眠时关闭蓝牙 */ \ + .disable_wifi_in_sleep = true, /* 睡眠时关闭WiFi */ \ + .reduce_cpu_frequency = true, /* 降低CPU频率 */ \ + .cpu_frequency_hz = 80000000, /* 80MHz */ \ + .power_down_sdcard = true, /* 睡眠时关闭SD卡 */ \ + .power_down_display = true, /* 睡眠时关闭显示 */ \ + .power_down_audio = true, /* 睡眠时关闭音频 */ \ + .power_down_motor = true, /* 睡眠时关闭电机 */ \ + .preserve_rtc_memory = true, /* 保留RTC内存 */ \ + .rtc_memory_size = 4096, /* 4KB RTC内存 */ \ +} + +/** + * @brief 各功耗模式的详细配置 + */ +static const power_management_config_t idle_mode_config = { + .light_sleep_duration_us = 500000, // 500ms轻度睡眠 + .deep_sleep_duration_us = 0, // 不使用深度睡眠 + .enable_timer_wakeup = true, + .enable_gpio_wakeup = true, + .wakeup_gpio_num = GPIO_NUM_0, // 按键唤醒 + .wakeup_level = 0, + .disable_bt_in_sleep = false, // 保持蓝牙连接 + .disable_wifi_in_sleep = false, // 保持WiFi连接 + .reduce_cpu_frequency = true, + .cpu_frequency_hz = 40000000, // 40MHz + .power_down_sdcard = false, // 保持SD卡(可能有后台任务) + .power_down_display = true, // 关闭显示背光 + .power_down_audio = true, // 关闭音频 + .power_down_motor = true, // 关闭电机 + .preserve_rtc_memory = true, + .rtc_memory_size = 2048, +}; + +static const power_management_config_t light_sleep_config = { + .light_sleep_duration_us = 0, // 直接进入轻度睡眠 + .deep_sleep_duration_us = 0, + .enable_timer_wakeup = true, + .enable_gpio_wakeup = true, + .wakeup_gpio_num = GPIO_NUM_0, + .wakeup_level = 0, + .disable_bt_in_sleep = true, // 关闭蓝牙 + .disable_wifi_in_sleep = true, // 关闭WiFi + .reduce_cpu_frequency = true, + .cpu_frequency_hz = 40000000, + .power_down_sdcard = true, // 关闭SD卡 + .power_down_display = true, // 关闭显示 + .power_down_audio = true, // 关闭音频 + .power_down_motor = true, // 关闭电机 + .preserve_rtc_memory = true, + .rtc_memory_size = 4096, +}; + +static const power_management_config_t deep_sleep_config = { + .light_sleep_duration_us = 0, + .deep_sleep_duration_us = 60000000, // 60秒深度睡眠 + .enable_timer_wakeup = true, + .enable_gpio_wakeup = true, + .wakeup_gpio_num = GPIO_NUM_0, + .wakeup_level = 0, + .disable_bt_in_sleep = true, // 关闭蓝牙 + .disable_wifi_in_sleep = true, // 关闭WiFi + .reduce_cpu_frequency = true, + .cpu_frequency_hz = 10000000, // 10MHz + .power_down_sdcard = true, // 关闭SD卡 + .power_down_display = true, // 关闭显示 + .power_down_audio = true, // 关闭音频 + .power_down_motor = true, // 关闭电机 + .preserve_rtc_memory = true, + .rtc_memory_size = 8192, +}; + +/** + * @brief 功耗统计和监控结构体 + */ +typedef struct { + uint64_t total_sleep_time_us; // 总睡眠时间 + uint64_t total_wake_time_us; // 总唤醒时间 + uint32_t sleep_count; // 睡眠次数 + uint32_t wake_count; // 唤醒次数 + uint32_t average_sleep_duration_us; // 平均睡眠时长 + uint32_t average_wake_duration_us; // 平均唤醒时长 + float estimated_power_saving_percent; // 估计的功耗节省百分比 +} power_statistics_t; + +/** + * @brief 功耗优化建议 + * + * 基于硬件特性和使用模式,提供功耗优化建议 + */ +typedef enum { + OPTIMIZATION_NONE = 0, + OPTIMIZATION_REDUCE_CPU_FREQ, // 降低CPU频率 + OPTIMIZATION_DISABLE_UNUSED_PERIPHERALS, // 关闭未使用的外设 + OPTIMIZATION_USE_LIGHT_SLEEP, // 使用轻度睡眠 + OPTIMIZATION_USE_DEEP_SLEEP, // 使用深度睡眠 + OPTIMIZATION_OPTIMIZE_GPIO_STATES, // 优化GPIO状态 + OPTIMIZATION_USE_RTC_MEMORY, // 使用RTC内存 + OPTIMIZATION_BATCH_OPERATIONS, // 批量操作 +} power_optimization_t; + +/** + * @brief 功耗管理事件回调 + */ +typedef void (*power_event_callback_t)(power_mode_t old_mode, power_mode_t new_mode, void* user_data); + +/** + * @brief 功耗管理事件 + */ +typedef enum { + POWER_EVENT_MODE_CHANGE, // 功耗模式改变 + POWER_EVENT_SLEEP_START, // 睡眠开始 + POWER_EVENT_SLEEP_END, // 睡眠结束 + POWER_EVENT_WAKEUP, // 系统唤醒 + POWER_EVENT_OPTIMIZATION_TRIGGER, // 功耗优化触发 +} power_event_t; + +#endif // POWER_MANAGEMENT_CONFIG_H \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_16/board_sweekar.cc b/main/02_physical/boards/board_v1_1_16/board_sweekar.cc new file mode 100644 index 0000000..6229388 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_16/board_sweekar.cc @@ -0,0 +1,738 @@ +/** + * @file board.cc + * @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +extern "C" { +#include "esp_log.h" +#include "driver/gpio.h" +#include "driver/uart.h" +#include "driver/ledc.h" +#include "driver/gptimer.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "hal/gpio_types.h" +#include "hal/uart_types.h" +#include "esp_check.h" +#include "sdkconfig.h" +#include "i2c_bus.h" +#include "esp_peripherals.h" +#include "periph_sdcard.h" +#include "esp_sleep.h" +#include "driver/rtc_io.h" +} + +#include "board_sweekar.h" +#include "config.h" +#include "board.h" // 添加board.h以获取audio_board_sdcard_init函数声明 +#include "drv8428.h" +#include "aw8646.h" + +#define TAG "board_sweekar" + +BoardSweekar::BoardSweekar() +{ +#ifdef CONFIG_STEPPER_DRIVER_AW8646 + stepper_driver_ = new Aw8646Driver(io_expansion_); +#else + stepper_driver_ = new Drv8428Driver(io_expansion_); +#endif + + // Initialize Shutdown Control Pin (GPIO_NUM_13) and pull it HIGH + // This is required to keep the main power on. +#ifdef SHUTDOWN_CTRL_PIN + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = (1ULL << SHUTDOWN_CTRL_PIN); + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + gpio_config(&io_conf); + gpio_set_level(SHUTDOWN_CTRL_PIN, 1); + ESP_LOGI(TAG, "Initialized SHUTDOWN_CTRL_PIN (%d) to HIGH", SHUTDOWN_CTRL_PIN); +#endif +} + +BoardSweekar::~BoardSweekar() +{ + if (stepper_driver_) { + delete stepper_driver_; + stepper_driver_ = nullptr; + } +} + +/*========================== 步进电机相关驱动 ==========================*/ + +/** + * @brief 步进电机初始化函数 + * 配置步进电机所需的GPIO引脚模式,通过IO扩展板设置步进驱动芯片的工作模式 + * 在 stepper_motor.cc 中完成 GPTimer + GPIO 翻转 STEP 脉冲的初始化 + */ +void BoardSweekar::StepperMotorInit(void) +{ + esp_err_t err = ESP_OK; + + // 1) STEP 引脚改为普通 GPIO(不再用 LEDC) + gpio_config_t io_cfg; + io_cfg.pin_bit_mask = 1ULL << STEPPER_STEP_IO; + io_cfg.mode = GPIO_MODE_OUTPUT; + io_cfg.pull_up_en = GPIO_PULLUP_DISABLE; + io_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_cfg.intr_type = GPIO_INTR_DISABLE; + err = gpio_config(&io_cfg); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "步进电机 STEP GPIO 配置失败, 错误码: 0x%x", err); + } + + // 初始电平拉低,保证上电不乱跳 + gpio_set_level(STEPPER_STEP_IO, 0); + + // 2) 检查 I2C 总线是否已初始化 + if (bus_handle_ == nullptr) + { + ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()"); + return; + } + + // 3) 初始化驱动对象并初始化 + if (stepper_driver_) { + err = stepper_driver_->Init(); + if (err != ESP_OK) { + ESP_LOGE(TAG_BOARD, "步进电机驱动初始化失败, 错误码: 0x%x", err); + } + } else { + ESP_LOGE(TAG_BOARD, "步进电机驱动创建失败"); + } +} + +/** + * @brief LCD IO引脚初始化函数(消除与步进电机的耦合) + * + * 配置LCD所需的IO扩展板寄存器,确保LCD复位引脚正常工作 + * 此函数独立于步进电机初始化,专门处理LCD相关的IO配置 + */ +void BoardSweekar::LcdIoInit(void) +{ + esp_err_t err = ESP_OK; + + // 1) 检查I2C总线是否已初始化 + if (bus_handle_ == nullptr) + { + ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()"); + return; + } + + // 2) 执行硬件复位,确保IO扩展板处于已知状态 + err = io_expansion_.ResetIoExpand(); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "IO扩展板硬件复位失败, 错误码: 0x%x", err); + return; + } + else + { + ESP_LOGI(TAG_BOARD, "IO扩展板硬件复位成功"); + } + + // 3) 配置IO扩展板模式(端口方向等) + err = io_expansion_.IoexpandSetMode(); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "IO扩展板模式配置失败, 错误码: 0x%x", err); + return; + } + else + { + ESP_LOGI(TAG_BOARD, "IO扩展板模式配置成功"); + } + + // 4) 初始化LCD复位引脚:设置为高电平 + err = io_expansion_.SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "LCD复位引脚高电平设置失败, 错误码: 0x%x", err); + return; + } + else + { + ESP_LOGI(TAG_BOARD, "LCD复位引脚高电平设置成功"); + } +} + +/*========================== 毫米波雷达相关驱动 ==========================*/ + +/** + * @brief 毫米波雷达串口初始化函数 + * + * 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚, + * 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免 + * 与自定义中断冲突。 + */ +void BoardSweekar::MillimeterWaveRadarUartInit(void) +{ + uart_config_t uart_config = { + .baud_rate = RADAR_BAUD_RATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + .flags = { + .allow_pd = 0, + .backup_before_sleep = 0, + }, + }; + + // 1. 设置串口参数 + ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config)); + + // 2. 设置 UART 引脚 + ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突) + // 增加 RX/TX FIFO 深度以处理突发数据 + ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4, + 0, NULL, 0)); +} + +/** + * @brief 执行系统关机(拉高 SHUTDOWN_CTRL_PIN 切断电源) + */ +void BoardSweekar::SystemShutdown(void) +{ +#ifdef SHUTDOWN_CTRL_PIN + ESP_LOGI(TAG, "Executing System Shutdown... Pulling SHUTDOWN_CTRL_PIN (%d) HIGH", SHUTDOWN_CTRL_PIN); + gpio_set_level(SHUTDOWN_CTRL_PIN, 1); + vTaskDelay(pdMS_TO_TICKS(1000)); +#else + ESP_LOGW(TAG, "SHUTDOWN_CTRL_PIN is not defined. Cannot execute hardware shutdown."); +#endif +} + +/** + * @brief 毫米波雷达中断引脚初始化函数 + * + * 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能 + * (如需使用中断需单独进行配置)。 + */ +void BoardSweekar::MillimeterWaveRadarGpioInit(void) +{ + // GPIO配置结构体 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚 + .mode = GPIO_MODE_INPUT, // 设置为输入模式 + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉 + .intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置) + }; + + // 配置GPIO + gpio_config(&io_conf); +} + +/*========================== I2C总线及挂载的从设备相关驱动 ==========================*/ + +/** + * @brief I2C总线及从机设备初始化函数 + * + * 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。 + * 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。 + * 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。 + * + * @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因 + */ +esp_err_t BoardSweekar::I2CMasterInit(void) +{ + static const char *I2C_INIT = "I2C_INIT"; + + // 初始化IO扩展板复位引脚 + gpio_config_t reset_io_conf = { + .pin_bit_mask = (1ULL << IO_EXPAND_RSTN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉 + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&reset_io_conf); + + // 执行复位时序:先拉低100ms,再拉高并等待100ms + gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms + gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + + ESP_LOGI(I2C_INIT, "IO扩展板复位完成"); + + // 创建统一的I2C总线(使用ESP-ADF的i2c_bus) + i2c_config_t i2c_cfg = { + .mode = I2C_MODE_MASTER, + .sda_io_num = I2C0_MASTER_SDA_IO, + .scl_io_num = I2C0_MASTER_SCL_IO, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master = { + .clk_speed = 100000, + }, + }; + + // 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线) + bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg); + if (bus_handle_ == NULL) { + ESP_LOGE(TAG, "Failed to create I2C bus"); + return ESP_FAIL; + } + + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + // ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信 + + // 验证线性马达设备是否存在 + esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR); + } + // 验证IO扩展板设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err); + // 不返回错误,继续初始化其他设备 + } else { + ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR); + } + // 验证陀螺仪设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR); + } + + // 为IO扩展板设置总线句柄和设备地址(使用7位地址) + io_expansion_.bus_handle_ = bus_handle_; + io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1; + + // 线性马达的初始化已移至 InitializeAllHardware 中统一调用 Init 方法 + // linear_motor_ 的参数传递将在那里完成,不再此处直接赋值,提高内聚性 + + ESP_LOGI(I2C_INIT, "I2C总线初始化完成"); + return ESP_OK; +} + +/*========================== VBAT to VBAT_5V相关驱动 ==========================*/ + +/** + * @brief 开启VBAT to VBAT_5V + * + * 创建开启升压的电源管理单元 + * + */ +void BoardSweekar::VbatToVbat5vInit(void) +{ + // 配置VBAT_5V引脚为输出模式 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << VBAT_5V_PIN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&io_conf); + // 使能VBAT_5V + gpio_set_level(VBAT_5V_PIN, 1); +} + +/*========================== 底座控制串口相关驱动 ==========================*/ + +/** + * @brief 底座控制命令串口初始化函数 + */ +// 根据配置选择通信方式的HAL头文件 +#ifdef CONFIG_BASE_BOARD_COMM_I2C +#include "base_board_hal_i2c.h" +#else +#include "base_board_hal_uart.h" +#endif + +void BoardSweekar::BaseBoardControlInit(void) +{ +#ifdef CONFIG_BASE_BOARD_COMM_I2C + // I2C Mode + if (bus_handle_ == nullptr) { + ESP_LOGE(TAG, "I2C bus not initialized before BaseBoardControlInit"); + return; + } + + // 创建 I2C HAL 实例 + BaseBoardHalI2c *hal = new BaseBoardHalI2c(bus_handle_); + base_board_control_.Init(hal); + ESP_LOGI(TAG, "BaseBoardControl I2C initialized"); +#else + // UART Mode + uart_config_t uart_config = { + .baud_rate = BASE_BOARD_CTL_UART_BAUDRATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + .flags = { + .allow_pd = 0, + .backup_before_sleep = 0, + }, + }; + + // 1. 设置串口参数 + ESP_ERROR_CHECK(uart_param_config(BASE_BOARD_CTL_UART_PORT, &uart_config)); + + // 2. 设置 UART 引脚 + ESP_ERROR_CHECK(uart_set_pin(BASE_BOARD_CTL_UART_PORT, BASE_BOARD_CTL_UART_TX_PIN, BASE_BOARD_CTL_UART_RX_PIN, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 3. 安装 UART 驱动 + ESP_ERROR_CHECK(uart_driver_install(BASE_BOARD_CTL_UART_PORT, + BASE_BOARD_CTL_UART_BUF_SIZE, + BASE_BOARD_CTL_UART_BUF_SIZE, + 0, NULL, 0)); + + BaseBoardHalUart *hal = new BaseBoardHalUart(BASE_BOARD_CTL_UART_PORT); + base_board_control_.Init(hal); + ESP_LOGI(TAG, "BaseBoardControl UART initialized"); +#endif +} + +/*========================== SD卡相关驱动 ==========================*/ + +/** + * @brief SD卡初始化函数 + * + * 初始化SD卡外设,使用1线模式进行通信。该函数负责初始化外设管理器 + * 并配置SD卡,为后续的文件系统操作做准备。 + * + * @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示失败原因 + */ +esp_err_t BoardSweekar::InitializeSdcard(void) +{ + static const char *SDCARD_TAG = "SDCARD_INIT"; + esp_err_t ret; + + ESP_LOGI(SDCARD_TAG, "Initializing SD card"); + + if (is_sdcard_initialized_) { + ESP_LOGW(SDCARD_TAG, "SD card already initialized"); + return ESP_OK; + } + + // 初始化外设管理 + esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG(); + periph_cfg.extern_stack = true; // 将任务栈分配到 PSRAM 以节省 Internal SRAM + periph_set_ = esp_periph_set_init(&periph_cfg); + if (!periph_set_) { + ESP_LOGE(SDCARD_TAG, "Failed to initialize peripheral set"); + return ESP_FAIL; + } + + // 初始化SD卡外设 + ret = audio_board_sdcard_init(periph_set_, SD_MODE_1_LINE); + if (ret != ESP_OK) { + ESP_LOGE(SDCARD_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret)); + return ret; + } + + is_sdcard_initialized_ = true; + ESP_LOGI(SDCARD_TAG, "SD card initialized successfully"); + return ESP_OK; +} + +/** + * @brief 统一的硬件初始化接口实现 + * + * 按照依赖关系顺序初始化所有硬件资源: + * 1. I2C总线(最基础,其他设备可能依赖) + * 2. IO扩展板(可能影响其他设备) + * 3. SD卡(文件系统,供显示和音频使用) + * 4. 其他外设 + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ +esp_err_t BoardSweekar::InitializeAllHardware(void) +{ + static const char *HW_INIT_TAG = "HW_INIT"; + esp_err_t ret; + + ESP_LOGI(HW_INIT_TAG, "Starting unified hardware initialization..."); + + // 1. 初始化I2C总线(最基础) + ret = I2CMasterInit(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret)); + return ret; + } + ESP_LOGI(HW_INIT_TAG, "I2C master initialized"); + + // 2. 创建I2C读任务(IO扩展板需要) + io_expansion_.CreateI2cReadTask(); + ESP_LOGI(HW_INIT_TAG, "I2C read task created"); + + // 3. 初始化SD卡(文件系统,供显示和音频使用) + ret = InitializeSdcard(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret)); + // SD卡失败不是致命错误,继续初始化其他硬件 + ESP_LOGW(HW_INIT_TAG, "SD card initialization failed, but continuing with other hardware"); + } else { + ESP_LOGI(HW_INIT_TAG, "SD card initialized"); + } + + // 4. 初始化LCD IO引脚 + LcdIoInit(); + ESP_LOGI(HW_INIT_TAG, "LCD IO pins initialized"); + + // 5. 初始化其他必要外设 + // BaseBoardControlUartInit(); // 底座控制串口(demo5需要) + // ESP_LOGI(HW_INIT_TAG, "Base board control UART initialized"); + + // 初始化底座控制 + // base_board_control_.Init(); + // ESP_LOGI(HW_INIT_TAG, "Base board control initialized"); + + // 可选外设(根据具体应用需求) + // MillimeterWaveRadarUartInit(); + // MillimeterWaveRadarGpioInit(); + StepperMotorInit(); + + + + ESP_LOGI(HW_INIT_TAG, "Unified hardware initialization completed successfully"); + return ESP_OK; +} + +/** + * @brief 进入低功耗模式 + * + * 根据指定的功耗模式,执行相应的功耗优化策略: + * - IDLE模式:关闭非必要外设,保持快速响应 + * - LIGHT_SLEEP模式:进入轻度睡眠,CPU暂停,外设断电 + * - DEEP_SLEEP模式:深度睡眠,仅RTC运行,功耗最低 + */ +esp_err_t BoardSweekar::EnterLowPowerMode(power_mode_t mode) { + static const char *POWER_TAG = "POWER_MGMT"; + esp_err_t ret = ESP_OK; + + ESP_LOGI(POWER_TAG, "Entering power mode: %d", mode); + + if (mode == current_power_mode_) { + ESP_LOGW(POWER_TAG, "Already in power mode %d", mode); + return ESP_OK; + } + + // 保存当前模式,以便恢复 + power_mode_t previous_mode = current_power_mode_; + + switch (mode) { + case POWER_MODE_NORMAL: + // 正常模式,不需要特殊处理 + break; + + case POWER_MODE_IDLE: + // 空闲模式:关闭非必要外设 + ESP_LOGI(POWER_TAG, "Idle mode: disabling non-essential peripherals"); + + // 关闭SD卡(如果正在使用,需要先卸载) + if (is_sdcard_initialized_) { + // 注意:这里只是示例,实际应用中需要确保没有文件操作 + ESP_LOGW(POWER_TAG, "SD card still active in idle mode"); + } + + // 关闭显示背光 + // 关闭非必要GPIO的上拉/下拉 + // 降低I2C时钟频率 + break; + + case POWER_MODE_LIGHT_SLEEP: + // 轻度睡眠 + ESP_LOGI(POWER_TAG, "Light sleep mode: preparing for sleep"); + + // 设置唤醒源(需要根据具体需求配置) + // esp_sleep_enable_timer_wakeup(1000000); // 1秒后唤醒 + // esp_sleep_enable_ext0_wakeup(GPIO_NUM_XX, 0); // 外部中断唤醒 + + // 进入轻度睡眠 + // ret = esp_light_sleep_start(); + if (ret != ESP_OK) { + ESP_LOGE(POWER_TAG, "Failed to enter light sleep: %s", esp_err_to_name(ret)); + current_power_mode_ = previous_mode; + return ret; + } + break; + + case POWER_MODE_DEEP_SLEEP: + // 深度睡眠 + ESP_LOGI(POWER_TAG, "Deep sleep mode: system will restart after wake-up"); + + // 保存必要的RTC数据 + // rtc_gpio_isolate(GPIO_NUM_XX); // 隔离GPIO + + // 设置深度睡眠唤醒源 + // esp_sleep_enable_timer_wakeup(60000000); // 60秒后唤醒 + + // 进入深度睡眠 + // esp_deep_sleep_start(); + // 注意:深度睡眠后系统会重启,不会返回 + break; + + default: + ESP_LOGE(POWER_TAG, "Invalid power mode: %d", mode); + return ESP_ERR_INVALID_ARG; + } + + current_power_mode_ = mode; + ESP_LOGI(POWER_TAG, "Successfully entered power mode: %d", mode); + return ret; +} + +/** + * @brief 退出低功耗模式 + * + * 从低功耗模式恢复到正常运行模式,重新初始化必要的硬件资源。 + */ +esp_err_t BoardSweekar::ExitLowPowerMode(void) { + static const char *POWER_TAG = "POWER_MGMT"; + + ESP_LOGI(POWER_TAG, "Exiting low power mode"); + + if (current_power_mode_ == POWER_MODE_NORMAL) { + ESP_LOGW(POWER_TAG, "Already in normal mode"); + return ESP_OK; + } + + // 根据之前的功耗模式执行相应的恢复操作 + switch (current_power_mode_) { + case POWER_MODE_IDLE: + // 恢复空闲模式 + ESP_LOGI(POWER_TAG, "Restoring from idle mode"); + + // 重新初始化必要的外设 + // 恢复I2C时钟频率 + // 重新开启显示背光 + break; + + case POWER_MODE_LIGHT_SLEEP: + // 轻度睡眠唤醒后会自动继续执行 + ESP_LOGI(POWER_TAG, "Woken up from light sleep"); + + // 重新配置时钟(如果需要) + // 重新初始化外设 + break; + + case POWER_MODE_DEEP_SLEEP: + // 深度睡眠后系统会重启,不会执行到这里 + ESP_LOGW(POWER_TAG, "Deep sleep recovery should not reach here"); + break; + + default: + break; + } + + // 恢复到正常模式 + current_power_mode_ = POWER_MODE_NORMAL; + ESP_LOGI(POWER_TAG, "Successfully exited low power mode"); + + return ESP_OK; +} + +/** + * @brief 设置硬件模块电源状态 + * + * 提供精细化的电源管理,可以单独控制各个硬件模块的电源状态。 + */ +esp_err_t BoardSweekar::SetModulePower(hardware_module_t module, bool enable) { + static const char *POWER_TAG = "POWER_MODULE"; + esp_err_t ret = ESP_OK; + + ESP_LOGI(POWER_TAG, "%s module %d", enable ? "Enabling" : "Disabling", module); + + // 更新电源状态位图 + if (enable) { + power_state_flags_ |= (1 << module); + } else { + power_state_flags_ &= ~(1 << module); + } + + switch (module) { + case HW_MODULE_I2C: + if (!enable && bus_handle_) { + // 注意:I2C总线通常不建议完全关闭,可能影响多个设备 + ESP_LOGW(POWER_TAG, "I2C bus power control not recommended"); + } + break; + + case HW_MODULE_SDCARD: + if (enable && !is_sdcard_initialized_) { + ret = InitializeSdcard(); + } else if (!enable && is_sdcard_initialized_) { + // 卸载SD卡文件系统 + // 注意:需要确保没有打开的文件 + ESP_LOGW(POWER_TAG, "SD card power down requires file system cleanup"); + } + break; + + case HW_MODULE_LCD: + // LCD背光控制 + // LCD电源引脚控制(如果有) + break; + + case HW_MODULE_AUDIO: + // 音频编解码器电源控制 + // 需要与AudioPlayer协调 + break; + + case HW_MODULE_MOTOR: + // 步进电机驱动器电源控制 + // 电机睡眠模式 + break; + + case HW_MODULE_GYROSCOPE: + // 陀螺仪电源控制 + // 设置陀螺仪为低功耗模式 + break; + + case HW_MODULE_TOUCH: + // 触摸传感器电源控制 + // 设置触摸传感器为睡眠模式 + break; + + case HW_MODULE_RADAR: + // 毫米波雷达电源控制 + // 设置雷达为低功耗模式 + break; + + case HW_MODULE_IO_EXPAND: + // IO扩展板电源控制 + // 设置扩展板为低功耗模式 + break; + + default: + ESP_LOGE(POWER_TAG, "Unknown hardware module: %d", module); + return ESP_ERR_INVALID_ARG; + } + + if (ret == ESP_OK) { + ESP_LOGI(POWER_TAG, "Module %d power %s successfully", module, enable ? "enabled" : "disabled"); + } else { + ESP_LOGE(POWER_TAG, "Failed to %s module %d: %s", enable ? "enable" : "disable", module, esp_err_to_name(ret)); + } + + return ret; +} + + + diff --git a/main/02_physical/boards/board_v1_1_16/board_sweekar.h b/main/02_physical/boards/board_v1_1_16/board_sweekar.h new file mode 100644 index 0000000..dc8463f --- /dev/null +++ b/main/02_physical/boards/board_v1_1_16/board_sweekar.h @@ -0,0 +1,174 @@ +#ifndef __BOARD_H__ +#define __BOARD_H__ +#include "config.h" +#include "io_expansion_board.h" +// #include "stepper_motor.h" // ! +#include "stepper_driver.h" +#include "i2c_bus.h" +#include "gyroscope.h" +// #include "touch_sensor.h" // ! +#include "base_board_control.h" +#include "esp_peripherals.h" +#include "periph_sdcard.h" +#include "esp_sleep.h" +#include "driver/rtc_io.h" + +/** + * @brief 功耗模式枚举 + */ +typedef enum { + POWER_MODE_NORMAL, // 正常运行模式,所有硬件可用 + POWER_MODE_IDLE, // 空闲模式,关闭非必要外设 + POWER_MODE_LIGHT_SLEEP, // 轻度睡眠,快速唤醒 + POWER_MODE_DEEP_SLEEP, // 深度睡眠,仅RTC运行 +} power_mode_t; + +/** + * @brief 硬件模块枚举,用于精细化电源管理 + */ +typedef enum { + HW_MODULE_I2C, // I2C总线 + HW_MODULE_SDCARD, // SD卡 + HW_MODULE_LCD, // LCD显示 + HW_MODULE_AUDIO, // 音频编解码器 + HW_MODULE_MOTOR, // 步进电机 + HW_MODULE_GYROSCOPE, // 陀螺仪 + HW_MODULE_TOUCH, // 触摸传感器 + HW_MODULE_RADAR, // 毫米波雷达 + HW_MODULE_IO_EXPAND, // IO扩展板 +} hardware_module_t; + +/** + * @brief 硬件板级管理器 + * + * 采用高内聚低耦合设计原则,统一管理所有硬件资源。 + * 提供统一的硬件初始化接口和资源访问,避免各模块重复初始化。 + */ +class BoardSweekar +{ +private: + i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄 + esp_periph_set_handle_t periph_set_ = nullptr; // 外设管理句柄 + bool is_sdcard_initialized_ = false; // SD卡初始化状态 + power_mode_t current_power_mode_ = POWER_MODE_NORMAL; // 当前功耗模式 + uint32_t power_state_flags_ = 0xFFFFFFFF; // 各模块电源状态位图(1为开启) + +public: + BoardSweekar(); + ~BoardSweekar(); + + IOExpansionBoard io_expansion_; // IO扩展板对象 + Gyroscope gyroscope_; // 陀螺仪对象 + // TouchSensor touch_sensor_; // 触摸传感器对象 //! + BaseBoardControl base_board_control_; // 底座控制对象 + StepperDriver* stepper_driver_ = nullptr; // 步进电机驱动对象 + + StepperDriver* GetStepperDriver() const { return stepper_driver_; } + + // 初始化步进电机 + void StepperMotorInit(void); + + // 初始化LCD IO引脚(消除与步进电机的耦合) + void LcdIoInit(void); + + // 初始化串口 + void MillimeterWaveRadarUartInit(void); + + //初始化毫米波雷达的中断引脚 + void MillimeterWaveRadarGpioInit(void); + + // 初始化I2C总线 + esp_err_t I2CMasterInit(void); + + // 初始化VBAT toVBAT_5V引脚 + void VbatToVbat5vInit(void); + + // 初始化底座控制串口 + void BaseBoardControlInit(void); + + // 初始化SD卡(推荐使用统一的硬件初始化) + esp_err_t InitializeSdcard(void); + + // 获取SD卡初始化状态 + bool IsSdcardInitialized() const { return is_sdcard_initialized_; } + + // 获取外设管理句柄(供需要访问SD卡的模块使用) + esp_periph_set_handle_t GetPeriphSet() const { return periph_set_; } + + // 获取I2C总线句柄 + i2c_bus_handle_t GetBusHandle() const { return bus_handle_; } + + /** + * @brief 统一的硬件初始化接口 + * + * 按照依赖关系顺序初始化所有硬件资源,确保各模块可以安全使用。 + * 推荐在主程序启动时调用此函数,而不是分别调用各个初始化函数。 + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ + esp_err_t InitializeAllHardware(void); + + /** + * @brief 完整的统一硬件初始化接口(专为复杂应用优化) + * + * 包含所有必要外设的完整初始化,适用于demo5等复杂应用场景。 + * 这个函数会初始化:I2C总线、IO扩展板、SD卡、LCD IO、底座控制等。 + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ + esp_err_t InitializeAllHardwareComplete(void); + + /** + * @brief 针对特定应用的硬件初始化配置 + * + * 为不同类型的应用提供专门的初始化配置,优化启动流程。 + * + * @param app_type 应用类型(demo5、音频播放器、显示应用等) + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ + esp_err_t InitializeHardwareForApplication(int app_type); + + /** + * @brief 功耗管理接口 - 进入低功耗模式 + * + * 根据指定的功耗模式,关闭非必要硬件、设置GPIO为低功耗状态、 + * 调整时钟频率等。支持多种功耗模式以适应不同应用场景。 + * + * @param mode 功耗模式 + * @return esp_err_t 操作结果 + */ + esp_err_t EnterLowPowerMode(power_mode_t mode); + + /** + * @brief 功耗管理接口 - 退出低功耗模式 + * + * 从低功耗模式恢复,重新初始化必要的硬件资源。 + * + * @return esp_err_t 操作结果 + */ + esp_err_t ExitLowPowerMode(void); + + /** + * @brief 获取当前功耗模式 + * + * @return power_mode_t 当前功耗模式 + */ + power_mode_t GetPowerMode(void) const { return current_power_mode_; } + + /** + * @brief 设置硬件模块电源状态 + * + * 单独控制某个硬件模块的电源状态,用于精细化的功耗管理。 + * + * @param module 硬件模块 + * @param enable true为开启,false为关闭 + * @return esp_err_t 操作结果 + */ + esp_err_t SetModulePower(hardware_module_t module, bool enable); + + /** + * @brief 执行系统关机(拉高 SHUTDOWN_CTRL_PIN) + */ + void SystemShutdown(void); +}; +#endif diff --git a/main/02_physical/boards/board_v1_1_16/board_sweekar_complete_init.cc b/main/02_physical/boards/board_v1_1_16/board_sweekar_complete_init.cc new file mode 100644 index 0000000..37a454a --- /dev/null +++ b/main/02_physical/boards/board_v1_1_16/board_sweekar_complete_init.cc @@ -0,0 +1,186 @@ +/** + * @file board_sweekar_complete_init.cc + * @brief 完整的统一硬件初始化实现 + * + * 这个文件提供了完整的统一硬件初始化函数,包含所有必要的硬件初始化步骤。 + * 专为demo5等复杂应用场景设计。 + */ + +/** + * @brief 完整的统一硬件初始化接口(专为demo5优化) + * + * 按照依赖关系顺序初始化所有硬件资源: + * 1. I2C总线(最基础,其他设备依赖) + * 2. IO扩展板(控制其他外设) + * 3. SD卡(文件系统,供显示和音频使用) + * 4. LCD IO引脚(显示相关) + * 5. 底座控制串口(通信) + * 6. 底座控制模块(业务逻辑) + * 7. 其他外设(根据应用需求) + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ +esp_err_t BoardSweekar::InitializeAllHardwareComplete(void) +{ + static const char *HW_INIT_TAG = "HW_INIT_COMPLETE"; + esp_err_t ret; + + ESP_LOGI(HW_INIT_TAG, "Starting complete hardware initialization..."); + + // 1. 初始化I2C总线(最基础,其他设备依赖) + ret = I2CMasterInit(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret)); + return ret; + } + ESP_LOGI(HW_INIT_TAG, "✓ I2C master initialized"); + + // 2. 创建I2C读任务(IO扩展板需要) + io_expansion_.CreateI2cReadTask(); + ESP_LOGI(HW_INIT_TAG, "✓ I2C read task created"); + + // 3. 初始化SD卡(文件系统,供显示和音频使用) + ret = InitializeSdcard(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret)); + // SD卡失败不是致命错误,继续初始化其他硬件 + ESP_LOGW(HW_INIT_TAG, "⚠ SD card initialization failed, but continuing with other hardware"); + } else { + ESP_LOGI(HW_INIT_TAG, "✓ SD card initialized"); + } + + // 4. 初始化LCD IO引脚(显示相关) + LcdIoInit(); + ESP_LOGI(HW_INIT_TAG, "✓ LCD IO pins initialized"); + + // 5. 初始化底座控制串口(demo5需要) + BaseBoardControlUartInit(); + ESP_LOGI(HW_INIT_TAG, "✓ Base board control UART initialized"); + + // 6. 初始化底座控制模块 + base_board_control_.Init(); + ESP_LOGI(HW_INIT_TAG, "✓ Base board control initialized"); + + // 7. 设置IO扩展板的PA控制模式(demo5需要) + io_expansion_.SetPaCtrlMode(true); + ESP_LOGI(HW_INIT_TAG, "✓ IO expansion PA control mode set"); + + // 8. 可选外设(根据具体应用需求启用) + // ESP_LOGI(HW_INIT_TAG, "Initializing optional peripherals..."); + // + // // 毫米波雷达(如需要) + // MillimeterWaveRadarUartInit(); + // MillimeterWaveRadarGpioInit(); + // ESP_LOGI(HW_INIT_TAG, "✓ Millimeter wave radar initialized"); + // + // // VBAT升压(如需要) + // VbatToVbat5vInit(); + // ESP_LOGI(HW_INIT_TAG, "✓ VBAT to 5V booster initialized"); + // + // // 步进电机(如需要) + // StepperMotorInit(); + // ESP_LOGI(HW_INIT_TAG, "✓ Stepper motor initialized"); + + ESP_LOGI(HW_INIT_TAG, "=== Complete hardware initialization finished successfully ==="); + return ESP_OK; +} + +/** + * @brief 针对特定应用的硬件初始化配置 + * + * 为不同类型的应用提供专门的初始化配置 + */ +esp_err_t BoardSweekar::InitializeHardwareForApplication(application_type_t app_type) { + static const char *APP_INIT_TAG = "APP_HW_INIT"; + + ESP_LOGI(APP_INIT_TAG, "Initializing hardware for application type: %d", app_type); + + // 基础硬件初始化(所有应用都需要) + esp_err_t ret = InitializeAllHardwareComplete(); + if (ret != ESP_OK) { + ESP_LOGE(APP_INIT_TAG, "Basic hardware initialization failed"); + return ret; + } + + switch (app_type) { + case APP_TYPE_DEMO5: // 宠物游戏demo + ESP_LOGI(APP_INIT_TAG, "Configuring for Demo5 (Pet Game)..."); + + // Demo5需要的额外初始化 + // 触摸传感器、陀螺仪、RGB LED等会在应用层初始化 + + ESP_LOGI(APP_INIT_TAG, "✓ Demo5 hardware configuration complete"); + break; + + case APP_TYPE_AUDIO_PLAYER: // 音频播放器 + ESP_LOGI(APP_INIT_TAG, "Configuring for Audio Player..."); + + // 音频应用需要确保音频编解码器正确初始化 + // 这部分通常在AudioPlayer类中处理 + + ESP_LOGI(APP_INIT_TAG, "✓ Audio player hardware configuration complete"); + break; + + case APP_TYPE_DISPLAY_ONLY: // 纯显示应用 + ESP_LOGI(APP_INIT_TAG, "Configuring for Display Only..."); + + // 显示应用需要确保LCD相关硬件正确配置 + // 这部分通常在Display类中处理 + + ESP_LOGI(APP_INIT_TAG, "✓ Display-only hardware configuration complete"); + break; + + case APP_TYPE_MINIMAL: // 最小化应用 + ESP_LOGI(APP_INIT_TAG, "Configuring for Minimal Application..."); + + // 最小化配置,只保留最基本的功能 + // 关闭非必要外设以节省功耗 + + ESP_LOGI(APP_INIT_TAG, "✓ Minimal hardware configuration complete"); + break; + + default: + ESP_LOGW(APP_INIT_TAG, "Unknown application type, using default configuration"); + break; + } + + return ESP_OK; +} + +/** + * @brief 硬件初始化状态报告 + * + * 提供详细的硬件初始化状态报告,便于调试和问题排查 + */ +void BoardSweekar::ReportHardwareStatus(void) { + static const char *STATUS_TAG = "HW_STATUS"; + + ESP_LOGI(STATUS_TAG, "=== Hardware Initialization Status Report ==="); + + // I2C总线状态 + ESP_LOGI(STATUS_TAG, "I2C Bus: %s", (bus_handle_ != nullptr) ? "✓ Initialized" : "✗ Not initialized"); + + // SD卡状态 + ESP_LOGI(STATUS_TAG, "SD Card: %s", (is_sdcard_initialized_) ? "✓ Initialized" : "✗ Not initialized"); + if (is_sdcard_initialized_) { + ESP_LOGI(STATUS_TAG, " Peripheral Set: %s", (periph_set_ != nullptr) ? "✓ Available" : "✗ Not available"); + } + + // IO扩展板状态 + ESP_LOGI(STATUS_TAG, "IO Expansion Board: %s", (io_expansion_.bus_handle_ != nullptr) ? "✓ Configured" : "✗ Not configured"); + + // 底座控制状态 + ESP_LOGI(STATUS_TAG, "Base Board Control: %s", (base_board_control_.GetUartPort() != 0) ? "✓ Initialized" : "✗ Not initialized"); + + // 功耗管理状态 + ESP_LOGI(STATUS_TAG, "Power Management: %s", (current_power_mode_ == POWER_MODE_NORMAL) ? "✓ Normal mode" : "⚠ Low power mode"); + ESP_LOGI(STATUS_TAG, " Current Mode: %d", current_power_mode_); + ESP_LOGI(STATUS_TAG, " Module Power States: 0x%08X", power_state_flags_); + + // 内存状态 + ESP_LOGI(STATUS_TAG, "Memory Status:"); + ESP_LOGI(STATUS_TAG, " Internal RAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + ESP_LOGI(STATUS_TAG, " PSRAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + + ESP_LOGI(STATUS_TAG, "=== End of Hardware Status Report ==="); +} \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_16/config.h b/main/02_physical/boards/board_v1_1_16/config.h new file mode 100644 index 0000000..e5a3387 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_16/config.h @@ -0,0 +1,138 @@ +/* 定义引脚分配 */ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +/** + * @file config.h + * @brief 定义了引脚的分配。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +#include "driver/gpio.h" +#include "driver/i2c_master.h" +#include "driver/i2s.h" +#include "esp_log.h" +#include "esp_rom_sys.h" // 用于 esp_rom_delay_us +#include "esp_timer.h" +#include "esp_mac.h" +#include "driver/ledc.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "driver/timer.h" +#include "esp_intr_alloc.h" +#include "soc/timer_group_struct.h" // 包含TIMERG0、TIMERG1的结构体定义 +#include "soc/timer_group_reg.h" // 包含定时器相关寄存器宏定义 +#include "driver/uart.h" +#include "esp_err.h" +#include "freertos/queue.h" +#include "soc/uart_reg.h" +// #include "linear_motor.h" +#include "gyroscope.h" + +#define TAG_BOARD "SWEEKAR_ESP32" +/*I2C总线引脚定义*/ +#define I2C0_MASTER_PORT I2C_NUM_0 +#define I2C0_MASTER_SDA_IO GPIO_NUM_2 +#define I2C0_MASTER_SCL_IO GPIO_NUM_3 + +/* 步进电机配置 */ +#define STEPPER_STEP_IO GPIO_NUM_42 // 步进电机脉冲输入引脚 +#define STEPPER_TIMER_RES_HZ 1000000 // 步进电机定时器分辨率 1 MHz(1 us 步进) + +/* 定义屏幕驱动控制引脚 */ +#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚 +#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL +#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚 +#define ST7789_PIN_CS GPIO_NUM_46 // SPI片选引脚 +#define ST7789_PIN_BL GPIO_NUM_45 // 背光引脚 +#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚 +#define LCD_BL_ACTIVE_LEVEL 1 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS) + +#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数) +#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数) + +/* 毫米波雷达配置参数 */ +/* 定义毫米波雷达的中断引脚 */ +#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35 +// UART 配置参数 +#define RADAR_UART_NUM UART_NUM_1 // 使用 UART1 +#define UART_TX_PIN GPIO_NUM_40 // GPIO40 作为 TX(根据实际硬件连接调整) +#define UART_RX_PIN GPIO_NUM_39 // GPIO39 作为 RX +#define RADAR_BAUD_RATE 9600 // 雷达波特率 +#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小 + +/* IO扩展硬件配置常量 */ +#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000) +#define I2C_IO_EXPAND_SLAVE_ADDR 0x58 // AW9523BTQR器件地址,v1_1_13的addr1和addr0是0 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚 +#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值 +#define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚 + +/* 定义线性马达的I2C从机配置常量 */ +#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址 + +/* 定义陀螺仪的I2C从机配置常量 */ +#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址 +#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚 + +/* AW触摸芯片配置 */ +#define AW_TOUCH_IRQ_PIN GPIO_NUM_11 // AW触摸芯片中断引脚 +#define NFC_RST_PIN GPIO_NUM_12 // NFC复位引脚 +#define SHUTDOWN_CTRL_PIN GPIO_NUM_13 // 关机控制引脚 + +/* 原生触摸引脚配置 (v1.1.16已改为上述功能,保留定义需谨慎) */ +// 触摸按键数量配置 +#define TOUCH_BUTTON_NUM 3 +// 触摸通道定义 - 注意:v1.1.16如果不使用ESP32原生触摸,这些定义可能不再适用 +// 但为了兼容编译,可以保留或注释 +#define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11 (Now AW_IRQ) +#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12 (Now NFC_RST) +#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13 (Now SHUTDOWN) + +/* ES8311音频编解码器配置 (ESP-ADF兼容) */ +#define AUDIO_INPUT_SAMPLE_RATE 24000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 +#define AUDIO_INPUT_REFERENCE true + +/* I2S GPIO定义 */ +#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15 +#define AUDIO_I2S_GPIO_WS GPIO_NUM_4 +#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5 +#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6 +#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7 + +/* PA引脚定义 */ +#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC + +/* I2C配置 */ +#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2 +#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3 +#define AUDIO_CODEC_ES8311_ADDR 0x18 +#define AUDIO_CODEC_ES7210_ADDR 0x40 + +/* WS2812 RGB LED配置 */ +#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚 +#define WS2812_NUM_LEDS 2 // WS2812 LED数量 + +/* 创建VBAT to VBAT_5V */ +#define VBAT_5V_PIN GPIO_NUM_NC // VBAT_5V引脚 + +/* 定义按键的中断引脚 */ +#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚 +#define RIGHT_BUTTON_PIN GPIO_NUM_8 // 按键中断引脚 + +/* 底座控制命令串口配置 */ +#define BASE_BOARD_CTL_UART_PORT UART_NUM_0 +#define BASE_BOARD_CTL_UART_TX_PIN GPIO_NUM_43 +#define BASE_BOARD_CTL_UART_RX_PIN GPIO_NUM_44 +#define BASE_BOARD_CTL_UART_BAUDRATE 115200 +#define BASE_BOARD_CTL_UART_BUF_SIZE 256 + +/* 背光控制引脚配置 */ +#define BL_PIN GPIO_NUM_45 + +#endif // _BOARD_CONFIG_H_ diff --git a/main/02_physical/boards/board_v1_1_16/io_expansion_board.cc b/main/02_physical/boards/board_v1_1_16/io_expansion_board.cc new file mode 100644 index 0000000..9e976d2 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_16/io_expansion_board.cc @@ -0,0 +1,1034 @@ +#include "io_expansion_board.h" +#include "millimeter_wave_radar.h" +#include "photo_interrupter.h" +#include "adc_battery_monitor.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_check.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/idf_additions.h" +#include "freertos/portable.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_rom_sys.h" +/** + * @file io_expansion_board.cc + * @brief IO扩展板功能实现类,包含I2C通信、GPIO中断配置、外设控制等功能 + * @details 实现了IO扩展板的初始化(中断引脚、复位引脚)、寄存器读写、步进电机控制(细分模式、使能、方向、睡眠状态)、 + * LCD相关引脚控制(背光、复位、片选)、毫米波雷达中断引脚配置等功能,并提供I2C数据读取任务的创建与管理 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +/** + * @brief 构造函数 + */ +IOExpansionBoard::IOExpansionBoard() + : bus_handle_(nullptr), + device_addr_(0), + last_port0_state_(0), + last_port1_state_(0), + radar_last_state_(false), + i2c_task_event_group_(nullptr), + xI2CReadTaskHandle_(nullptr), + is_initialized_(false), + interrupt_gpio_(GPIO_NUM_NC), + reset_gpio_(GPIO_NUM_NC) +{ +} + +/** + * @brief 析构函数 + */ +IOExpansionBoard::~IOExpansionBoard() +{ + // 删除任务 + if (xI2CReadTaskHandle_) { + vTaskDelete(xI2CReadTaskHandle_); + } + + // if(pI2CReadTaskStackBuffer) { + // heap_caps_free(pI2CReadTaskStackBuffer); + // pI2CReadTaskStackBuffer = nullptr; + // } + + // if(pxI2CReadTaskBuffer) { + // vPortFree(pxI2CReadTaskBuffer); + // pxI2CReadTaskBuffer = nullptr; + // } + + // 删除事件组 + if (i2c_task_event_group_) { + vEventGroupDelete(i2c_task_event_group_); + } + + // 移除中断处理 + if (interrupt_gpio_ != GPIO_NUM_NC) { + gpio_isr_handler_remove(interrupt_gpio_); + } + + // 删除IO扩展板设备 + // 使用i2c_bus API时不需要手动删除设备句柄 + // bus_handle_由board_sweekar统一管理 +} + +/** + * @brief 静态中断处理函数 + */ +void IRAM_ATTR IOExpansionBoard::GpioIsrHandler(void* arg) +{ + IOExpansionBoard* instance = static_cast(arg); + if (!instance) return; + + // 调试:记录中断触发 + // ESP_EARLY_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "中断触发!"); // IRAM函数中不能使用普通日志 + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // 设置事件标志位 + if (instance->i2c_task_event_group_) { + xEventGroupSetBitsFromISR( + instance->i2c_task_event_group_, + BIT0, + &xHigherPriorityTaskWoken + ); + } + + // 触发上下文切换 + if (xHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); + } +} + +/** + * @brief 初始化GPIO中断检测 + */ +esp_err_t IOExpansionBoard::InterruptGpioInit(gpio_num_t gpio_num) +{ + // 配置IO扩展板中断引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_ANYEDGE; // 改为双沿触发,检测上升沿和下降沿 + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + // io_conf.pull_up_en = GPIO_PULLUP_DISABLE; + // io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE; + + + esp_err_t err = gpio_config(&io_conf); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + // 配置中断服务 + err = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3); + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断服务安装失败,错误码: 0x%x", err); + return err; + } + // 注册中断处理函数 + err = gpio_isr_handler_add(gpio_num, GpioIsrHandler, this); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断处理函数添加失败,错误码: 0x%x", err); + return err; + } + // 创建事件组 + i2c_task_event_group_ = xEventGroupCreate(); + if (!i2c_task_event_group_) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "事件组创建失败"); + return ESP_FAIL; + } + + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d中断初始化完成", gpio_num); + return ESP_OK; +} + +/** + * @brief 初始化硬件复位引脚 + * 设置为上拉,需要复位,需要输出低电平为20us的脉冲信号 + */ +esp_err_t IOExpansionBoard::ResetGpioInit(gpio_num_t gpio_num) +{ + reset_gpio_ = gpio_num; + + // 配置复位引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + esp_err_t err = gpio_config(&io_conf); + gpio_set_level(gpio_num, 1); // 复位引脚拉高 + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d复位引脚初始化完成", gpio_num); + return err; + } +} + +/** + * @brief 计算Port0的字节值,用于配置输入还是输出模式(0为输出模式,1为输入模式) + * @return uint8_t 操作结果 + */ +uint8_t IOExpansionBoard::ByteCalculatePort0() +{ + uint8_t byte_val = 0x00; // 初始化为所有引脚为输出模式(0),然后根据配置设置为输入模式(1) + + // 输入模式配置:将对应位置位(1为输入模式) + if(RADAR_INTERRUPT_CONFIG == CONFIG_PORT0){ //雷达中断引脚 + byte_val |= (1 << RADAR_INTERRUPT_PIN); + } + if(START_PHOTO_INTERRUPTER_CONFIG == CONFIG_PORT0){ //起始光学传感器 + byte_val |= (1 << START_PHOTO_INTERRUPTER_PIN); + } + if(END_PHOTO_INTERRUPTER_PORT_CONFIG == CONFIG_PORT0){ //结束光学传感器 + byte_val |= (1 << END_PHOTO_INTERRUPTER_PIN); + } + if(BATTERY_FULL_CONFIG == CONFIG_PORT0){ //电池充满检测 + byte_val |= (1 << BATTERY_FULL_PIN); + } + if(BATTERY_CHRG_CONFIG == CONFIG_PORT0){ //电池充电检测 + byte_val |= (1 << BATTERY_CHRG_PIN); + } + + return byte_val; +} + +/** + * @brief 计算Port1的字节值,用于配置输入还是输出模式(0为输出模式,1为输入模式) + * @return uint8_t 操作结果 + */ +uint8_t IOExpansionBoard::ByteCalculatePort1() +{ + uint8_t byte_val = 0x00; // 初始化为所有引脚为输出模式(0),然后根据配置设置为输入模式(1) + + // 输入模式配置:将对应位置位(1为输入模式) + if(RADAR_INTERRUPT_CONFIG == CONFIG_PORT1){ //雷达中断引脚 + byte_val |= (1 << RADAR_INTERRUPT_PIN); + } + if(START_PHOTO_INTERRUPTER_CONFIG == CONFIG_PORT1){ //起始光学传感器 + byte_val |= (1 << START_PHOTO_INTERRUPTER_PIN); + } + if(END_PHOTO_INTERRUPTER_PORT_CONFIG == CONFIG_PORT1){ //结束光学传感器 + byte_val |= (1 << END_PHOTO_INTERRUPTER_PIN); + } + if(BATTERY_FULL_CONFIG == CONFIG_PORT1){ //电池充满检测 + byte_val |= (1 << BATTERY_FULL_PIN); + } + if(BATTERY_CHRG_CONFIG == CONFIG_PORT1){ //电池充电检测 + byte_val |= (1 << BATTERY_CHRG_PIN); + } + + return byte_val; +} + +/** + * @brief 复位IO扩展板 + */ +esp_err_t IOExpansionBoard::ResetIoExpand() +{ + if (reset_gpio_ == GPIO_NUM_NC) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位引脚未初始化"); + return ESP_ERR_INVALID_STATE; + } + + // 复位IO扩展板 + gpio_set_level(reset_gpio_, 0); + esp_rom_delay_us(30); + gpio_set_level(reset_gpio_, 1); + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "复位成功"); + } + return ESP_OK; +} + +/** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::IoexpandWriteReg(uint8_t reg_addr, uint8_t data) +{ + return i2c_bus_write_bytes(bus_handle_, device_addr_, ®_addr, 1, &data, 1); +} + +/** + * @brief 从寄存器读取数据 + * @param reg_addr 寄存器地址(如INPUT_PORT0、ID等) + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果(ESP_OK为成功) + */ +esp_err_t IOExpansionBoard::IoexpandReadReg(uint8_t reg_addr, uint8_t* data) +{ + if (data == nullptr){ // 检查输入参数有效性 + return ESP_ERR_INVALID_ARG; + } + + // 使用i2c_bus_read_bytes进行寄存器读取 + esp_err_t err = i2c_bus_read_bytes(bus_handle_, device_addr_, ®_addr, 1, data, 1); + if (err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "读取寄存器失败,错误码:0x%x", err); + return err; + } + + return ESP_OK; +} + +/** + * @brief 读取输入端口0寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::ReadInputPort0(uint8_t* data) +{ + return IoexpandReadReg(INPUT_PORT0, data); +} + +/** + * @brief 读取输入端口1寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::ReadInputPort1(uint8_t* data) +{ + return IoexpandReadReg(INPUT_PORT1, data); +} + +//设置IO扩展板为输入模式或是输出模式 +/* +* 这里需要根据实际情况设置IO扩展板的模式,比如输入模式还是输出模式,以及各个引脚的配置。 +* P0_0 对应NFC_RST引脚,需要设置为输出模式,低电平有效。(待测) +* P0_1 对应USB_VBUS引脚,需要设置为输出模式,低电平有效。(待测) +* P0_2 对应BTN_RIGHT_EAR引脚,需要设置为输出模式,低电平有效。(待测) +* P0_3 暂时未使用。 +* P0_4 对应步进电机方向引脚,需要设置为输出模式,根据需求设置。(待测) +* P0_5 对应CHRG引脚(待测) +* P0_6 LCD_DC引脚,需要设置为输出模式,根据需求设置电平。(待测) +* P0_7 对应步进电机的使能引脚,需要设置为输出模式,根据需求设置。(待测) +* +* +* P1_0 对应EG800K_PWR。(待测) +* P1_1 对应LCD_RST,需要设置为输出模式,低电平有效。(待测) +* P1_2 对应LCD_CS,需要设置为输出模式,低电平有效。(待测) +* P1_3 暂时未使用。 +* P1_4 对应步进电机的细分模式M1引脚。(待测) +* P1_5 对应步进电机的细分模式M0引脚。(待测) +* P1_6 对应步进电机的睡眠引脚。(待测) +* P1_7 对应RADAR_O雷达的输出引脚。(待测) +* */ +esp_err_t IOExpansionBoard::IoexpandSetMode(void) +{ + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功"); + } + + err = IoexpandWriteReg(CONFIG_PORT0, ByteCalculatePort0()); + + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + // 打印BytecalculatePort0()结果 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功, 0x%02X", ByteCalculatePort0()); + } + + err = IoexpandWriteReg(CONFIG_PORT1, ByteCalculatePort1()); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口失败,错误码:0x%x", err); + return err; + } + else{ + // 打印BytecalculatePort1()结果 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口成功, 0x%02X", ByteCalculatePort1()); + } + // 配置P0_0-P0_7的初始为高电平 + // 配置P1_0-P1_7的初始为高电平 + err = IoexpandWriteReg(OUTPUT_PORT0, 0x40); // 0100 0000 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值成功"); + } + err = IoexpandWriteReg(OUTPUT_PORT1, 0x04); // 0000 0100 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值成功"); + } + + + // AW9523B中断使能配置:0为使能中断,1为禁止中断 + // 使能P0_5(充电检测)和P1_3(充满检测)的中断 + uint8_t int_enable_port0 = 0x00; // 0x00 = 使能所有P0引脚中断 + uint8_t int_enable_port1 = 0x00; // 0x00 = 使能所有P1引脚中断 + + err = IoexpandWriteReg(INT_PORT0, int_enable_port0); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口中断使能失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口中断使能成功: 0x%02X (0=使能)", int_enable_port0); + } + + err = IoexpandWriteReg(INT_PORT1, int_enable_port1); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能成功: 0x%02X (0=使能)", int_enable_port1); + } + + return ESP_OK; +} + +/** + * @brief 设置步进电机的细分模式 + */ +void IOExpansionBoard::SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin) +{ + uint8_t current_val; + switch (mode) { + case 1: //全步输出模式 低低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 2: //非圆 1/2 高低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val |= (1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 3: //1/4 步 低高电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val |= (1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 4: //1/8 步 高高电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val |= (1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val |= (1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + default: //全步输入模式 低低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + } +} + +/** + * @brief 设置步进电机的使能 + */ +esp_err_t IOExpansionBoard::SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin) +{ + uint8_t current_val; + if(enable){ + // 进入工作状态mode + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << enable_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << enable_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} +/** + * @brief 设置步进电机运行方向 + */ +esp_err_t IOExpansionBoard::StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin) +{ + uint8_t current_val; + if(dir){ + // 方向为正转 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/** + * @brief 设置步进电机是否进入睡眠或者工作状态(高电平进入工作状态,低电平进入睡眠状态) + */ +esp_err_t IOExpansionBoard::SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin) +{ + uint8_t current_val; + if(mode){ + // 进入工作状态mode + // ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入工作状态"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "电机睡眠输出寄存器: 0x%x", current_val); + current_val |= (1 << nsleep_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置电机睡眠输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + // ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入睡眠状态"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "电机睡眠输出寄存器: 0x%x", current_val); + current_val &= ~(1 << nsleep_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置电机睡眠输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/*********************************************IO扩展板LCD引脚配置参数***********************************************/ +/** + * @brief 设置 LCD_BL引脚电平(高电平为命令模式,低电平为数据模式) + */ +esp_err_t IOExpansionBoard::SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin) +{ + uint8_t current_val; + if(mode){ + // 进入命令模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << bl_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入数据模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << bl_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/** + * @brief 设置 LCD_RST引脚电平(高电平为复位模式,低电平为工作模式) + */ +esp_err_t IOExpansionBoard::SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t reset_pin) +{ + uint8_t current_val; + if(mode){ + // 进入复位模式 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入复位模式"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "LCD复位输出寄存器: 0x%x", current_val); + current_val |= (1 << reset_pin); + //打印设置后的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置LCD复位输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入工作模式 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入工作模式"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "LCD复位输出寄存器: 0x%x", current_val); + current_val &= ~(1 << reset_pin); + //打印设置后的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置LCD复位输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/** + * @brief 设置 LED_EN 引脚状态(v1.1.16:高电平有效,低电平无效) + */ +esp_err_t IOExpansionBoard::SetLedEnMode(bool enable) +{ + uint8_t current_val; + esp_err_t err = IoexpandReadReg(LED_EN_PORT, ¤t_val); + if (err != ESP_OK) return err; + if (enable) { + current_val |= (1 << LED_EN_PIN); // 高电平:开启 + } else { + current_val &= ~(1 << LED_EN_PIN); // 低电平:关闭 + } + return IoexpandWriteReg(LED_EN_PORT, current_val); +} + +/*********************************************IO扩展板的输入引脚配置以及中断引脚定义***********************************************/ +/** + * @brief 设置 毫米波雷达的中断引脚 + */ +esp_err_t IOExpansionBoard::SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin) +{ + uint8_t current_val; + if(mode){ + // 进入输入模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + current_val |= (1 << interrupt_pin); + return IoexpandWriteReg(INPUT_PORT, current_val); + } + else{ + // 进入输出模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + current_val &= ~(1 << interrupt_pin); + return IoexpandWriteReg(INPUT_PORT, current_val); + } +} + +/** + * @brief 设置 PA_CTRL引脚电平 + */ +esp_err_t IOExpansionBoard::SetPaCtrlMode(bool mode) +{ + uint8_t current_val; + if(mode){ + // 进入高电平状态 + ESP_LOGI("io_ex:", "read reg"); + IoexpandReadReg(PA_CTRL_PORT, ¤t_val); + current_val |= (1 << PA_CTRL_PIN); + return IoexpandWriteReg(PA_CTRL_PORT, current_val); + } + else{ + // 进入低电平状态 + IoexpandReadReg(PA_CTRL_PORT, ¤t_val); + current_val &= ~(1 << PA_CTRL_PIN); + return IoexpandWriteReg(PA_CTRL_PORT, current_val); + } +} + + + +/** + * @brief I2C数据读取任务主体 + */ +void IOExpansionBoard::I2cReadTask(void* pvParameters) +{ + IOExpansionBoard* instance = static_cast(pvParameters); + if (!instance) { + vTaskDelete(nullptr); + return; + } + // 初始化复位引脚 + esp_err_t err = instance->ResetGpioInit(IO_EXPAND_RSTN); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO复位初始化失败"); + } + + // 执行硬件复位 - 这是解决中断引脚持续拉低的关键 + err = instance->ResetIoExpand(); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板硬件复位失败"); + } else { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板硬件复位成功"); + + // 检查复位后的中断引脚状态 + int interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "复位后中断引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + } + + // 初始化IO扩展板子的中断引脚 + err = instance->InterruptGpioInit(GPIO_INPUT_PIN_SEL); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断初始化失败"); + } + // 设置IO扩展板模式 - 复位后必须重新配置寄存器! + err = instance->IoexpandSetMode(); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板模式配置失败"); + } else { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板模式配置成功"); + } + // 设置LCD屏幕复位引脚 + err = instance->SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功"); + } + // 设置LCD屏幕复位引脚为低电平 + err = instance->SetLcdResetMode(LCD_RST_LOW, LCD_RST_PORT, LCD_RST_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功"); + } + + uint8_t current_val_port0_ = 0,current_val_port1_ = 0,current_temp_ = 0; + for (;;) { + // 等待中断事件触发 + if (instance->i2c_task_event_group_) { + xEventGroupWaitBits(instance->i2c_task_event_group_, BIT0, pdTRUE, pdFALSE, portMAX_DELAY); + } + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板中断触发"); + + // 检查中断触发时的引脚状态 + int interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "中断触发时引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + + // AW9523B中断处理说明(根据数据手册): + // 1. 当输入引脚状态变化时,AW9523B会拉低INT引脚(连接到ESP32的GPIO10) + // 2. 通过读取输入端口寄存器(00H, 01H)来清除对应端口的中断 + // 3. 无独立的中断状态寄存器,需要通过输入电平变化来判断中断源 + // 4. 读取INPUT_PORT0 (00H) 清除P0口中断,读取INPUT_PORT1 (01H) 清除P1口中断 + + // 一次性读取两个端口的输入寄存器,避免重复读取和错误的OR操作 + instance->IoexpandReadReg(INPUT_PORT0, ¤t_val_port0_); + instance->IoexpandReadReg(INPUT_PORT1, ¤t_val_port1_); + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "读取端口状态 - Port0: 0x%02X, Port1: 0x%02X", current_val_port0_, current_val_port1_); + + // 检查读取寄存器后中断引脚是否被清除(应该恢复高电平) + interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "读取寄存器后中断引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + + //判断是否有中断来自雷达引脚 + if((RADAR_INTERRUPT_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << RADAR_INTERRUPT_PIN))){ + // 检查雷达引脚状态是否发生了变化,避免重复触发 + bool current_radar_state = (current_val_port0_ & (1 << RADAR_INTERRUPT_PIN)) != 0; + if (current_radar_state != instance->radar_last_state_) { + instance->radar_last_state_ = current_radar_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用毫米波雷达回调函数 + if (instance->radar_) { + instance->radar_->TriggerRadarDetectCallback(); + } + // 调用雷达回调函数(新接口) + if (instance->radar_callback_) { + instance->radar_callback_(); + } + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((RADAR_INTERRUPT_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << RADAR_INTERRUPT_PIN))){ + // 检查雷达引脚状态是否发生了变化,避免重复触发 + bool current_radar_state = (current_val_port1_ & (1 << RADAR_INTERRUPT_PIN)) != 0; + if (current_radar_state != instance->radar_last_state_) { + instance->radar_last_state_ = current_radar_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚1\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用毫米波雷达回调函数 + if (instance->radar_) { + instance->radar_->TriggerRadarDetectCallback(); + } + // 调用雷达回调函数(新接口) + if (instance->radar_callback_) { + instance->radar_callback_(); + } + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + // else{ + // ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "未检测到雷达引脚中断\n"); + // } + + //判断是否有中断来自初始光学传感器引脚 + if((START_PHOTO_INTERRUPTER_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << START_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port0_ & (1 << START_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port0_state_ & (1 << START_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自初始光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用初始光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerStartCallback(); + } + // 调用光学传感器开始回调函数(新接口) + if (instance->photo_start_callback_) { + instance->photo_start_callback_(); + } + // 更新状态 + instance->last_port0_state_ = current_val_port0_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((START_PHOTO_INTERRUPTER_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << START_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port1_ & (1 << START_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port1_state_ & (1 << START_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自初始光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用初始光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerStartCallback(); + } + // 调用光学传感器开始回调函数(新接口) + if (instance->photo_start_callback_) { + instance->photo_start_callback_(); + } + // 更新状态 + instance->last_port1_state_ = current_val_port1_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + // else{ + // // ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "未检测到初始光学传感器引脚中断\n"); + // } + + //判断是否有中断来自结束光学传感器引脚 + if((END_PHOTO_INTERRUPTER_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << END_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port0_ & (1 << END_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port0_state_ & (1 << END_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自结束光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用结束光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerEndCallback(); + } + // 调用光学传感器结束回调函数(新接口) + if (instance->photo_end_callback_) { + instance->photo_end_callback_(); + } + // 更新状态 + instance->last_port0_state_ = current_val_port0_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((END_PHOTO_INTERRUPTER_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << END_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port1_ & (1 << END_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port1_state_ & (1 << END_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自结束光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用结束光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerEndCallback(); + } + // 调用光学传感器结束回调函数(新接口) + if (instance->photo_end_callback_) { + instance->photo_end_callback_(); + } + // 更新状态 + instance->last_port1_state_ = current_val_port1_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + + //CHRG引脚充电前为高电平 充电中为低电平 充满电为高电平 + //FULL未充满为高电平 充满电为低电平 + //判断是否有中断来自电池充电引脚 + //根据配置:BATTERY_CHRG_INPUT = INPUT_PORT0, BATTERY_FULL_INPUT = INPUT_PORT1 + + // AW9523B没有独立的中断状态寄存器,需要通过比较前后状态变化来判断中断源 + // 由于读取输入端口会清除中断,我们需要先保存当前状态,然后与上次状态比较 + + //获取当前电池状态 + bool current_charging_state = !(current_val_port0_ & (1 << BATTERY_CHRG_PIN)); // CHRG低电平表示充电中 + bool current_full_state = !(current_val_port1_ & (1 << BATTERY_FULL_PIN)); // FULL低电平表示已充满 + + // 详细的调试信息 + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - Port0: 0x%02X, Port1: 0x%02X", current_val_port0_, current_val_port1_); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - CHRG_PIN: %d (bit %d), FULL_PIN: %d (bit %d)", + (current_val_port0_ & (1 << BATTERY_CHRG_PIN)) ? 1 : 0, BATTERY_CHRG_PIN, + (current_val_port1_ & (1 << BATTERY_FULL_PIN)) ? 1 : 0, BATTERY_FULL_PIN); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - 充电状态: %s, 充满状态: %s", + current_charging_state ? "充电中" : "未充电", + current_full_state ? "已充满" : "未充满"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - 上次充电状态: %s, 上次充满状态: %s", + instance->battery_charging_last_state_ ? "充电中" : "未充电", + instance->battery_full_last_state_ ? "已充满" : "未充满"); + + //检查充电状态是否发生变化 + if (current_charging_state != instance->battery_charging_last_state_) { + instance->battery_charging_last_state_ = current_charging_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "电池充电状态变化: %s", current_charging_state ? "充电中" : "未充电"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "充电状态变化详情 - 从 %s 到 %s", + instance->battery_charging_last_state_ ? "未充电" : "充电中", + current_charging_state ? "充电中" : "未充电"); + + if (current_charging_state) { + // 进入充电状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到开始充电"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerChrgCallback(); + } + if (instance->battery_charging_callback_) { + instance->battery_charging_callback_(); + } + } else { + // 退出充电状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到停止充电"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerNotChrgCallback(); + } + if (instance->battery_not_charging_callback_) { + instance->battery_not_charging_callback_(); + } + } + } + + //检查充满状态是否发生变化 + if (current_full_state != instance->battery_full_last_state_) { + instance->battery_full_last_state_ = current_full_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "电池充满状态变化: %s", current_full_state ? "已充满" : "未充满"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "充满状态变化详情 - 从 %s 到 %s", + instance->battery_full_last_state_ ? "未充满" : "已充满", + current_full_state ? "已充满" : "未充满"); + + if (current_full_state) { + // 进入充满状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到电池已充满"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerFullCallback(); + } + if (instance->battery_full_callback_) { + instance->battery_full_callback_(); + } + } + + } + + // 根据AW9523B数据手册:读取输入端口寄存器清除对应端口的中断 + // 读取INPUT_PORT0 (00H) 清除P0口中断,读取INPUT_PORT1 (01H) 清除P1口中断 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "中断处理完成,已读取输入端口寄存器清除中断标志"); + } +} + + +/** + * @brief 创建I2C数据读取任务 + */ +void IOExpansionBoard::CreateI2cReadTask() +{ + printf("创建I2C读取任务之前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之前:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + if (xI2CReadTaskHandle_) { + return; // 任务已创建 + } + + xTaskCreateWithCaps( + I2cReadTask, + "i2c_read_task", + I2C_TASK_STACK, + this, + I2C_TASK_PRIORITY, + &xI2CReadTaskHandle_, + MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT + ); + + if (xI2CReadTaskHandle_ == NULL) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to create static I2C read task"); + } else { + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static I2C read task created successfully"); + } + printf("创建I2C读取任务之后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之后:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +} + +/** + * @brief 启动I2C任务 (整合初始化和任务创建) + */ +esp_err_t IOExpansionBoard::StartTask() +{ + // 再创建任务 + if (!xI2CReadTaskHandle_) { + CreateI2cReadTask(); + } + return ESP_OK; +} diff --git a/main/02_physical/boards/board_v1_1_16/io_expansion_board.h b/main/02_physical/boards/board_v1_1_16/io_expansion_board.h new file mode 100644 index 0000000..0157e39 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_16/io_expansion_board.h @@ -0,0 +1,432 @@ +#ifndef IO_EXPANSION_BOARD_H +#define IO_EXPANSION_BOARD_H + +#include +#include +#include +#include +#include +#include +#include "i2c_bus.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include +#include +#include +#include +#include +#include +#include +#include "esp_err.h" +#include "config.h" +#include "portmacro.h" + +// 前向声明,避免循环引用 +class MillimeterWaveRadar; +class PhotoInterrupter; +class AdcBatteryMonitor; + +// 回调函数类型定义 +typedef std::function RadarCallback; +typedef std::function PhotoInterrupterStartCallback; +typedef std::function PhotoInterrupterEndCallback; +typedef std::function BatteryChargingCallback; +typedef std::function BatteryFullCallback; +typedef std::function BatteryNotChargingCallback; + +/* 寄存器地址 */ +#define INPUT_PORT0 0x00 // 输入端口0寄存器 +#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取) +#define OUTPUT_PORT0 0x02 // 输出端口0寄存器 +#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平 +#define CONFIG_PORT0 0x04 // 配置端口0寄存器 +#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式 +#define INT_PORT0 0x06 // 中断端口0寄存器 +#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的) +#define CTL 0x11 // 全局控制寄存器 +#define ID 0x23 // 芯片ID寄存器(0x23) + +/***********************************IO扩展板电机引脚配置参数*************************************/ +/* 设置步进电机方向 */ +#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转 +#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转 +#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4 +#define STEPPER_MOTOR_DIR_CONFIG CONFIG_PORT0 //步进电机方向引脚配置在P0_4 + +/* 设置步进电机细分模式 */ +#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5 +#define STEPPER_MOTOR_M0_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define STEPPER_MOTOR_M0_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_5 + +#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4 +#define STEPPER_MOTOR_M1_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define STEPPER_MOTOR_M1_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_4 + +/* 设置步进电机睡眠引脚 */ +#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式 +#define STEPPER_MOTOR_WORK true //步进电机进入工作模式 +#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6 +#define STEPPER_MOTOR_SLEEP_CONFIG CONFIG_PORT1 //步进电机睡眠引脚配置在P1_6 +#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 + +/* 设置电机的使能引脚 */ +#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7 +#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_ENABLE_CONFIG CONFIG_PORT0 //电机使能引脚配置在P0_7 +#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平 +#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平 + +/* 设置毫米波雷达对应IO扩展板的中断引脚 */ +#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7 +#define RADAR_INTERRUPT_CONFIG CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口 +#define RADAR_INTERRUPT_INPUT INPUT_PORT1 //毫米波雷达中断引脚输入状态检测在INPUT_PORT1 +#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态 +#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态 +/* 任务配置常量 */ +#define WRITE_BUF_SIZE 2 // I2C单次写入字节数 +#define READ_BUF_SIZE 2 // I2C单次读取字节数 +#define I2C_TASK_PRIORITY 2 // 任务优先级(中等) +#define I2C_TASK_STACK 4096 // 任务栈大小(4KB) + +// 光学传感器引脚定义 +#define START_PHOTO_INTERRUPTER_PIN 2 // 光学传感器引脚(P0_2) +#define START_PHOTO_INTERRUPTER_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口 +#define START_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0 +#define START_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平 +#define START_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平 + +#define END_PHOTO_INTERRUPTER_PIN 3 // 光学传感器引脚(P0_3) +#define END_PHOTO_INTERRUPTER_PORT_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口 +#define END_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0 +#define END_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平 +#define END_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平 + +/***********************************LED_EN 电源控制(WS2812/背光等)*************************************/ +// v1.1.16: LED_EN 高电平有效,低电平无效;端口为 IO 扩展 P0_1 +#define LED_EN_PIN 1 +#define LED_EN_PORT OUTPUT_PORT0 +#define LED_EN_CONFIG CONFIG_PORT0 + +/***********************************IO扩展板LCD引脚配置参数*************************************/ +// /* 设置LCD的BL引脚 */ +// #define LCD_BL_PIN 6 //LCD背光引脚对应IO扩展板引脚P0_6 +// #define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +// #define LCD_BL_CONFIG CONFIG_PORT0 //LCD背光引脚配置在P0_6 +// #define LCD_BL_HIGH true //LCD背光引脚状态为高电平 +// #define LCD_BL_LOW false //LCD背光引脚状态为低电平 + +/* 设置LCD的RST引脚 */ +#define LCD_RST_PIN 1 //LCD复位引脚对应IO扩展板引脚P1_1 +#define LCD_RST_CONFIG CONFIG_PORT1 //LCD复位引脚配置在P1_1 +#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define LCD_RST_HIGH true //LCD复位引脚状态为高电平 +#define LCD_RST_LOW false //LCD复位引脚状态为低电平 + +/* 设置PA控制引脚 */ +#define PA_CTRL_PIN 2 //PA控制引脚对应IO扩展板引脚P1_2 +#define PA_CTRL_CONFIG CONFIG_PORT1 //PA控制引脚配置在P1_2 +#define PA_CTRL_PORT OUTPUT_PORT1 //PA控制引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define PA_CTRL_HIGH true //PA控制引脚状态为高电平 +#define PA_CTRL_LOW false //PA控制引脚状态为低电平 + +// 电池充电检测引脚定义 +#define BATTERY_FULL_INPUT INPUT_PORT1 // 电池充满检测引脚挂载在IO扩展板的输入端口 +#define BATTERY_FULL_PIN 3 // 电池充满检测引脚对应IO扩展板引脚P1_3 +#define BATTERY_FULL_CONFIG CONFIG_PORT1 // 电池充满检测引脚配置在P1_3 + +#define BATTERY_CHRG_INPUT INPUT_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口 +#define BATTERY_CHRG_PIN 5 // 充电检测引脚(P0_5) +#define BATTERY_CHRG_CONFIG CONFIG_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口 + +#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签 +#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签 + +// GPIO引脚定义 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚 +// #define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚 + +/** + * @class IOExpansionBoard + * @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作 + */ +class IOExpansionBoard +{ +public: + /** + * @brief 构造函数 + */ + IOExpansionBoard(); + + /** + * @brief 设置毫米波雷达指针 + * @param radar 毫米波雷达对象指针 + */ + void SetRadar(MillimeterWaveRadar* radar) { radar_ = radar; }; + + /** + * @brief 设置限位开关指针 + * @param photo_interrupter 限位开关对象指针 + */ + void setPhotoInterrupter(PhotoInterrupter* photo_interrupter) { photo_interrupter_ = photo_interrupter; }; + + /** + * @brief 设置电池监控器指针 + * @param battery_monitor 电池监控器对象指针 + */ + void setBatteryMonitor(AdcBatteryMonitor* battery_monitor) { battery_monitor_ = battery_monitor; }; + + /** + * @brief 析构函数 + */ + ~IOExpansionBoard(); + + /** + * @brief 初始化GPIO中断检测 + * @param gpio_num 中断引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t InterruptGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetIoExpand(); + + /** + * @brief 初始化I2C主机通信 + * @return esp_err_t 初始化结果 + */ + // esp_err_t IoExpansionI2cInit(); + + /** + * @brief 创建I2C数据读取任务 + */ + void CreateI2cReadTask(); + + /** + * @brief 启动I2C任务(整合初始化和任务创建) + * @return esp_err_t 操作结果 + */ + esp_err_t StartTask(); + + /** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data); + + /** + * @brief 读寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要读出的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data); + + /** + * @brief 读取输入端口0寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t ReadInputPort0(uint8_t *data); + + /** + * @brief 读取输入端口1寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t ReadInputPort1(uint8_t *data); + + // /** + // * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断 + // * @param reg_addr 寄存器地址 + // * @return esp_err_t 操作结果 + // */ + // esp_err_t SetInterruptStatus(bool status); + + /** + * @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandSetMode(); + + /** + * @brief 设置步进电机的细分模式 + * @param mode 模式:1/2/4/8/16/32/64 + * @return esp_err_t 操作结果 + */ + void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin); + + /** + * @brief 设置步进电机的方向 + * @param dir 方向 + * @param OUTPUT_PORT 输出端口 + * @param pin 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin); + + /** + * @brief 设置步进电机的睡眠模式 + * @param 是否进入睡眠模式 + * @param 输出端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin); + + /** + * @brief 设置步进电机的使能引脚状态 + * @param 使能状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin); + + /** + * @brief 设置LCD的BL引脚状态 + * @param BL状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin); + + /** + * @brief 设置LCD的RST引脚状态 + * @param RST状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin); + + /** + * @brief 设置 LED_EN 引脚状态(v1.1.16:高电平有效,低电平无效) + * @param enable true: 开启(置高),false: 关闭(置低) + * @return esp_err_t 操作结果 + */ + esp_err_t SetLedEnMode(bool enable); + + /** + * @brief 设置PA控制引脚状态 + * @param mode PA_CTRL状态(true为高电平,false为低电平) + * @return esp_err_t 操作结果 + */ + esp_err_t SetPaCtrlMode(bool mode); + + /** + * @brief 设置雷达中断引脚 + * @param 毫米波雷达的中断引脚模式 + * @param 输入端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin); + + /** + * @brief 计算Port0的字节值 + * @return uint8_t 操作结果 + */ + uint8_t ByteCalculatePort0(); + + /** + * @brief 计算Port1的字节值 + * @return uint8_t 操作结果 + */ + uint8_t ByteCalculatePort1(); + + /** + * @brief 设置雷达中断回调函数 + * @param callback 雷达中断回调函数 + */ + void SetRadarCallback(RadarCallback callback) { radar_callback_ = callback; } + + /** + * @brief 设置光学传感器开始中断回调函数 + * @param callback 光学传感器开始中断回调函数 + */ + void SetPhotoInterrupterStartCallback(PhotoInterrupterStartCallback callback) { photo_start_callback_ = callback; } + + /** + * @brief 设置光学传感器结束中断回调函数 + * @param callback 光学传感器结束中断回调函数 + */ + void SetPhotoInterrupterEndCallback(PhotoInterrupterEndCallback callback) { photo_end_callback_ = callback; } + + /** + * @brief 设置电池充电中断回调函数 + * @param callback 电池充电中断回调函数 + */ + void SetBatteryChargingCallback(BatteryChargingCallback callback) { battery_charging_callback_ = callback; } + + /** + * @brief 设置电池充满中断回调函数 + * @param callback 电池充满中断回调函数 + */ + void SetBatteryFullCallback(BatteryFullCallback callback) { battery_full_callback_ = callback; } + + /** + * @brief 设置电池非充电中断回调函数 + * @param callback 电池非充电中断回调函数 + */ + void SetBatteryNotChargingCallback(BatteryNotChargingCallback callback) { battery_not_charging_callback_ = callback; } + + // 公共成员变量 + i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄 + uint8_t device_addr_; // I2C设备地址 + +private: + // 静态成员函数 + MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调 + PhotoInterrupter* photo_interrupter_ = nullptr; // 限位开关指针,用于触发回调 + AdcBatteryMonitor* battery_monitor_ = nullptr; // 电池监控器指针,用于触发回调 + static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数 + static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数 + + // 成员变量用于状态跟踪 + uint8_t last_port0_state_ = 0; // 上次检测到的Port0状态 + uint8_t last_port1_state_ = 0; // 上次检测到的Port1状态 + bool radar_last_state_ = false; // 雷达引脚上一次的状态 + bool battery_charging_last_state_ = false; // 电池充电状态上一次的状态 + bool battery_full_last_state_ = false; // 电池充满状态上一次的状态 + + // 回调函数成员变量 + RadarCallback radar_callback_ = nullptr; + PhotoInterrupterStartCallback photo_start_callback_ = nullptr; + PhotoInterrupterEndCallback photo_end_callback_ = nullptr; + BatteryChargingCallback battery_charging_callback_ = nullptr; + BatteryFullCallback battery_full_callback_ = nullptr; + BatteryNotChargingCallback battery_not_charging_callback_ = nullptr; + + // PhotoInterrupter* photo_interrupter_ = nullptr; // 光学传感器指针,用于触发回调 + // /** + // * @brief 分配静态任务所需的内存 + // * @return bool 分配是否成功 + // */ + // bool AllocateStaticTaskMemory(); + + // /** + // * @brief 释放静态任务分配的内存 + // */ + // void FreeStaticTaskMemory(); + + // 实例成员变量 + EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组 + TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄 + bool is_initialized_ = false; // 初始化状态标记(新增) + gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚 + gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚 + + // StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM) + // StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM) +}; + +#endif diff --git a/main/02_physical/boards/board_v1_1_16/power_management_config.h b/main/02_physical/boards/board_v1_1_16/power_management_config.h new file mode 100644 index 0000000..da609fb --- /dev/null +++ b/main/02_physical/boards/board_v1_1_16/power_management_config.h @@ -0,0 +1,178 @@ +/** + * @file power_management_config.h + * @brief 功耗管理配置和策略定义 + * @author Embedded Software Expert + * @date 2025年1月 + * + * 这个文件定义了功耗管理的配置参数、策略和优化建议, + * 为系统提供灵活的功耗管理方案。 + */ + +#ifndef POWER_MANAGEMENT_CONFIG_H +#define POWER_MANAGEMENT_CONFIG_H + +#include "esp_sleep.h" +#include "driver/rtc_io.h" +#include "esp32/rom/rtc.h" + +/** + * @brief 功耗管理配置结构体 + */ +typedef struct { + // 睡眠模式配置 + uint64_t light_sleep_duration_us; // 轻度睡眠持续时间(微秒) + uint64_t deep_sleep_duration_us; // 深度睡眠持续时间(微秒) + + // 唤醒源配置 + bool enable_timer_wakeup; // 启用定时器唤醒 + bool enable_gpio_wakeup; // 启用GPIO唤醒 + bool enable_touch_wakeup; // 启用触摸唤醒 + gpio_num_t wakeup_gpio_num; // 唤醒GPIO编号 + int wakeup_level; // 唤醒电平(0或1) + + // 功耗优化配置 + bool disable_bt_in_sleep; // 睡眠时关闭蓝牙 + bool disable_wifi_in_sleep; // 睡眠时关闭WiFi + bool reduce_cpu_frequency; // 降低CPU频率 + uint32_t cpu_frequency_hz; // CPU频率(Hz) + + // 外设功耗配置 + bool power_down_sdcard; // 睡眠时关闭SD卡电源 + bool power_down_display; // 睡眠时关闭显示电源 + bool power_down_audio; // 睡眠时关闭音频电源 + bool power_down_motor; // 睡眠时关闭电机电源 + + // RTC内存配置 + bool preserve_rtc_memory; // 保留RTC内存 + size_t rtc_memory_size; // RTC内存大小 +} power_management_config_t; + +/** + * @brief 默认功耗管理配置 + */ +#define DEFAULT_POWER_CONFIG { \ + .light_sleep_duration_us = 1000000, /* 1秒 */ \ + .deep_sleep_duration_us = 30000000, /* 30秒 */ \ + .enable_timer_wakeup = true, /* 启用定时器唤醒 */ \ + .enable_gpio_wakeup = false, /* 不启用GPIO唤醒 */ \ + .enable_touch_wakeup = false, /* 不启用触摸唤醒 */ \ + .wakeup_gpio_num = GPIO_NUM_NC, /* 无GPIO唤醒 */ \ + .wakeup_level = 0, /* 低电平唤醒 */ \ + .disable_bt_in_sleep = true, /* 睡眠时关闭蓝牙 */ \ + .disable_wifi_in_sleep = true, /* 睡眠时关闭WiFi */ \ + .reduce_cpu_frequency = true, /* 降低CPU频率 */ \ + .cpu_frequency_hz = 80000000, /* 80MHz */ \ + .power_down_sdcard = true, /* 睡眠时关闭SD卡 */ \ + .power_down_display = true, /* 睡眠时关闭显示 */ \ + .power_down_audio = true, /* 睡眠时关闭音频 */ \ + .power_down_motor = true, /* 睡眠时关闭电机 */ \ + .preserve_rtc_memory = true, /* 保留RTC内存 */ \ + .rtc_memory_size = 4096, /* 4KB RTC内存 */ \ +} + +/** + * @brief 各功耗模式的详细配置 + */ +static const power_management_config_t idle_mode_config = { + .light_sleep_duration_us = 500000, // 500ms轻度睡眠 + .deep_sleep_duration_us = 0, // 不使用深度睡眠 + .enable_timer_wakeup = true, + .enable_gpio_wakeup = true, + .wakeup_gpio_num = GPIO_NUM_0, // 按键唤醒 + .wakeup_level = 0, + .disable_bt_in_sleep = false, // 保持蓝牙连接 + .disable_wifi_in_sleep = false, // 保持WiFi连接 + .reduce_cpu_frequency = true, + .cpu_frequency_hz = 40000000, // 40MHz + .power_down_sdcard = false, // 保持SD卡(可能有后台任务) + .power_down_display = true, // 关闭显示背光 + .power_down_audio = true, // 关闭音频 + .power_down_motor = true, // 关闭电机 + .preserve_rtc_memory = true, + .rtc_memory_size = 2048, +}; + +static const power_management_config_t light_sleep_config = { + .light_sleep_duration_us = 0, // 直接进入轻度睡眠 + .deep_sleep_duration_us = 0, + .enable_timer_wakeup = true, + .enable_gpio_wakeup = true, + .wakeup_gpio_num = GPIO_NUM_0, + .wakeup_level = 0, + .disable_bt_in_sleep = true, // 关闭蓝牙 + .disable_wifi_in_sleep = true, // 关闭WiFi + .reduce_cpu_frequency = true, + .cpu_frequency_hz = 40000000, + .power_down_sdcard = true, // 关闭SD卡 + .power_down_display = true, // 关闭显示 + .power_down_audio = true, // 关闭音频 + .power_down_motor = true, // 关闭电机 + .preserve_rtc_memory = true, + .rtc_memory_size = 4096, +}; + +static const power_management_config_t deep_sleep_config = { + .light_sleep_duration_us = 0, + .deep_sleep_duration_us = 60000000, // 60秒深度睡眠 + .enable_timer_wakeup = true, + .enable_gpio_wakeup = true, + .wakeup_gpio_num = GPIO_NUM_0, + .wakeup_level = 0, + .disable_bt_in_sleep = true, // 关闭蓝牙 + .disable_wifi_in_sleep = true, // 关闭WiFi + .reduce_cpu_frequency = true, + .cpu_frequency_hz = 10000000, // 10MHz + .power_down_sdcard = true, // 关闭SD卡 + .power_down_display = true, // 关闭显示 + .power_down_audio = true, // 关闭音频 + .power_down_motor = true, // 关闭电机 + .preserve_rtc_memory = true, + .rtc_memory_size = 8192, +}; + +/** + * @brief 功耗统计和监控结构体 + */ +typedef struct { + uint64_t total_sleep_time_us; // 总睡眠时间 + uint64_t total_wake_time_us; // 总唤醒时间 + uint32_t sleep_count; // 睡眠次数 + uint32_t wake_count; // 唤醒次数 + uint32_t average_sleep_duration_us; // 平均睡眠时长 + uint32_t average_wake_duration_us; // 平均唤醒时长 + float estimated_power_saving_percent; // 估计的功耗节省百分比 +} power_statistics_t; + +/** + * @brief 功耗优化建议 + * + * 基于硬件特性和使用模式,提供功耗优化建议 + */ +typedef enum { + OPTIMIZATION_NONE = 0, + OPTIMIZATION_REDUCE_CPU_FREQ, // 降低CPU频率 + OPTIMIZATION_DISABLE_UNUSED_PERIPHERALS, // 关闭未使用的外设 + OPTIMIZATION_USE_LIGHT_SLEEP, // 使用轻度睡眠 + OPTIMIZATION_USE_DEEP_SLEEP, // 使用深度睡眠 + OPTIMIZATION_OPTIMIZE_GPIO_STATES, // 优化GPIO状态 + OPTIMIZATION_USE_RTC_MEMORY, // 使用RTC内存 + OPTIMIZATION_BATCH_OPERATIONS, // 批量操作 +} power_optimization_t; + +/** + * @brief 功耗管理事件回调 + */ +typedef void (*power_event_callback_t)(power_mode_t old_mode, power_mode_t new_mode, void* user_data); + +/** + * @brief 功耗管理事件 + */ +typedef enum { + POWER_EVENT_MODE_CHANGE, // 功耗模式改变 + POWER_EVENT_SLEEP_START, // 睡眠开始 + POWER_EVENT_SLEEP_END, // 睡眠结束 + POWER_EVENT_WAKEUP, // 系统唤醒 + POWER_EVENT_OPTIMIZATION_TRIGGER, // 功耗优化触发 +} power_event_t; + +#endif // POWER_MANAGEMENT_CONFIG_H \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_17/board_sweekar.cc b/main/02_physical/boards/board_v1_1_17/board_sweekar.cc new file mode 100644 index 0000000..59cd1dd --- /dev/null +++ b/main/02_physical/boards/board_v1_1_17/board_sweekar.cc @@ -0,0 +1,780 @@ +/** + * @file board.cc + * @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +extern "C" { +#include "esp_log.h" +#include "driver/gpio.h" +#include "driver/uart.h" +#include "driver/ledc.h" +#include "driver/gptimer.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "hal/gpio_types.h" +#include "hal/uart_types.h" +#include "esp_check.h" +#include "sdkconfig.h" +#include "i2c_bus.h" +#include "esp_peripherals.h" +#include "periph_sdcard.h" +#include "esp_sleep.h" +#include "driver/rtc_io.h" +} + +#include "board_sweekar.h" +#include "config.h" +#include "board.h" // 添加board.h以获取audio_board_sdcard_init函数声明 +#include "drv8428.h" +#include "aw8646.h" +#include "esp_vfs_fat.h" +#include "audio_mem.h" +#include "esp_timer.h" +#include "base_board_hal_i2c.h" + +#define TAG "board_sweekar" + +static BoardSweekar* s_board_instance = nullptr; + +BoardSweekar* BoardSweekar::GetInstance() +{ + if (s_board_instance == nullptr) { + static BoardSweekar global_board; + s_board_instance = &global_board; + } + return s_board_instance; +} + +BoardSweekar::BoardSweekar() +{ +#ifdef CONFIG_STEPPER_DRIVER_AW8646 + stepper_driver_ = new Aw8646Driver(io_expansion_); +#else + stepper_driver_ = new Drv8428Driver(io_expansion_); +#endif + + // Initialize Shutdown Control Pin (GPIO_NUM_13) and pull it HIGH + // This is required to keep the main power on. +#ifdef SHUTDOWN_CTRL_PIN + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = (1ULL << SHUTDOWN_CTRL_PIN); + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + gpio_config(&io_conf); + // 拉低开机 + gpio_set_level(SHUTDOWN_CTRL_PIN, 0); + ESP_LOGI(TAG, "Initialized SHUTDOWN_CTRL_PIN (%d) to LOW (Power ON)", SHUTDOWN_CTRL_PIN); +#endif +} + +BoardSweekar::~BoardSweekar() +{ + if (stepper_driver_) { + delete stepper_driver_; + stepper_driver_ = nullptr; + } +} + +void BoardSweekar::SetAudioAmplifier(bool enable) { + // 隐藏具体的硬件实现细节(比如当前版本是通过 IO 扩展板控制的) + io_expansion_.SetPaCtrlMode(enable); + ESP_LOGI(TAG, "Audio Amplifier %s", enable ? "ENABLED" : "DISABLED"); +} + +/*========================== 步进电机相关驱动 ==========================*/ + +/** + * @brief 步进电机初始化函数 + * 配置步进电机所需的GPIO引脚模式,通过IO扩展板设置步进驱动芯片的工作模式 + * 在 stepper_motor.cc 中完成 GPTimer + GPIO 翻转 STEP 脉冲的初始化 + */ +void BoardSweekar::StepperMotorInit(void) +{ + esp_err_t err = ESP_OK; + + // 1) STEP 引脚改为普通 GPIO(不再用 LEDC) + gpio_config_t io_cfg; + io_cfg.pin_bit_mask = 1ULL << STEPPER_STEP_IO; + io_cfg.mode = GPIO_MODE_OUTPUT; + io_cfg.pull_up_en = GPIO_PULLUP_DISABLE; + io_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_cfg.intr_type = GPIO_INTR_DISABLE; + err = gpio_config(&io_cfg); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "步进电机 STEP GPIO 配置失败, 错误码: 0x%x", err); + } + + // 初始电平拉低,保证上电不乱跳 + gpio_set_level(STEPPER_STEP_IO, 0); + + // 2) 检查 I2C 总线是否已初始化 + if (bus_handle_ == nullptr) + { + ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()"); + return; + } + + // 3) 初始化驱动对象并初始化 + if (stepper_driver_) { + err = stepper_driver_->Init(); + if (err != ESP_OK) { + ESP_LOGE(TAG_BOARD, "步进电机驱动初始化失败, 错误码: 0x%x", err); + } + } else { + ESP_LOGE(TAG_BOARD, "步进电机驱动创建失败"); + } +} + +/** + * @brief LCD IO引脚初始化函数(消除与步进电机的耦合) + * + * 配置LCD所需的IO扩展板寄存器,确保LCD复位引脚正常工作 + * 此函数独立于步进电机初始化,专门处理LCD相关的IO配置 + */ +void BoardSweekar::LcdIoInit(void) +{ + esp_err_t err = ESP_OK; + + // 1) 检查I2C总线是否已初始化 + if (bus_handle_ == nullptr) + { + ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()"); + return; + } + + // 2) 执行硬件复位,确保IO扩展板处于已知状态 + err = io_expansion_.ResetIoExpand(); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "IO扩展板硬件复位失败, 错误码: 0x%x", err); + return; + } + else + { + ESP_LOGI(TAG_BOARD, "IO扩展板硬件复位成功"); + } + + // 3) 配置IO扩展板模式(端口方向等) + err = io_expansion_.IoexpandSetMode(); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "IO扩展板模式配置失败, 错误码: 0x%x", err); + return; + } + else + { + ESP_LOGI(TAG_BOARD, "IO扩展板模式配置成功"); + } + + // 4) 初始化LCD复位引脚:设置为高电平 + err = io_expansion_.SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "LCD复位引脚高电平设置失败, 错误码: 0x%x", err); + return; + } + else + { + ESP_LOGI(TAG_BOARD, "LCD复位引脚高电平设置成功"); + } + + // 5) 初始化LED_EN电源为关闭状态 (PMOS高电平关) + // 只有在需要亮灯时,由ActuatorActor主动开启,避免平静状态下常亮 + err = io_expansion_.SetLedEnMode(false); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "初始化LED_EN电源(关闭)失败, 错误码: 0x%x", err); + } + else + { + ESP_LOGI(TAG_BOARD, "初始化LED_EN电源(关闭)成功"); + } +} + +/** + * @brief 执行系统关机 + * 内部拉高 SHUTDOWN_CTRL_PIN 引脚切断电源 + */ +void BoardSweekar::SystemShutdown(void) +{ +#ifdef SHUTDOWN_CTRL_PIN + ESP_LOGI(TAG, "Executing System Shutdown... Pulling SHUTDOWN_CTRL_PIN (%d) HIGH", SHUTDOWN_CTRL_PIN); + // 用户指定:拉高可以完成关机动作 + gpio_set_level(SHUTDOWN_CTRL_PIN, 1); + + // 给一点时间让电源完全断开 + vTaskDelay(pdMS_TO_TICKS(1000)); +#else + ESP_LOGW(TAG, "SHUTDOWN_CTRL_PIN is not defined. Cannot execute hardware shutdown."); +#endif +} + +/*========================== 毫米波雷达相关驱动 ==========================*/ + +/** + * @brief 毫米波雷达串口初始化函数 + * + * 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚, + * 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免 + * 与自定义中断冲突。 + */ +void BoardSweekar::MillimeterWaveRadarUartInit(void) +{ + uart_config_t uart_config = { + .baud_rate = RADAR_BAUD_RATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + .flags = { + .allow_pd = 0, + .backup_before_sleep = 0, + }, + }; + + // 1. 设置串口参数 + ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config)); + + // 2. 设置 UART 引脚 + ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突) + // 增加 RX/TX FIFO 深度以处理突发数据 + ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4, + 0, NULL, 0)); +} + +/** + * @brief 毫米波雷达中断引脚初始化函数 + * + * 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能 + * (如需使用中断需单独进行配置)。 + */ +void BoardSweekar::MillimeterWaveRadarGpioInit(void) +{ + // GPIO配置结构体 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚 + .mode = GPIO_MODE_INPUT, // 设置为输入模式 + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉 + .intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置) + }; + + // 配置GPIO + gpio_config(&io_conf); +} + +/*========================== I2C总线及挂载的从设备相关驱动 ==========================*/ + +/** + * @brief I2C总线及从机设备初始化函数 + * + * 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。 + * 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。 + * 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。 + * + * @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因 + */ +esp_err_t BoardSweekar::I2CMasterInit(void) +{ + static const char *I2C_INIT = "I2C_INIT"; + + // 初始化IO扩展板复位引脚 + gpio_config_t reset_io_conf = { + .pin_bit_mask = (1ULL << IO_EXPAND_RSTN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉 + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&reset_io_conf); + + // 执行复位时序:先拉低100ms,再拉高并等待100ms + gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms + gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + + ESP_LOGI(I2C_INIT, "IO扩展板复位完成"); + + // 创建统一的I2C总线(使用ESP-ADF的i2c_bus) + i2c_config_t i2c_cfg = { + .mode = I2C_MODE_MASTER, + .sda_io_num = I2C0_MASTER_SDA_IO, + .scl_io_num = I2C0_MASTER_SCL_IO, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master = { + .clk_speed = 100000, + }, + }; + + // 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线) + bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg); + if (bus_handle_ == NULL) { + ESP_LOGE(TAG, "Failed to create I2C bus"); + return ESP_FAIL; + } + + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + // ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信 + + // 验证线性马达设备是否存在 + esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR); + } + // 验证IO扩展板设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err); + // 不返回错误,继续初始化其他设备 + } else { + ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR); + } + // 验证陀螺仪设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR); + } + + // 为IO扩展板设置总线句柄和设备地址(使用7位地址) + io_expansion_.bus_handle_ = bus_handle_; + io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1; + + // 线性马达的初始化已移至 InitializeAllHardware 中统一调用 Init 方法 + // linear_motor_ 的参数传递将在那里完成,不再此处直接赋值,提高内聚性 + + ESP_LOGI(I2C_INIT, "I2C总线初始化完成"); + return ESP_OK; +} + +/*========================== VBAT to VBAT_5V相关驱动 ==========================*/ + +/** + * @brief 开启VBAT to VBAT_5V + * + * 创建开启升压的电源管理单元 + * + */ +void BoardSweekar::VbatToVbat5vInit(void) +{ + // 配置VBAT_5V引脚为输出模式 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << VBAT_5V_PIN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&io_conf); + // 使能VBAT_5V + gpio_set_level(VBAT_5V_PIN, 1); +} + +/*========================== 底座控制串口相关驱动 ==========================*/ + +/** + * @brief 底座控制命令串口初始化函数 + */ +// 根据配置选择通信方式的HAL头文件 +#ifdef CONFIG_BASE_BOARD_COMM_I2C +#include "base_board_hal_i2c.h" +#else +#include "base_board_hal_uart.h" +#endif + +void BoardSweekar::BaseBoardControlInit(void) +{ +#ifdef CONFIG_BASE_BOARD_COMM_I2C + // I2C Mode + if (bus_handle_ == nullptr) { + ESP_LOGE(TAG, "I2C bus not initialized before BaseBoardControlInit"); + return; + } + + // 创建 I2C HAL 实例 + BaseBoardHalI2c *hal = new BaseBoardHalI2c(bus_handle_); + base_board_control_.Init(hal); + ESP_LOGI(TAG, "BaseBoardControl I2C initialized"); +#else + // UART Mode + uart_config_t uart_config = { + .baud_rate = BASE_BOARD_CTL_UART_BAUDRATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + .flags = { + .allow_pd = 0, + .backup_before_sleep = 0, + }, + }; + + // 1. 设置串口参数 + ESP_ERROR_CHECK(uart_param_config(BASE_BOARD_CTL_UART_PORT, &uart_config)); + + // 2. 设置 UART 引脚 + ESP_ERROR_CHECK(uart_set_pin(BASE_BOARD_CTL_UART_PORT, BASE_BOARD_CTL_UART_TX_PIN, BASE_BOARD_CTL_UART_RX_PIN, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 3. 安装 UART 驱动 + ESP_ERROR_CHECK(uart_driver_install(BASE_BOARD_CTL_UART_PORT, + BASE_BOARD_CTL_UART_BUF_SIZE, + BASE_BOARD_CTL_UART_BUF_SIZE, + 0, NULL, 0)); + + BaseBoardHalUart *hal = new BaseBoardHalUart(BASE_BOARD_CTL_UART_PORT); + base_board_control_.Init(hal); + ESP_LOGI(TAG, "BaseBoardControl UART initialized"); +#endif +} + +/*========================== SD卡相关驱动 ==========================*/ + +/** + * @brief SD卡初始化函数 + * + * 初始化SD卡外设,使用1线模式进行通信。该函数负责初始化外设管理器 + * 并配置SD卡,为后续的文件系统操作做准备。 + * + * @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示失败原因 + */ +esp_err_t BoardSweekar::InitializeSdcard(void) +{ + static const char *SDCARD_TAG = "SDCARD_INIT"; + esp_err_t ret; + + ESP_LOGI(SDCARD_TAG, "Initializing SD card"); + + if (is_sdcard_initialized_) { + ESP_LOGW(SDCARD_TAG, "SD card already initialized"); + return ESP_OK; + } + + // 初始化外设管理 + esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG(); + periph_cfg.extern_stack = true; // 将任务栈分配到 PSRAM 以节省 Internal SRAM + periph_set_ = esp_periph_set_init(&periph_cfg); + if (!periph_set_) { + ESP_LOGE(SDCARD_TAG, "Failed to initialize peripheral set"); + return ESP_FAIL; + } + + // 初始化SD卡外设 + ret = audio_board_sdcard_init(periph_set_, SD_MODE_1_LINE); + if (ret != ESP_OK) { + ESP_LOGE(SDCARD_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret)); + return ret; + } + + is_sdcard_initialized_ = true; + ESP_LOGI(SDCARD_TAG, "SD card initialized successfully"); + return ESP_OK; +} + +/** + * @brief 统一的硬件初始化接口实现 + * + * 按照依赖关系顺序初始化所有硬件资源: + * 1. I2C总线(最基础,其他设备可能依赖) + * 2. IO扩展板(可能影响其他设备) + * 3. SD卡(文件系统,供显示和音频使用) + * 4. 其他外设 + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ +esp_err_t BoardSweekar::InitializeAllHardware(void) +{ + static const char *HW_INIT_TAG = "HW_INIT"; + esp_err_t ret; + + ESP_LOGI(HW_INIT_TAG, "Starting unified hardware initialization..."); + + // 1. 初始化I2C总线(最基础) + ret = I2CMasterInit(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret)); + return ret; + } + ESP_LOGI(HW_INIT_TAG, "I2C master initialized"); + + // 2. 创建I2C读任务(IO扩展板需要) + io_expansion_.CreateI2cReadTask(); + ESP_LOGI(HW_INIT_TAG, "I2C read task created"); + + // 3. 初始化SD卡(文件系统,供显示和音频使用) + ret = InitializeSdcard(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret)); + // SD卡失败不是致命错误,继续初始化其他硬件 + ESP_LOGW(HW_INIT_TAG, "SD card initialization failed, but continuing with other hardware"); + } else { + ESP_LOGI(HW_INIT_TAG, "SD card initialized"); + } + + // 4. 初始化LCD IO引脚 + LcdIoInit(); + ESP_LOGI(HW_INIT_TAG, "LCD IO pins initialized"); + + // 5. 初始化底座控制 + if (bus_handle_ != nullptr) { + BaseBoardHalI2c *hal_i2c = new BaseBoardHalI2c(bus_handle_); + base_board_control_.Init(hal_i2c); + ESP_LOGI(HW_INIT_TAG, "Base board control initialized with I2C handle"); + } else { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize base board control: I2C bus is null"); + } + + // 6. 可选外设(根据具体应用需求) + // BaseBoardControlUartInit(); // 底座控制串口(demo5需要) + // ESP_LOGI(HW_INIT_TAG, "Base board control UART initialized"); + + // MillimeterWaveRadarUartInit(); + // MillimeterWaveRadarGpioInit(); + StepperMotorInit(); + + + + ESP_LOGI(HW_INIT_TAG, "Unified hardware initialization completed successfully"); + return ESP_OK; +} + +/** + * @brief 进入低功耗模式 + * + * 根据指定的功耗模式,执行相应的功耗优化策略: + * - IDLE模式:关闭非必要外设,保持快速响应 + * - LIGHT_SLEEP模式:进入轻度睡眠,CPU暂停,外设断电 + * - DEEP_SLEEP模式:深度睡眠,仅RTC运行,功耗最低 + */ +esp_err_t BoardSweekar::EnterLowPowerMode(power_mode_t mode) { + static const char *POWER_TAG = "POWER_MGMT"; + esp_err_t ret = ESP_OK; + + ESP_LOGI(POWER_TAG, "Entering power mode: %d", mode); + + if (mode == current_power_mode_) { + ESP_LOGW(POWER_TAG, "Already in power mode %d", mode); + return ESP_OK; + } + + // 保存当前模式,以便恢复 + power_mode_t previous_mode = current_power_mode_; + + switch (mode) { + case POWER_MODE_NORMAL: + // 正常模式,不需要特殊处理 + break; + + case POWER_MODE_IDLE: + // 空闲模式:关闭非必要外设 + ESP_LOGI(POWER_TAG, "Idle mode: disabling non-essential peripherals"); + + // 关闭SD卡(如果正在使用,需要先卸载) + if (is_sdcard_initialized_) { + // 注意:这里只是示例,实际应用中需要确保没有文件操作 + ESP_LOGW(POWER_TAG, "SD card still active in idle mode"); + } + + // 关闭显示背光 + // 关闭非必要GPIO的上拉/下拉 + // 降低I2C时钟频率 + break; + + case POWER_MODE_LIGHT_SLEEP: + // 轻度睡眠 + ESP_LOGI(POWER_TAG, "Light sleep mode: preparing for sleep"); + + // 设置唤醒源(需要根据具体需求配置) + // esp_sleep_enable_timer_wakeup(1000000); // 1秒后唤醒 + // esp_sleep_enable_ext0_wakeup(GPIO_NUM_XX, 0); // 外部中断唤醒 + + // 进入轻度睡眠 + // ret = esp_light_sleep_start(); + if (ret != ESP_OK) { + ESP_LOGE(POWER_TAG, "Failed to enter light sleep: %s", esp_err_to_name(ret)); + current_power_mode_ = previous_mode; + return ret; + } + break; + + case POWER_MODE_DEEP_SLEEP: + // 深度睡眠 + ESP_LOGI(POWER_TAG, "Deep sleep mode: system will restart after wake-up"); + + // 保存必要的RTC数据 + // rtc_gpio_isolate(GPIO_NUM_XX); // 隔离GPIO + + // 设置深度睡眠唤醒源 + // esp_sleep_enable_timer_wakeup(60000000); // 60秒后唤醒 + + // 进入深度睡眠 + // esp_deep_sleep_start(); + // 注意:深度睡眠后系统会重启,不会返回 + break; + + default: + ESP_LOGE(POWER_TAG, "Invalid power mode: %d", mode); + return ESP_ERR_INVALID_ARG; + } + + current_power_mode_ = mode; + ESP_LOGI(POWER_TAG, "Successfully entered power mode: %d", mode); + return ret; +} + +/** + * @brief 退出低功耗模式 + * + * 从低功耗模式恢复到正常运行模式,重新初始化必要的硬件资源。 + */ +esp_err_t BoardSweekar::ExitLowPowerMode(void) { + static const char *POWER_TAG = "POWER_MGMT"; + + ESP_LOGI(POWER_TAG, "Exiting low power mode"); + + if (current_power_mode_ == POWER_MODE_NORMAL) { + ESP_LOGW(POWER_TAG, "Already in normal mode"); + return ESP_OK; + } + + // 根据之前的功耗模式执行相应的恢复操作 + switch (current_power_mode_) { + case POWER_MODE_IDLE: + // 恢复空闲模式 + ESP_LOGI(POWER_TAG, "Restoring from idle mode"); + + // 重新初始化必要的外设 + // 恢复I2C时钟频率 + // 重新开启显示背光 + break; + + case POWER_MODE_LIGHT_SLEEP: + // 轻度睡眠唤醒后会自动继续执行 + ESP_LOGI(POWER_TAG, "Woken up from light sleep"); + + // 重新配置时钟(如果需要) + // 重新初始化外设 + break; + + case POWER_MODE_DEEP_SLEEP: + // 深度睡眠后系统会重启,不会执行到这里 + ESP_LOGW(POWER_TAG, "Deep sleep recovery should not reach here"); + break; + + default: + break; + } + + // 恢复到正常模式 + current_power_mode_ = POWER_MODE_NORMAL; + ESP_LOGI(POWER_TAG, "Successfully exited low power mode"); + + return ESP_OK; +} + +/** + * @brief 设置硬件模块电源状态 + * + * 提供精细化的电源管理,可以单独控制各个硬件模块的电源状态。 + */ +esp_err_t BoardSweekar::SetModulePower(hardware_module_t module, bool enable) { + static const char *POWER_TAG = "POWER_MODULE"; + esp_err_t ret = ESP_OK; + + ESP_LOGI(POWER_TAG, "%s module %d", enable ? "Enabling" : "Disabling", module); + + // 更新电源状态位图 + if (enable) { + power_state_flags_ |= (1 << module); + } else { + power_state_flags_ &= ~(1 << module); + } + + switch (module) { + case HW_MODULE_I2C: + if (!enable && bus_handle_) { + // 注意:I2C总线通常不建议完全关闭,可能影响多个设备 + ESP_LOGW(POWER_TAG, "I2C bus power control not recommended"); + } + break; + + case HW_MODULE_SDCARD: + if (enable && !is_sdcard_initialized_) { + ret = InitializeSdcard(); + } else if (!enable && is_sdcard_initialized_) { + // 卸载SD卡文件系统 + // 注意:需要确保没有打开的文件 + ESP_LOGW(POWER_TAG, "SD card power down requires file system cleanup"); + } + break; + + case HW_MODULE_LCD: + // LCD背光控制 + // LCD电源引脚控制(如果有) + break; + + case HW_MODULE_AUDIO: + // 音频编解码器电源控制 + // 需要与AudioPlayer协调 + break; + + case HW_MODULE_MOTOR: + // 步进电机驱动器电源控制 + // 电机睡眠模式 + break; + + case HW_MODULE_GYROSCOPE: + // 陀螺仪电源控制 + // 设置陀螺仪为低功耗模式 + break; + + case HW_MODULE_TOUCH: + // 触摸传感器电源控制 + // 设置触摸传感器为睡眠模式 + break; + + case HW_MODULE_RADAR: + // 毫米波雷达电源控制 + // 设置雷达为低功耗模式 + break; + + case HW_MODULE_IO_EXPAND: + // IO扩展板电源控制 + // 设置扩展板为低功耗模式 + break; + + default: + ESP_LOGE(POWER_TAG, "Unknown hardware module: %d", module); + return ESP_ERR_INVALID_ARG; + } + + if (ret == ESP_OK) { + ESP_LOGI(POWER_TAG, "Module %d power %s successfully", module, enable ? "enabled" : "disabled"); + } else { + ESP_LOGE(POWER_TAG, "Failed to %s module %d: %s", enable ? "enable" : "disable", module, esp_err_to_name(ret)); + } + + return ret; +} + + + diff --git a/main/02_physical/boards/board_v1_1_17/board_sweekar.h b/main/02_physical/boards/board_v1_1_17/board_sweekar.h new file mode 100644 index 0000000..55665ac --- /dev/null +++ b/main/02_physical/boards/board_v1_1_17/board_sweekar.h @@ -0,0 +1,181 @@ +#ifndef __BOARD_H__ +#define __BOARD_H__ +#include "config.h" +#include "io_expansion_board.h" +#include "stepper_motor.h" +#include "stepper_driver.h" +#include "i2c_bus.h" +#include "gyroscope.h" +#include "touch_sensor.h" +#include "base_board_control.h" +#include "esp_peripherals.h" +#include "periph_sdcard.h" +#include "esp_sleep.h" +#include "driver/rtc_io.h" + +/** + * @brief 功耗模式枚举 + */ +typedef enum { + POWER_MODE_NORMAL, // 正常运行模式,所有硬件可用 + POWER_MODE_IDLE, // 空闲模式,关闭非必要外设 + POWER_MODE_LIGHT_SLEEP, // 轻度睡眠,快速唤醒 + POWER_MODE_DEEP_SLEEP, // 深度睡眠,仅RTC运行 +} power_mode_t; + +/** + * @brief 硬件模块枚举,用于精细化电源管理 + */ +typedef enum { + HW_MODULE_I2C, // I2C总线 + HW_MODULE_SDCARD, // SD卡 + HW_MODULE_LCD, // LCD显示 + HW_MODULE_AUDIO, // 音频编解码器 + HW_MODULE_MOTOR, // 步进电机 + HW_MODULE_GYROSCOPE, // 陀螺仪 + HW_MODULE_TOUCH, // 触摸传感器 + HW_MODULE_RADAR, // 毫米波雷达 + HW_MODULE_IO_EXPAND, // IO扩展板 +} hardware_module_t; + +/** + * @brief 硬件板级管理器 + * + * 采用高内聚低耦合设计原则,统一管理所有硬件资源。 + * 提供统一的硬件初始化接口和资源访问,避免各模块重复初始化。 + */ +class BoardSweekar +{ +private: + i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄 + esp_periph_set_handle_t periph_set_ = nullptr; // 外设管理句柄 + bool is_sdcard_initialized_ = false; // SD卡初始化状态 + power_mode_t current_power_mode_ = POWER_MODE_NORMAL; // 当前功耗模式 + uint32_t power_state_flags_ = 0xFFFFFFFF; // 各模块电源状态位图(1为开启) + +public: + BoardSweekar(); + ~BoardSweekar(); + + static BoardSweekar* GetInstance(); + + // --- 语义化的高层 API:音频与功放控制 --- + // 开启或关闭外放功放 (PA),供上层 AudioActor/AudioPlayer 调用,屏蔽底层引脚实现 + void SetAudioAmplifier(bool enable); + + IOExpansionBoard io_expansion_; // IO扩展板对象 + Gyroscope gyroscope_; // 陀螺仪对象 + TouchSensor touch_sensor_; // 触摸传感器对象 + BaseBoardControl base_board_control_; // 底座控制对象 + StepperDriver* stepper_driver_ = nullptr; // 步进电机驱动对象 + + StepperDriver* GetStepperDriver() const { return stepper_driver_; } + + // 初始化步进电机 + void StepperMotorInit(void); + + // 初始化LCD IO引脚(消除与步进电机的耦合) + void LcdIoInit(void); + + // 初始化串口 + void MillimeterWaveRadarUartInit(void); + + //初始化毫米波雷达的中断引脚 + void MillimeterWaveRadarGpioInit(void); + + /** + * @brief 执行系统关机 + * 内部拉高/拉低 SHUTDOWN_CTRL_PIN 引脚切断电源 + */ + void SystemShutdown(void); + + // 初始化I2C总线 + esp_err_t I2CMasterInit(void); + + // 初始化VBAT toVBAT_5V引脚 + void VbatToVbat5vInit(void); + + // 初始化底座控制串口 + void BaseBoardControlInit(void); + + // 初始化SD卡(推荐使用统一的硬件初始化) + esp_err_t InitializeSdcard(void); + + // 获取SD卡初始化状态 + bool IsSdcardInitialized() const { return is_sdcard_initialized_; } + + // 获取外设管理句柄(供需要访问SD卡的模块使用) + esp_periph_set_handle_t GetPeriphSet() const { return periph_set_; } + + // 获取I2C总线句柄 + i2c_bus_handle_t GetBusHandle() const { return bus_handle_; } + + /** + * @brief 统一的硬件初始化接口 + * + * 按照依赖关系顺序初始化所有硬件资源,确保各模块可以安全使用。 + * 推荐在主程序启动时调用此函数,而不是分别调用各个初始化函数。 + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ + esp_err_t InitializeAllHardware(void); + + /** + * @brief 完整的统一硬件初始化接口(专为复杂应用优化) + * + * 包含所有必要外设的完整初始化,适用于demo5等复杂应用场景。 + * 这个函数会初始化:I2C总线、IO扩展板、SD卡、LCD IO、底座控制等。 + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ + esp_err_t InitializeAllHardwareComplete(void); + + /** + * @brief 针对特定应用的硬件初始化配置 + * + * 为不同类型的应用提供专门的初始化配置,优化启动流程。 + * + * @param app_type 应用类型(demo5、音频播放器、显示应用等) + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ + esp_err_t InitializeHardwareForApplication(int app_type); + + /** + * @brief 功耗管理接口 - 进入低功耗模式 + * + * 根据指定的功耗模式,关闭非必要硬件、设置GPIO为低功耗状态、 + * 调整时钟频率等。支持多种功耗模式以适应不同应用场景。 + * + * @param mode 功耗模式 + * @return esp_err_t 操作结果 + */ + esp_err_t EnterLowPowerMode(power_mode_t mode); + + /** + * @brief 功耗管理接口 - 退出低功耗模式 + * + * 从低功耗模式恢复,重新初始化必要的硬件资源。 + * + * @return esp_err_t 操作结果 + */ + esp_err_t ExitLowPowerMode(void); + + /** + * @brief 获取当前功耗模式 + * + * @return power_mode_t 当前功耗模式 + */ + power_mode_t GetPowerMode(void) const { return current_power_mode_; } + + /** + * @brief 设置硬件模块电源状态 + * + * 单独控制某个硬件模块的电源状态,用于精细化的功耗管理。 + * + * @param module 硬件模块 + * @param enable true为开启,false为关闭 + * @return esp_err_t 操作结果 + */ + esp_err_t SetModulePower(hardware_module_t module, bool enable); +}; +#endif diff --git a/main/02_physical/boards/board_v1_1_17/board_sweekar_complete_init.cc b/main/02_physical/boards/board_v1_1_17/board_sweekar_complete_init.cc new file mode 100644 index 0000000..37a454a --- /dev/null +++ b/main/02_physical/boards/board_v1_1_17/board_sweekar_complete_init.cc @@ -0,0 +1,186 @@ +/** + * @file board_sweekar_complete_init.cc + * @brief 完整的统一硬件初始化实现 + * + * 这个文件提供了完整的统一硬件初始化函数,包含所有必要的硬件初始化步骤。 + * 专为demo5等复杂应用场景设计。 + */ + +/** + * @brief 完整的统一硬件初始化接口(专为demo5优化) + * + * 按照依赖关系顺序初始化所有硬件资源: + * 1. I2C总线(最基础,其他设备依赖) + * 2. IO扩展板(控制其他外设) + * 3. SD卡(文件系统,供显示和音频使用) + * 4. LCD IO引脚(显示相关) + * 5. 底座控制串口(通信) + * 6. 底座控制模块(业务逻辑) + * 7. 其他外设(根据应用需求) + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ +esp_err_t BoardSweekar::InitializeAllHardwareComplete(void) +{ + static const char *HW_INIT_TAG = "HW_INIT_COMPLETE"; + esp_err_t ret; + + ESP_LOGI(HW_INIT_TAG, "Starting complete hardware initialization..."); + + // 1. 初始化I2C总线(最基础,其他设备依赖) + ret = I2CMasterInit(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret)); + return ret; + } + ESP_LOGI(HW_INIT_TAG, "✓ I2C master initialized"); + + // 2. 创建I2C读任务(IO扩展板需要) + io_expansion_.CreateI2cReadTask(); + ESP_LOGI(HW_INIT_TAG, "✓ I2C read task created"); + + // 3. 初始化SD卡(文件系统,供显示和音频使用) + ret = InitializeSdcard(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret)); + // SD卡失败不是致命错误,继续初始化其他硬件 + ESP_LOGW(HW_INIT_TAG, "⚠ SD card initialization failed, but continuing with other hardware"); + } else { + ESP_LOGI(HW_INIT_TAG, "✓ SD card initialized"); + } + + // 4. 初始化LCD IO引脚(显示相关) + LcdIoInit(); + ESP_LOGI(HW_INIT_TAG, "✓ LCD IO pins initialized"); + + // 5. 初始化底座控制串口(demo5需要) + BaseBoardControlUartInit(); + ESP_LOGI(HW_INIT_TAG, "✓ Base board control UART initialized"); + + // 6. 初始化底座控制模块 + base_board_control_.Init(); + ESP_LOGI(HW_INIT_TAG, "✓ Base board control initialized"); + + // 7. 设置IO扩展板的PA控制模式(demo5需要) + io_expansion_.SetPaCtrlMode(true); + ESP_LOGI(HW_INIT_TAG, "✓ IO expansion PA control mode set"); + + // 8. 可选外设(根据具体应用需求启用) + // ESP_LOGI(HW_INIT_TAG, "Initializing optional peripherals..."); + // + // // 毫米波雷达(如需要) + // MillimeterWaveRadarUartInit(); + // MillimeterWaveRadarGpioInit(); + // ESP_LOGI(HW_INIT_TAG, "✓ Millimeter wave radar initialized"); + // + // // VBAT升压(如需要) + // VbatToVbat5vInit(); + // ESP_LOGI(HW_INIT_TAG, "✓ VBAT to 5V booster initialized"); + // + // // 步进电机(如需要) + // StepperMotorInit(); + // ESP_LOGI(HW_INIT_TAG, "✓ Stepper motor initialized"); + + ESP_LOGI(HW_INIT_TAG, "=== Complete hardware initialization finished successfully ==="); + return ESP_OK; +} + +/** + * @brief 针对特定应用的硬件初始化配置 + * + * 为不同类型的应用提供专门的初始化配置 + */ +esp_err_t BoardSweekar::InitializeHardwareForApplication(application_type_t app_type) { + static const char *APP_INIT_TAG = "APP_HW_INIT"; + + ESP_LOGI(APP_INIT_TAG, "Initializing hardware for application type: %d", app_type); + + // 基础硬件初始化(所有应用都需要) + esp_err_t ret = InitializeAllHardwareComplete(); + if (ret != ESP_OK) { + ESP_LOGE(APP_INIT_TAG, "Basic hardware initialization failed"); + return ret; + } + + switch (app_type) { + case APP_TYPE_DEMO5: // 宠物游戏demo + ESP_LOGI(APP_INIT_TAG, "Configuring for Demo5 (Pet Game)..."); + + // Demo5需要的额外初始化 + // 触摸传感器、陀螺仪、RGB LED等会在应用层初始化 + + ESP_LOGI(APP_INIT_TAG, "✓ Demo5 hardware configuration complete"); + break; + + case APP_TYPE_AUDIO_PLAYER: // 音频播放器 + ESP_LOGI(APP_INIT_TAG, "Configuring for Audio Player..."); + + // 音频应用需要确保音频编解码器正确初始化 + // 这部分通常在AudioPlayer类中处理 + + ESP_LOGI(APP_INIT_TAG, "✓ Audio player hardware configuration complete"); + break; + + case APP_TYPE_DISPLAY_ONLY: // 纯显示应用 + ESP_LOGI(APP_INIT_TAG, "Configuring for Display Only..."); + + // 显示应用需要确保LCD相关硬件正确配置 + // 这部分通常在Display类中处理 + + ESP_LOGI(APP_INIT_TAG, "✓ Display-only hardware configuration complete"); + break; + + case APP_TYPE_MINIMAL: // 最小化应用 + ESP_LOGI(APP_INIT_TAG, "Configuring for Minimal Application..."); + + // 最小化配置,只保留最基本的功能 + // 关闭非必要外设以节省功耗 + + ESP_LOGI(APP_INIT_TAG, "✓ Minimal hardware configuration complete"); + break; + + default: + ESP_LOGW(APP_INIT_TAG, "Unknown application type, using default configuration"); + break; + } + + return ESP_OK; +} + +/** + * @brief 硬件初始化状态报告 + * + * 提供详细的硬件初始化状态报告,便于调试和问题排查 + */ +void BoardSweekar::ReportHardwareStatus(void) { + static const char *STATUS_TAG = "HW_STATUS"; + + ESP_LOGI(STATUS_TAG, "=== Hardware Initialization Status Report ==="); + + // I2C总线状态 + ESP_LOGI(STATUS_TAG, "I2C Bus: %s", (bus_handle_ != nullptr) ? "✓ Initialized" : "✗ Not initialized"); + + // SD卡状态 + ESP_LOGI(STATUS_TAG, "SD Card: %s", (is_sdcard_initialized_) ? "✓ Initialized" : "✗ Not initialized"); + if (is_sdcard_initialized_) { + ESP_LOGI(STATUS_TAG, " Peripheral Set: %s", (periph_set_ != nullptr) ? "✓ Available" : "✗ Not available"); + } + + // IO扩展板状态 + ESP_LOGI(STATUS_TAG, "IO Expansion Board: %s", (io_expansion_.bus_handle_ != nullptr) ? "✓ Configured" : "✗ Not configured"); + + // 底座控制状态 + ESP_LOGI(STATUS_TAG, "Base Board Control: %s", (base_board_control_.GetUartPort() != 0) ? "✓ Initialized" : "✗ Not initialized"); + + // 功耗管理状态 + ESP_LOGI(STATUS_TAG, "Power Management: %s", (current_power_mode_ == POWER_MODE_NORMAL) ? "✓ Normal mode" : "⚠ Low power mode"); + ESP_LOGI(STATUS_TAG, " Current Mode: %d", current_power_mode_); + ESP_LOGI(STATUS_TAG, " Module Power States: 0x%08X", power_state_flags_); + + // 内存状态 + ESP_LOGI(STATUS_TAG, "Memory Status:"); + ESP_LOGI(STATUS_TAG, " Internal RAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + ESP_LOGI(STATUS_TAG, " PSRAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + + ESP_LOGI(STATUS_TAG, "=== End of Hardware Status Report ==="); +} \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_17/config.h b/main/02_physical/boards/board_v1_1_17/config.h new file mode 100644 index 0000000..7af2bd4 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_17/config.h @@ -0,0 +1,136 @@ +/* 定义引脚分配 */ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +/** + * @file config.h + * @brief 定义了引脚的分配。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +#include "driver/gpio.h" +#include "driver/i2c_master.h" +#include "driver/i2s.h" +#include "esp_log.h" +#include "esp_rom_sys.h" // 用于 esp_rom_delay_us +#include "esp_timer.h" +#include "esp_mac.h" +#include "driver/ledc.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "driver/gptimer.h" +#include "esp_intr_alloc.h" +#include "driver/uart.h" +#include "esp_err.h" +#include "freertos/queue.h" +#include "soc/uart_reg.h" +#include "linear_motor.h" +#include "gyroscope.h" + +#define TAG_BOARD "SWEEKAR_ESP32" +/*I2C总线引脚定义*/ +#define I2C0_MASTER_PORT I2C_NUM_0 +#define I2C0_MASTER_SDA_IO GPIO_NUM_2 +#define I2C0_MASTER_SCL_IO GPIO_NUM_3 + +/* 步进电机配置 */ +#define STEPPER_STEP_IO GPIO_NUM_42 // 步进电机脉冲输入引脚 +#define STEPPER_TIMER_RES_HZ 1000000 // 步进电机定时器分辨率 1 MHz(1 us 步进) + +/* 定义屏幕驱动控制引脚 */ +#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚 +#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL +#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚 +#define ST7789_PIN_CS GPIO_NUM_46 // SPI片选引脚 +#define ST7789_PIN_BL GPIO_NUM_45 // 背光引脚 +#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚 +#define LCD_BL_ACTIVE_LEVEL 0 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS) + +#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数) +#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数) + +/* 毫米波雷达配置参数 */ +/* 定义毫米波雷达的中断引脚 */ +#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35 +// UART 配置参数 +#define RADAR_UART_NUM UART_NUM_1 // 使用 UART1 +#define UART_TX_PIN GPIO_NUM_40 // GPIO40 作为 TX(根据实际硬件连接调整) +#define UART_RX_PIN GPIO_NUM_39 // GPIO39 作为 RX +#define RADAR_BAUD_RATE 9600 // 雷达波特率 +#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小 + +/* IO扩展硬件配置常量 */ +#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000) +#define I2C_IO_EXPAND_SLAVE_ADDR 0x58 // AW9523BTQR器件地址,v1_1_13的addr1和addr0是0 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚 +#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值 +#define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚 + +/* 定义线性马达的I2C从机配置常量 */ +#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址 + +/* 定义陀螺仪的I2C从机配置常量 */ +#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址 +#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚 + +/* AW触摸芯片配置 */ +#define AW_TOUCH_IRQ_PIN GPIO_NUM_11 // AW触摸芯片中断引脚 +#define NFC_RST_PIN GPIO_NUM_12 // NFC复位引脚 +#define SHUTDOWN_CTRL_PIN GPIO_NUM_13 // 关机控制引脚 + +/* 原生触摸引脚配置 (v1.1.17已改为上述功能,保留定义需谨慎) */ +// 触摸按键数量配置 +#define TOUCH_BUTTON_NUM 3 +// 触摸通道定义 - 注意:v1.1.17如果不使用ESP32原生触摸,这些定义可能不再适用 +// 但为了兼容编译,可以保留或注释 +#define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11 (Now AW_IRQ) +#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12 (Now NFC_RST) +#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13 (Now SHUTDOWN) + +/* ES8311音频编解码器配置 (ESP-ADF兼容) */ +#define AUDIO_INPUT_SAMPLE_RATE 24000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 +#define AUDIO_INPUT_REFERENCE true + +/* I2S GPIO定义 */ +#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15 +#define AUDIO_I2S_GPIO_WS GPIO_NUM_4 +#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5 +#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6 +#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7 + +/* PA引脚定义 */ +#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC + +/* I2C配置 */ +#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2 +#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3 +#define AUDIO_CODEC_ES8311_ADDR 0x18 +#define AUDIO_CODEC_ES7210_ADDR 0x40 + +/* WS2812 RGB LED配置 */ +#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚 +#define WS2812_NUM_LEDS 2 // WS2812 LED数量 + +/* 创建VBAT to VBAT_5V */ +#define VBAT_5V_PIN GPIO_NUM_NC // VBAT_5V引脚 + +/* 定义按键的中断引脚 */ +#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚 +#define RIGHT_BUTTON_PIN GPIO_NUM_8 // 按键中断引脚 + +/* 底座控制命令串口配置 */ +#define BASE_BOARD_CTL_UART_PORT UART_NUM_0 +#define BASE_BOARD_CTL_UART_TX_PIN GPIO_NUM_43 +#define BASE_BOARD_CTL_UART_RX_PIN GPIO_NUM_44 +#define BASE_BOARD_CTL_UART_BAUDRATE 115200 +#define BASE_BOARD_CTL_UART_BUF_SIZE 256 + +/* 背光控制引脚配置 */ +#define BL_PIN GPIO_NUM_45 + +#endif // _BOARD_CONFIG_H_ diff --git a/main/02_physical/boards/board_v1_1_17/io_expansion_board.cc b/main/02_physical/boards/board_v1_1_17/io_expansion_board.cc new file mode 100644 index 0000000..bfe1679 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_17/io_expansion_board.cc @@ -0,0 +1,1040 @@ +#include "io_expansion_board.h" +#include "millimeter_wave_radar.h" +#include "photo_interrupter.h" +#include "adc_battery_monitor.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_check.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/idf_additions.h" +#include "freertos/portable.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_rom_sys.h" +/** + * @file io_expansion_board.cc + * @brief IO扩展板功能实现类,包含I2C通信、GPIO中断配置、外设控制等功能 + * @details 实现了IO扩展板的初始化(中断引脚、复位引脚)、寄存器读写、步进电机控制(细分模式、使能、方向、睡眠状态)、 + * LCD相关引脚控制(背光、复位、片选)、毫米波雷达中断引脚配置等功能,并提供I2C数据读取任务的创建与管理 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +/** + * @brief 构造函数 + */ +IOExpansionBoard::IOExpansionBoard() + : bus_handle_(nullptr), + device_addr_(0), + last_port0_state_(0), + last_port1_state_(0), + radar_last_state_(false), + i2c_task_event_group_(nullptr), + xI2CReadTaskHandle_(nullptr), + is_initialized_(false), + interrupt_gpio_(GPIO_NUM_NC), + reset_gpio_(GPIO_NUM_NC) +{ +} + +/** + * @brief 析构函数 + */ +IOExpansionBoard::~IOExpansionBoard() +{ + // 删除任务 + if (xI2CReadTaskHandle_) { + vTaskDelete(xI2CReadTaskHandle_); + } + + // if(pI2CReadTaskStackBuffer) { + // heap_caps_free(pI2CReadTaskStackBuffer); + // pI2CReadTaskStackBuffer = nullptr; + // } + + // if(pxI2CReadTaskBuffer) { + // vPortFree(pxI2CReadTaskBuffer); + // pxI2CReadTaskBuffer = nullptr; + // } + + // 删除事件组 + if (i2c_task_event_group_) { + vEventGroupDelete(i2c_task_event_group_); + } + + // 移除中断处理 + if (interrupt_gpio_ != GPIO_NUM_NC) { + gpio_isr_handler_remove(interrupt_gpio_); + } + + // 删除IO扩展板设备 + // 使用i2c_bus API时不需要手动删除设备句柄 + // bus_handle_由board_sweekar统一管理 +} + +/** + * @brief 静态中断处理函数 + */ +void IRAM_ATTR IOExpansionBoard::GpioIsrHandler(void* arg) +{ + IOExpansionBoard* instance = static_cast(arg); + if (!instance) return; + + // 调试:记录中断触发 + // ESP_EARLY_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "中断触发!"); // IRAM函数中不能使用普通日志 + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // 设置事件标志位 + if (instance->i2c_task_event_group_) { + xEventGroupSetBitsFromISR( + instance->i2c_task_event_group_, + BIT0, + &xHigherPriorityTaskWoken + ); + } + + // 触发上下文切换 + if (xHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); + } +} + +/** + * @brief 初始化GPIO中断检测 + */ +esp_err_t IOExpansionBoard::InterruptGpioInit(gpio_num_t gpio_num) +{ + // 配置IO扩展板中断引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_ANYEDGE; // 改为双沿触发,检测上升沿和下降沿 + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + // io_conf.pull_up_en = GPIO_PULLUP_DISABLE; + // io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE; + + + esp_err_t err = gpio_config(&io_conf); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + // 配置中断服务 + err = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3); + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断服务安装失败,错误码: 0x%x", err); + return err; + } + // 注册中断处理函数 + err = gpio_isr_handler_add(gpio_num, GpioIsrHandler, this); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断处理函数添加失败,错误码: 0x%x", err); + return err; + } + // 创建事件组 + i2c_task_event_group_ = xEventGroupCreate(); + if (!i2c_task_event_group_) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "事件组创建失败"); + return ESP_FAIL; + } + + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d中断初始化完成", gpio_num); + return ESP_OK; +} + +/** + * @brief 初始化硬件复位引脚 + * 设置为上拉,需要复位,需要输出低电平为20us的脉冲信号 + */ +esp_err_t IOExpansionBoard::ResetGpioInit(gpio_num_t gpio_num) +{ + reset_gpio_ = gpio_num; + + // 配置复位引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + esp_err_t err = gpio_config(&io_conf); + gpio_set_level(gpio_num, 1); // 复位引脚拉高 + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d复位引脚初始化完成", gpio_num); + return err; + } +} + +/** + * @brief 计算Port0的字节值,用于配置输入还是输出模式(0为输出模式,1为输入模式) + * @return uint8_t 操作结果 + */ +uint8_t IOExpansionBoard::ByteCalculatePort0() +{ + uint8_t byte_val = 0x00; // 初始化为所有引脚为输出模式(0),然后根据配置设置为输入模式(1) + + // 输入模式配置:将对应位置位(1为输入模式) + if(RADAR_INTERRUPT_CONFIG == CONFIG_PORT0){ //雷达中断引脚 + byte_val |= (1 << RADAR_INTERRUPT_PIN); + } + if(START_PHOTO_INTERRUPTER_CONFIG == CONFIG_PORT0){ //起始光学传感器 + byte_val |= (1 << START_PHOTO_INTERRUPTER_PIN); + } + if(END_PHOTO_INTERRUPTER_PORT_CONFIG == CONFIG_PORT0){ //结束光学传感器 + byte_val |= (1 << END_PHOTO_INTERRUPTER_PIN); + } + if(BATTERY_FULL_CONFIG == CONFIG_PORT0){ //电池充满检测 + byte_val |= (1 << BATTERY_FULL_PIN); + } + if(BATTERY_CHRG_CONFIG == CONFIG_PORT0){ //电池充电检测 + byte_val |= (1 << BATTERY_CHRG_PIN); + } + + return byte_val; +} + +/** + * @brief 计算Port1的字节值,用于配置输入还是输出模式(0为输出模式,1为输入模式) + * @return uint8_t 操作结果 + */ +uint8_t IOExpansionBoard::ByteCalculatePort1() +{ + uint8_t byte_val = 0x00; // 初始化为所有引脚为输出模式(0),然后根据配置设置为输入模式(1) + + // 输入模式配置:将对应位置位(1为输入模式) + if(RADAR_INTERRUPT_CONFIG == CONFIG_PORT1){ //雷达中断引脚 + byte_val |= (1 << RADAR_INTERRUPT_PIN); + } + if(START_PHOTO_INTERRUPTER_CONFIG == CONFIG_PORT1){ //起始光学传感器 + byte_val |= (1 << START_PHOTO_INTERRUPTER_PIN); + } + if(END_PHOTO_INTERRUPTER_PORT_CONFIG == CONFIG_PORT1){ //结束光学传感器 + byte_val |= (1 << END_PHOTO_INTERRUPTER_PIN); + } + if(BATTERY_FULL_CONFIG == CONFIG_PORT1){ //电池充满检测 + byte_val |= (1 << BATTERY_FULL_PIN); + } + if(BATTERY_CHRG_CONFIG == CONFIG_PORT1){ //电池充电检测 + byte_val |= (1 << BATTERY_CHRG_PIN); + } + + return byte_val; +} + +/** + * @brief 复位IO扩展板 + */ +esp_err_t IOExpansionBoard::ResetIoExpand() +{ + if (reset_gpio_ == GPIO_NUM_NC) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位引脚未初始化"); + return ESP_ERR_INVALID_STATE; + } + + // 复位IO扩展板 + gpio_set_level(reset_gpio_, 0); + esp_rom_delay_us(30); + gpio_set_level(reset_gpio_, 1); + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "复位成功"); + } + return ESP_OK; +} + +/** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::IoexpandWriteReg(uint8_t reg_addr, uint8_t data) +{ + return i2c_bus_write_bytes(bus_handle_, device_addr_, ®_addr, 1, &data, 1); +} + +/** + * @brief 从寄存器读取数据 + * @param reg_addr 寄存器地址(如INPUT_PORT0、ID等) + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果(ESP_OK为成功) + */ +esp_err_t IOExpansionBoard::IoexpandReadReg(uint8_t reg_addr, uint8_t* data) +{ + if (data == nullptr){ // 检查输入参数有效性 + return ESP_ERR_INVALID_ARG; + } + + // 使用i2c_bus_read_bytes进行寄存器读取 + esp_err_t err = i2c_bus_read_bytes(bus_handle_, device_addr_, ®_addr, 1, data, 1); + if (err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "读取寄存器失败,错误码:0x%x", err); + return err; + } + + return ESP_OK; +} + +/** + * @brief 读取输入端口0寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::ReadInputPort0(uint8_t* data) +{ + return IoexpandReadReg(INPUT_PORT0, data); +} + +/** + * @brief 读取输入端口1寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::ReadInputPort1(uint8_t* data) +{ + return IoexpandReadReg(INPUT_PORT1, data); +} + +//设置IO扩展板为输入模式或是输出模式 +/* +* 这里需要根据实际情况设置IO扩展板的模式,比如输入模式还是输出模式,以及各个引脚的配置。 +* P0_0 对应NFC_RST引脚,需要设置为输出模式,低电平有效。(待测) +* P0_1 对应USB_VBUS引脚,需要设置为输出模式,低电平有效。(待测) +* P0_2 对应BTN_RIGHT_EAR引脚,需要设置为输出模式,低电平有效。(待测) +* P0_3 暂时未使用。 +* P0_4 对应步进电机方向引脚,需要设置为输出模式,根据需求设置。(待测) +* P0_5 对应CHRG引脚(待测) +* P0_6 LCD_DC引脚,需要设置为输出模式,根据需求设置电平。(待测) +* P0_7 对应步进电机的使能引脚,需要设置为输出模式,根据需求设置。(待测) +* +* +* P1_0 对应EG800K_PWR。(待测) +* P1_1 对应LCD_RST,需要设置为输出模式,低电平有效。(待测) +* P1_2 对应LCD_CS,需要设置为输出模式,低电平有效。(待测) +* P1_3 暂时未使用。 +* P1_4 对应步进电机的细分模式M1引脚。(待测) +* P1_5 对应步进电机的细分模式M0引脚。(待测) +* P1_6 对应步进电机的睡眠引脚。(待测) +* P1_7 对应RADAR_O雷达的输出引脚。(待测) +* */ +esp_err_t IOExpansionBoard::IoexpandSetMode(void) +{ + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功"); + } + + err = IoexpandWriteReg(CONFIG_PORT0, ByteCalculatePort0()); + + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + // 打印BytecalculatePort0()结果 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功, 0x%02X", ByteCalculatePort0()); + } + + err = IoexpandWriteReg(CONFIG_PORT1, ByteCalculatePort1()); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口失败,错误码:0x%x", err); + return err; + } + else{ + // 打印BytecalculatePort1()结果 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口成功, 0x%02X", ByteCalculatePort1()); + } + // 配置P0_0-P0_7的初始为高电平 + // 配置P1_0-P1_7的初始为高电平 + // P0_6(旧的LCD_BL, 0x40), P0_1(led_en, PMOS高侧驱动, 高电平关, 0x02) + err = IoexpandWriteReg(OUTPUT_PORT0, 0x42); // 0100 0010 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值成功"); + } + err = IoexpandWriteReg(OUTPUT_PORT1, 0x04); // 0000 0100 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值成功"); + } + + + // AW9523B中断使能配置:0为使能中断,1为禁止中断 + // 使能P0_5(充电检测)和P1_3(充满检测)的中断 + uint8_t int_enable_port0 = 0x00; // 0x00 = 使能所有P0引脚中断 + uint8_t int_enable_port1 = 0x00; // 0x00 = 使能所有P1引脚中断 + + err = IoexpandWriteReg(INT_PORT0, int_enable_port0); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口中断使能失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口中断使能成功: 0x%02X (0=使能)", int_enable_port0); + } + + err = IoexpandWriteReg(INT_PORT1, int_enable_port1); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能成功: 0x%02X (0=使能)", int_enable_port1); + } + + return ESP_OK; +} + +/** + * @brief 设置步进电机的细分模式 + */ +void IOExpansionBoard::SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin) +{ + uint8_t current_val; + switch (mode) { + case 1: //全步输出模式 低低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 2: //非圆 1/2 高低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val |= (1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 3: //1/4 步 低高电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val |= (1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 4: //1/8 步 高高电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val |= (1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val |= (1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + default: //全步输入模式 低低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + } +} + +/** + * @brief 设置步进电机的使能 + */ +esp_err_t IOExpansionBoard::SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin) +{ + uint8_t current_val; + if(enable){ + // 进入工作状态mode + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << enable_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << enable_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} +/** + * @brief 设置步进电机运行方向 + */ +esp_err_t IOExpansionBoard::StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin) +{ + uint8_t current_val; + if(dir){ + // 方向为正转 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/** + * @brief 设置步进电机是否进入睡眠或者工作状态(高电平进入工作状态,低电平进入睡眠状态) + */ +esp_err_t IOExpansionBoard::SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin) +{ + uint8_t current_val; + if(mode){ + // 进入工作状态mode + // ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入工作状态"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "电机睡眠输出寄存器: 0x%x", current_val); + current_val |= (1 << nsleep_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置电机睡眠输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + // ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入睡眠状态"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "电机睡眠输出寄存器: 0x%x", current_val); + current_val &= ~(1 << nsleep_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置电机睡眠输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/*********************************************IO扩展板LCD引脚配置参数***********************************************/ +/** + * @brief 设置 LCD_BL引脚电平(高电平为命令模式,低电平为数据模式) + */ +esp_err_t IOExpansionBoard::SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin) +{ + uint8_t current_val; + if(mode){ + // 进入命令模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << bl_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入数据模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << bl_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/** + * @brief 设置 LED_EN 引脚电平(用于控制LCD背光/LED灯电源) + * @param mode true:开启(低电平), false:关闭(高电平) + */ +esp_err_t IOExpansionBoard::SetLedEnMode(bool mode) +{ + uint8_t current_val; + esp_err_t err = IoexpandReadReg(LED_EN_PORT, ¤t_val); + if (err != ESP_OK) return err; + + if(mode){ + // 开启 (PMOS低电平有效) + current_val &= ~(1 << LED_EN_PIN); + } + else{ + // 关闭 (PMOS高电平无效) + current_val |= (1 << LED_EN_PIN); + } + return IoexpandWriteReg(LED_EN_PORT, current_val); +} + +/** + * @brief 设置 LCD_RST引脚电平(高电平为复位模式,低电平为工作模式) + */ +esp_err_t IOExpansionBoard::SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t reset_pin) +{ + uint8_t current_val; + if(mode){ + // 进入复位模式 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入复位模式"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "LCD复位输出寄存器: 0x%x", current_val); + current_val |= (1 << reset_pin); + //打印设置后的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置LCD复位输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入工作模式 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入工作模式"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "LCD复位输出寄存器: 0x%x", current_val); + current_val &= ~(1 << reset_pin); + //打印设置后的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置LCD复位输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/*********************************************IO扩展板的输入引脚配置以及中断引脚定义***********************************************/ +/** + * @brief 设置 毫米波雷达的中断引脚 + */ +esp_err_t IOExpansionBoard::SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin) +{ + uint8_t current_val; + if(mode){ + // 进入输入模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + current_val |= (1 << interrupt_pin); + return IoexpandWriteReg(INPUT_PORT, current_val); + } + else{ + // 进入输出模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + current_val &= ~(1 << interrupt_pin); + return IoexpandWriteReg(INPUT_PORT, current_val); + } +} + +/** + * @brief 设置 PA_CTRL引脚电平 + */ +esp_err_t IOExpansionBoard::SetPaCtrlMode(bool mode) +{ + uint8_t current_val; + if(mode){ + // 进入高电平状态 + ESP_LOGI("io_ex:", "read reg"); + IoexpandReadReg(PA_CTRL_PORT, ¤t_val); + current_val |= (1 << PA_CTRL_PIN); + return IoexpandWriteReg(PA_CTRL_PORT, current_val); + } + else{ + // 进入低电平状态 + IoexpandReadReg(PA_CTRL_PORT, ¤t_val); + current_val &= ~(1 << PA_CTRL_PIN); + return IoexpandWriteReg(PA_CTRL_PORT, current_val); + } +} + + + +/** + * @brief I2C数据读取任务主体 + */ +void IOExpansionBoard::I2cReadTask(void* pvParameters) +{ + IOExpansionBoard* instance = static_cast(pvParameters); + if (!instance) { + vTaskDelete(nullptr); + return; + } + // 初始化复位引脚 + esp_err_t err = instance->ResetGpioInit(IO_EXPAND_RSTN); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO复位初始化失败"); + } + + // 执行硬件复位 - 这是解决中断引脚持续拉低的关键 + err = instance->ResetIoExpand(); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板硬件复位失败"); + } else { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板硬件复位成功"); + + // 检查复位后的中断引脚状态 + int interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "复位后中断引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + } + + // 初始化IO扩展板子的中断引脚 + err = instance->InterruptGpioInit(GPIO_INPUT_PIN_SEL); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断初始化失败"); + } + // 设置IO扩展板模式 - 复位后必须重新配置寄存器! + err = instance->IoexpandSetMode(); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板模式配置失败"); + } else { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板模式配置成功"); + } + // 设置LCD屏幕复位引脚 + err = instance->SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功"); + } + // 设置LCD屏幕复位引脚为低电平 + err = instance->SetLcdResetMode(LCD_RST_LOW, LCD_RST_PORT, LCD_RST_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功"); + } + + uint8_t current_val_port0_ = 0,current_val_port1_ = 0,current_temp_ = 0; + for (;;) { + // 等待中断事件触发 + if (instance->i2c_task_event_group_) { + xEventGroupWaitBits(instance->i2c_task_event_group_, BIT0, pdTRUE, pdFALSE, portMAX_DELAY); + } + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板中断触发"); + + // 检查中断触发时的引脚状态 + int interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "中断触发时引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + + // AW9523B中断处理说明(根据数据手册): + // 1. 当输入引脚状态变化时,AW9523B会拉低INT引脚(连接到ESP32的GPIO10) + // 2. 通过读取输入端口寄存器(00H, 01H)来清除对应端口的中断 + // 3. 无独立的中断状态寄存器,需要通过输入电平变化来判断中断源 + // 4. 读取INPUT_PORT0 (00H) 清除P0口中断,读取INPUT_PORT1 (01H) 清除P1口中断 + + // 一次性读取两个端口的输入寄存器,避免重复读取和错误的OR操作 + instance->IoexpandReadReg(INPUT_PORT0, ¤t_val_port0_); + instance->IoexpandReadReg(INPUT_PORT1, ¤t_val_port1_); + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "读取端口状态 - Port0: 0x%02X, Port1: 0x%02X", current_val_port0_, current_val_port1_); + + // 检查读取寄存器后中断引脚是否被清除(应该恢复高电平) + interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "读取寄存器后中断引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + + //判断是否有中断来自雷达引脚 + if((RADAR_INTERRUPT_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << RADAR_INTERRUPT_PIN))){ + // 检查雷达引脚状态是否发生了变化,避免重复触发 + bool current_radar_state = (current_val_port0_ & (1 << RADAR_INTERRUPT_PIN)) != 0; + if (current_radar_state != instance->radar_last_state_) { + instance->radar_last_state_ = current_radar_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用毫米波雷达回调函数 + if (instance->radar_) { + instance->radar_->TriggerRadarDetectCallback(); + } + // 调用雷达回调函数(新接口) + if (instance->radar_callback_) { + instance->radar_callback_(); + } + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((RADAR_INTERRUPT_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << RADAR_INTERRUPT_PIN))){ + // 检查雷达引脚状态是否发生了变化,避免重复触发 + bool current_radar_state = (current_val_port1_ & (1 << RADAR_INTERRUPT_PIN)) != 0; + if (current_radar_state != instance->radar_last_state_) { + instance->radar_last_state_ = current_radar_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚1\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用毫米波雷达回调函数 + if (instance->radar_) { + instance->radar_->TriggerRadarDetectCallback(); + } + // 调用雷达回调函数(新接口) + if (instance->radar_callback_) { + instance->radar_callback_(); + } + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + // else{ + // ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "未检测到雷达引脚中断\n"); + // } + + //判断是否有中断来自初始光学传感器引脚 + if((START_PHOTO_INTERRUPTER_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << START_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port0_ & (1 << START_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port0_state_ & (1 << START_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自初始光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用初始光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerStartCallback(); + } + // 调用光学传感器开始回调函数(新接口) + if (instance->photo_start_callback_) { + instance->photo_start_callback_(); + } + // 更新状态 + instance->last_port0_state_ = current_val_port0_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((START_PHOTO_INTERRUPTER_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << START_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port1_ & (1 << START_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port1_state_ & (1 << START_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自初始光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用初始光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerStartCallback(); + } + // 调用光学传感器开始回调函数(新接口) + if (instance->photo_start_callback_) { + instance->photo_start_callback_(); + } + // 更新状态 + instance->last_port1_state_ = current_val_port1_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + // else{ + // // ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "未检测到初始光学传感器引脚中断\n"); + // } + + //判断是否有中断来自结束光学传感器引脚 + if((END_PHOTO_INTERRUPTER_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << END_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port0_ & (1 << END_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port0_state_ & (1 << END_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自结束光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用结束光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerEndCallback(); + } + // 调用光学传感器结束回调函数(新接口) + if (instance->photo_end_callback_) { + instance->photo_end_callback_(); + } + // 更新状态 + instance->last_port0_state_ = current_val_port0_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((END_PHOTO_INTERRUPTER_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << END_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port1_ & (1 << END_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port1_state_ & (1 << END_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自结束光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用结束光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerEndCallback(); + } + // 调用光学传感器结束回调函数(新接口) + if (instance->photo_end_callback_) { + instance->photo_end_callback_(); + } + // 更新状态 + instance->last_port1_state_ = current_val_port1_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + + //CHRG引脚充电前为高电平 充电中为低电平 充满电为高电平 + //FULL未充满为高电平 充满电为低电平 + //判断是否有中断来自电池充电引脚 + //根据配置:BATTERY_CHRG_INPUT = INPUT_PORT0, BATTERY_FULL_INPUT = INPUT_PORT1 + + // AW9523B没有独立的中断状态寄存器,需要通过比较前后状态变化来判断中断源 + // 由于读取输入端口会清除中断,我们需要先保存当前状态,然后与上次状态比较 + + //获取当前电池状态 + bool current_charging_state = !(current_val_port0_ & (1 << BATTERY_CHRG_PIN)); // CHRG低电平表示充电中 + bool current_full_state = !(current_val_port1_ & (1 << BATTERY_FULL_PIN)); // FULL低电平表示已充满 + + // 详细的调试信息 + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - Port0: 0x%02X, Port1: 0x%02X", current_val_port0_, current_val_port1_); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - CHRG_PIN: %d (bit %d), FULL_PIN: %d (bit %d)", + (current_val_port0_ & (1 << BATTERY_CHRG_PIN)) ? 1 : 0, BATTERY_CHRG_PIN, + (current_val_port1_ & (1 << BATTERY_FULL_PIN)) ? 1 : 0, BATTERY_FULL_PIN); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - 充电状态: %s, 充满状态: %s", + current_charging_state ? "充电中" : "未充电", + current_full_state ? "已充满" : "未充满"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - 上次充电状态: %s, 上次充满状态: %s", + instance->battery_charging_last_state_ ? "充电中" : "未充电", + instance->battery_full_last_state_ ? "已充满" : "未充满"); + + //检查充电状态是否发生变化 + if (current_charging_state != instance->battery_charging_last_state_) { + instance->battery_charging_last_state_ = current_charging_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "电池充电状态变化: %s", current_charging_state ? "充电中" : "未充电"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "充电状态变化详情 - 从 %s 到 %s", + instance->battery_charging_last_state_ ? "未充电" : "充电中", + current_charging_state ? "充电中" : "未充电"); + + if (current_charging_state) { + // 进入充电状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到开始充电"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerChrgCallback(); + } + if (instance->battery_charging_callback_) { + instance->battery_charging_callback_(); + } + } else { + // 退出充电状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到停止充电"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerNotChrgCallback(); + } + if (instance->battery_not_charging_callback_) { + instance->battery_not_charging_callback_(); + } + } + } + + //检查充满状态是否发生变化 + if (current_full_state != instance->battery_full_last_state_) { + instance->battery_full_last_state_ = current_full_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "电池充满状态变化: %s", current_full_state ? "已充满" : "未充满"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "充满状态变化详情 - 从 %s 到 %s", + instance->battery_full_last_state_ ? "未充满" : "已充满", + current_full_state ? "已充满" : "未充满"); + + if (current_full_state) { + // 进入充满状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到电池已充满"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerFullCallback(); + } + if (instance->battery_full_callback_) { + instance->battery_full_callback_(); + } + } + + } + + // 根据AW9523B数据手册:读取输入端口寄存器清除对应端口的中断 + // 读取INPUT_PORT0 (00H) 清除P0口中断,读取INPUT_PORT1 (01H) 清除P1口中断 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "中断处理完成,已读取输入端口寄存器清除中断标志"); + } +} + + +/** + * @brief 创建I2C数据读取任务 + */ +void IOExpansionBoard::CreateI2cReadTask() +{ + printf("创建I2C读取任务之前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之前:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + if (xI2CReadTaskHandle_) { + return; // 任务已创建 + } + + xTaskCreateWithCaps( + I2cReadTask, + "i2c_read_task", + I2C_TASK_STACK, + this, + I2C_TASK_PRIORITY, + &xI2CReadTaskHandle_, + MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT + ); + + if (xI2CReadTaskHandle_ == NULL) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to create static I2C read task"); + } else { + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static I2C read task created successfully"); + } + printf("创建I2C读取任务之后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之后:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +} + +/** + * @brief 启动I2C任务 (整合初始化和任务创建) + */ +esp_err_t IOExpansionBoard::StartTask() +{ + // 再创建任务 + if (!xI2CReadTaskHandle_) { + CreateI2cReadTask(); + } + return ESP_OK; +} diff --git a/main/02_physical/boards/board_v1_1_17/io_expansion_board.h b/main/02_physical/boards/board_v1_1_17/io_expansion_board.h new file mode 100644 index 0000000..2697e39 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_17/io_expansion_board.h @@ -0,0 +1,432 @@ +#ifndef IO_EXPANSION_BOARD_H +#define IO_EXPANSION_BOARD_H + +#include +#include +#include +#include +#include +#include +#include "i2c_bus.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include +#include +#include +#include +#include +#include +#include +#include "esp_err.h" +#include "config.h" +#include "portmacro.h" + +// 前向声明,避免循环引用 +class MillimeterWaveRadar; +class PhotoInterrupter; +class AdcBatteryMonitor; + +// 回调函数类型定义 +typedef std::function RadarCallback; +typedef std::function PhotoInterrupterStartCallback; +typedef std::function PhotoInterrupterEndCallback; +typedef std::function BatteryChargingCallback; +typedef std::function BatteryFullCallback; +typedef std::function BatteryNotChargingCallback; + +/* 寄存器地址 */ +#define INPUT_PORT0 0x00 // 输入端口0寄存器 +#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取) +#define OUTPUT_PORT0 0x02 // 输出端口0寄存器 +#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平 +#define CONFIG_PORT0 0x04 // 配置端口0寄存器 +#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式 +#define INT_PORT0 0x06 // 中断端口0寄存器 +#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的) +#define CTL 0x11 // 全局控制寄存器 +#define ID 0x23 // 芯片ID寄存器(0x23) + +/***********************************IO扩展板电机引脚配置参数*************************************/ +/* 设置步进电机方向 */ +#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转 +#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转 +#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4 +#define STEPPER_MOTOR_DIR_CONFIG CONFIG_PORT0 //步进电机方向引脚配置在P0_4 + +/* 设置步进电机细分模式 */ +#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5 +#define STEPPER_MOTOR_M0_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define STEPPER_MOTOR_M0_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_5 + +#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4 +#define STEPPER_MOTOR_M1_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define STEPPER_MOTOR_M1_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_4 + +/* 设置步进电机睡眠引脚 */ +#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式 +#define STEPPER_MOTOR_WORK true //步进电机进入工作模式 +#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6 +#define STEPPER_MOTOR_SLEEP_CONFIG CONFIG_PORT1 //步进电机睡眠引脚配置在P1_6 +#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 + +/* 设置电机的使能引脚 */ +#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7 +#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_ENABLE_CONFIG CONFIG_PORT0 //电机使能引脚配置在P0_7 +#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平 +#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平 + +/* 设置毫米波雷达对应IO扩展板的中断引脚 */ +#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7 +#define RADAR_INTERRUPT_CONFIG CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口 +#define RADAR_INTERRUPT_INPUT INPUT_PORT1 //毫米波雷达中断引脚输入状态检测在INPUT_PORT1 +#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态 +#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态 +/* 任务配置常量 */ +#define WRITE_BUF_SIZE 2 // I2C单次写入字节数 +#define READ_BUF_SIZE 2 // I2C单次读取字节数 +#define I2C_TASK_PRIORITY 2 // 任务优先级(中等) +#define I2C_TASK_STACK 4096 // 任务栈大小(4KB) + +// 光学传感器引脚定义 +#define START_PHOTO_INTERRUPTER_PIN 2 // 光学传感器引脚(P0_2) +#define START_PHOTO_INTERRUPTER_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口 +#define START_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0 +#define START_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平 +#define START_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平 + +#define END_PHOTO_INTERRUPTER_PIN 3 // 光学传感器引脚(P0_3) +#define END_PHOTO_INTERRUPTER_PORT_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口 +#define END_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0 +#define END_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平 +#define END_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平 + +/***********************************IO扩展板LCD引脚配置参数*************************************/ +// /* 设置LCD的BL引脚 */ +// #define LCD_BL_PIN 6 //LCD背光引脚对应IO扩展板引脚P0_6 +// #define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +// #define LCD_BL_CONFIG CONFIG_PORT0 //LCD背光引脚配置在P0_6 +// #define LCD_BL_HIGH true //LCD背光引脚状态为高电平 +// #define LCD_BL_LOW false //LCD背光引脚状态为低电平 + +/* 设置LED_EN (LCD背光/LED控制)引脚, PMOS高侧驱动 */ +#define LED_EN_PIN 1 //LED_EN对应IO扩展板引脚P0_1 +#define LED_EN_PORT OUTPUT_PORT0 //挂载在输出端口OUTPUT_PORT0 +#define LED_EN_CONFIG CONFIG_PORT0 //配置在P0_1 +#define LED_EN_OFF true //高电平关(PMOS) +#define LED_EN_ON false //低电平开(PMOS) + +/* 设置LCD的RST引脚 */ +#define LCD_RST_PIN 1 //LCD复位引脚对应IO扩展板引脚P1_1 +#define LCD_RST_CONFIG CONFIG_PORT1 //LCD复位引脚配置在P1_1 +#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define LCD_RST_HIGH true //LCD复位引脚状态为高电平 +#define LCD_RST_LOW false //LCD复位引脚状态为低电平 + +/* 设置PA控制引脚 */ +#define PA_CTRL_PIN 2 //PA控制引脚对应IO扩展板引脚P1_2 +#define PA_CTRL_CONFIG CONFIG_PORT1 //PA控制引脚配置在P1_2 +#define PA_CTRL_PORT OUTPUT_PORT1 //PA控制引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define PA_CTRL_HIGH true //PA控制引脚状态为高电平 +#define PA_CTRL_LOW false //PA控制引脚状态为低电平 + +// 电池充电检测引脚定义 +#define BATTERY_FULL_INPUT INPUT_PORT1 // 电池充满检测引脚挂载在IO扩展板的输入端口 +#define BATTERY_FULL_PIN 3 // 电池充满检测引脚对应IO扩展板引脚P1_3 +#define BATTERY_FULL_CONFIG CONFIG_PORT1 // 电池充满检测引脚配置在P1_3 + +#define BATTERY_CHRG_INPUT INPUT_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口 +#define BATTERY_CHRG_PIN 5 // 充电检测引脚(P0_5) +#define BATTERY_CHRG_CONFIG CONFIG_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口 + +#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签 +#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签 + +// GPIO引脚定义 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚 +// #define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚 + +/** + * @class IOExpansionBoard + * @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作 + */ +class IOExpansionBoard +{ +public: + /** + * @brief 构造函数 + */ + IOExpansionBoard(); + + /** + * @brief 设置毫米波雷达指针 + * @param radar 毫米波雷达对象指针 + */ + void SetRadar(MillimeterWaveRadar* radar) { radar_ = radar; }; + + /** + * @brief 设置限位开关指针 + * @param photo_interrupter 限位开关对象指针 + */ + void setPhotoInterrupter(PhotoInterrupter* photo_interrupter) { photo_interrupter_ = photo_interrupter; }; + + /** + * @brief 设置电池监控器指针 + * @param battery_monitor 电池监控器对象指针 + */ + void setBatteryMonitor(AdcBatteryMonitor* battery_monitor) { battery_monitor_ = battery_monitor; }; + + /** + * @brief 析构函数 + */ + ~IOExpansionBoard(); + + /** + * @brief 初始化GPIO中断检测 + * @param gpio_num 中断引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t InterruptGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetIoExpand(); + + /** + * @brief 初始化I2C主机通信 + * @return esp_err_t 初始化结果 + */ + // esp_err_t IoExpansionI2cInit(); + + /** + * @brief 创建I2C数据读取任务 + */ + void CreateI2cReadTask(); + + /** + * @brief 启动I2C任务(整合初始化和任务创建) + * @return esp_err_t 操作结果 + */ + esp_err_t StartTask(); + + /** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data); + + /** + * @brief 读寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要读出的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data); + + /** + * @brief 读取输入端口0寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t ReadInputPort0(uint8_t *data); + + /** + * @brief 读取输入端口1寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t ReadInputPort1(uint8_t *data); + + // /** + // * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断 + // * @param reg_addr 寄存器地址 + // * @return esp_err_t 操作结果 + // */ + // esp_err_t SetInterruptStatus(bool status); + + /** + * @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandSetMode(); + + /** + * @brief 设置步进电机的细分模式 + * @param mode 模式:1/2/4/8/16/32/64 + * @return esp_err_t 操作结果 + */ + void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin); + + /** + * @brief 设置步进电机的方向 + * @param dir 方向 + * @param OUTPUT_PORT 输出端口 + * @param pin 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin); + + /** + * @brief 设置步进电机的睡眠模式 + * @param 是否进入睡眠模式 + * @param 输出端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin); + + /** + * @brief 设置步进电机的使能引脚状态 + * @param 使能状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin); + + /** + * @brief 设置LCD的BL引脚状态 + * @param BL状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin); + + /** + * @brief 设置 LED_EN 引脚电平(用于控制LCD背光/LED灯电源) + * @param mode true:开启(低电平), false:关闭(高电平) + */ + esp_err_t SetLedEnMode(bool mode); + + /** + * @brief 设置LCD的RST引脚状态 + * @param RST状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin); + + /** + * @brief 设置PA控制引脚状态 + * @param mode PA_CTRL状态(true为高电平,false为低电平) + * @return esp_err_t 操作结果 + */ + esp_err_t SetPaCtrlMode(bool mode); + + /** + * @brief 设置雷达中断引脚 + * @param 毫米波雷达的中断引脚模式 + * @param 输入端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin); + + /** + * @brief 计算Port0的字节值 + * @return uint8_t 操作结果 + */ + uint8_t ByteCalculatePort0(); + + /** + * @brief 计算Port1的字节值 + * @return uint8_t 操作结果 + */ + uint8_t ByteCalculatePort1(); + + /** + * @brief 设置雷达中断回调函数 + * @param callback 雷达中断回调函数 + */ + void SetRadarCallback(RadarCallback callback) { radar_callback_ = callback; } + + /** + * @brief 设置光学传感器开始中断回调函数 + * @param callback 光学传感器开始中断回调函数 + */ + void SetPhotoInterrupterStartCallback(PhotoInterrupterStartCallback callback) { photo_start_callback_ = callback; } + + /** + * @brief 设置光学传感器结束中断回调函数 + * @param callback 光学传感器结束中断回调函数 + */ + void SetPhotoInterrupterEndCallback(PhotoInterrupterEndCallback callback) { photo_end_callback_ = callback; } + + /** + * @brief 设置电池充电中断回调函数 + * @param callback 电池充电中断回调函数 + */ + void SetBatteryChargingCallback(BatteryChargingCallback callback) { battery_charging_callback_ = callback; } + + /** + * @brief 设置电池充满中断回调函数 + * @param callback 电池充满中断回调函数 + */ + void SetBatteryFullCallback(BatteryFullCallback callback) { battery_full_callback_ = callback; } + + /** + * @brief 设置电池非充电中断回调函数 + * @param callback 电池非充电中断回调函数 + */ + void SetBatteryNotChargingCallback(BatteryNotChargingCallback callback) { battery_not_charging_callback_ = callback; } + + // 公共成员变量 + i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄 + uint8_t device_addr_; // I2C设备地址 + +private: + // 静态成员函数 + MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调 + PhotoInterrupter* photo_interrupter_ = nullptr; // 限位开关指针,用于触发回调 + AdcBatteryMonitor* battery_monitor_ = nullptr; // 电池监控器指针,用于触发回调 + static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数 + static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数 + + // 成员变量用于状态跟踪 + uint8_t last_port0_state_ = 0; // 上次检测到的Port0状态 + uint8_t last_port1_state_ = 0; // 上次检测到的Port1状态 + bool radar_last_state_ = false; // 雷达引脚上一次的状态 + bool battery_charging_last_state_ = false; // 电池充电状态上一次的状态 + bool battery_full_last_state_ = false; // 电池充满状态上一次的状态 + + // 回调函数成员变量 + RadarCallback radar_callback_ = nullptr; + PhotoInterrupterStartCallback photo_start_callback_ = nullptr; + PhotoInterrupterEndCallback photo_end_callback_ = nullptr; + BatteryChargingCallback battery_charging_callback_ = nullptr; + BatteryFullCallback battery_full_callback_ = nullptr; + BatteryNotChargingCallback battery_not_charging_callback_ = nullptr; + + // PhotoInterrupter* photo_interrupter_ = nullptr; // 光学传感器指针,用于触发回调 + // /** + // * @brief 分配静态任务所需的内存 + // * @return bool 分配是否成功 + // */ + // bool AllocateStaticTaskMemory(); + + // /** + // * @brief 释放静态任务分配的内存 + // */ + // void FreeStaticTaskMemory(); + + // 实例成员变量 + EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组 + TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄 + bool is_initialized_ = false; // 初始化状态标记(新增) + gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚 + gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚 + + // StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM) + // StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM) +}; + +#endif \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_17/power_management_config.h b/main/02_physical/boards/board_v1_1_17/power_management_config.h new file mode 100644 index 0000000..da609fb --- /dev/null +++ b/main/02_physical/boards/board_v1_1_17/power_management_config.h @@ -0,0 +1,178 @@ +/** + * @file power_management_config.h + * @brief 功耗管理配置和策略定义 + * @author Embedded Software Expert + * @date 2025年1月 + * + * 这个文件定义了功耗管理的配置参数、策略和优化建议, + * 为系统提供灵活的功耗管理方案。 + */ + +#ifndef POWER_MANAGEMENT_CONFIG_H +#define POWER_MANAGEMENT_CONFIG_H + +#include "esp_sleep.h" +#include "driver/rtc_io.h" +#include "esp32/rom/rtc.h" + +/** + * @brief 功耗管理配置结构体 + */ +typedef struct { + // 睡眠模式配置 + uint64_t light_sleep_duration_us; // 轻度睡眠持续时间(微秒) + uint64_t deep_sleep_duration_us; // 深度睡眠持续时间(微秒) + + // 唤醒源配置 + bool enable_timer_wakeup; // 启用定时器唤醒 + bool enable_gpio_wakeup; // 启用GPIO唤醒 + bool enable_touch_wakeup; // 启用触摸唤醒 + gpio_num_t wakeup_gpio_num; // 唤醒GPIO编号 + int wakeup_level; // 唤醒电平(0或1) + + // 功耗优化配置 + bool disable_bt_in_sleep; // 睡眠时关闭蓝牙 + bool disable_wifi_in_sleep; // 睡眠时关闭WiFi + bool reduce_cpu_frequency; // 降低CPU频率 + uint32_t cpu_frequency_hz; // CPU频率(Hz) + + // 外设功耗配置 + bool power_down_sdcard; // 睡眠时关闭SD卡电源 + bool power_down_display; // 睡眠时关闭显示电源 + bool power_down_audio; // 睡眠时关闭音频电源 + bool power_down_motor; // 睡眠时关闭电机电源 + + // RTC内存配置 + bool preserve_rtc_memory; // 保留RTC内存 + size_t rtc_memory_size; // RTC内存大小 +} power_management_config_t; + +/** + * @brief 默认功耗管理配置 + */ +#define DEFAULT_POWER_CONFIG { \ + .light_sleep_duration_us = 1000000, /* 1秒 */ \ + .deep_sleep_duration_us = 30000000, /* 30秒 */ \ + .enable_timer_wakeup = true, /* 启用定时器唤醒 */ \ + .enable_gpio_wakeup = false, /* 不启用GPIO唤醒 */ \ + .enable_touch_wakeup = false, /* 不启用触摸唤醒 */ \ + .wakeup_gpio_num = GPIO_NUM_NC, /* 无GPIO唤醒 */ \ + .wakeup_level = 0, /* 低电平唤醒 */ \ + .disable_bt_in_sleep = true, /* 睡眠时关闭蓝牙 */ \ + .disable_wifi_in_sleep = true, /* 睡眠时关闭WiFi */ \ + .reduce_cpu_frequency = true, /* 降低CPU频率 */ \ + .cpu_frequency_hz = 80000000, /* 80MHz */ \ + .power_down_sdcard = true, /* 睡眠时关闭SD卡 */ \ + .power_down_display = true, /* 睡眠时关闭显示 */ \ + .power_down_audio = true, /* 睡眠时关闭音频 */ \ + .power_down_motor = true, /* 睡眠时关闭电机 */ \ + .preserve_rtc_memory = true, /* 保留RTC内存 */ \ + .rtc_memory_size = 4096, /* 4KB RTC内存 */ \ +} + +/** + * @brief 各功耗模式的详细配置 + */ +static const power_management_config_t idle_mode_config = { + .light_sleep_duration_us = 500000, // 500ms轻度睡眠 + .deep_sleep_duration_us = 0, // 不使用深度睡眠 + .enable_timer_wakeup = true, + .enable_gpio_wakeup = true, + .wakeup_gpio_num = GPIO_NUM_0, // 按键唤醒 + .wakeup_level = 0, + .disable_bt_in_sleep = false, // 保持蓝牙连接 + .disable_wifi_in_sleep = false, // 保持WiFi连接 + .reduce_cpu_frequency = true, + .cpu_frequency_hz = 40000000, // 40MHz + .power_down_sdcard = false, // 保持SD卡(可能有后台任务) + .power_down_display = true, // 关闭显示背光 + .power_down_audio = true, // 关闭音频 + .power_down_motor = true, // 关闭电机 + .preserve_rtc_memory = true, + .rtc_memory_size = 2048, +}; + +static const power_management_config_t light_sleep_config = { + .light_sleep_duration_us = 0, // 直接进入轻度睡眠 + .deep_sleep_duration_us = 0, + .enable_timer_wakeup = true, + .enable_gpio_wakeup = true, + .wakeup_gpio_num = GPIO_NUM_0, + .wakeup_level = 0, + .disable_bt_in_sleep = true, // 关闭蓝牙 + .disable_wifi_in_sleep = true, // 关闭WiFi + .reduce_cpu_frequency = true, + .cpu_frequency_hz = 40000000, + .power_down_sdcard = true, // 关闭SD卡 + .power_down_display = true, // 关闭显示 + .power_down_audio = true, // 关闭音频 + .power_down_motor = true, // 关闭电机 + .preserve_rtc_memory = true, + .rtc_memory_size = 4096, +}; + +static const power_management_config_t deep_sleep_config = { + .light_sleep_duration_us = 0, + .deep_sleep_duration_us = 60000000, // 60秒深度睡眠 + .enable_timer_wakeup = true, + .enable_gpio_wakeup = true, + .wakeup_gpio_num = GPIO_NUM_0, + .wakeup_level = 0, + .disable_bt_in_sleep = true, // 关闭蓝牙 + .disable_wifi_in_sleep = true, // 关闭WiFi + .reduce_cpu_frequency = true, + .cpu_frequency_hz = 10000000, // 10MHz + .power_down_sdcard = true, // 关闭SD卡 + .power_down_display = true, // 关闭显示 + .power_down_audio = true, // 关闭音频 + .power_down_motor = true, // 关闭电机 + .preserve_rtc_memory = true, + .rtc_memory_size = 8192, +}; + +/** + * @brief 功耗统计和监控结构体 + */ +typedef struct { + uint64_t total_sleep_time_us; // 总睡眠时间 + uint64_t total_wake_time_us; // 总唤醒时间 + uint32_t sleep_count; // 睡眠次数 + uint32_t wake_count; // 唤醒次数 + uint32_t average_sleep_duration_us; // 平均睡眠时长 + uint32_t average_wake_duration_us; // 平均唤醒时长 + float estimated_power_saving_percent; // 估计的功耗节省百分比 +} power_statistics_t; + +/** + * @brief 功耗优化建议 + * + * 基于硬件特性和使用模式,提供功耗优化建议 + */ +typedef enum { + OPTIMIZATION_NONE = 0, + OPTIMIZATION_REDUCE_CPU_FREQ, // 降低CPU频率 + OPTIMIZATION_DISABLE_UNUSED_PERIPHERALS, // 关闭未使用的外设 + OPTIMIZATION_USE_LIGHT_SLEEP, // 使用轻度睡眠 + OPTIMIZATION_USE_DEEP_SLEEP, // 使用深度睡眠 + OPTIMIZATION_OPTIMIZE_GPIO_STATES, // 优化GPIO状态 + OPTIMIZATION_USE_RTC_MEMORY, // 使用RTC内存 + OPTIMIZATION_BATCH_OPERATIONS, // 批量操作 +} power_optimization_t; + +/** + * @brief 功耗管理事件回调 + */ +typedef void (*power_event_callback_t)(power_mode_t old_mode, power_mode_t new_mode, void* user_data); + +/** + * @brief 功耗管理事件 + */ +typedef enum { + POWER_EVENT_MODE_CHANGE, // 功耗模式改变 + POWER_EVENT_SLEEP_START, // 睡眠开始 + POWER_EVENT_SLEEP_END, // 睡眠结束 + POWER_EVENT_WAKEUP, // 系统唤醒 + POWER_EVENT_OPTIMIZATION_TRIGGER, // 功耗优化触发 +} power_event_t; + +#endif // POWER_MANAGEMENT_CONFIG_H \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_18/board_sweekar.cc b/main/02_physical/boards/board_v1_1_18/board_sweekar.cc new file mode 100644 index 0000000..8369f11 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_18/board_sweekar.cc @@ -0,0 +1,778 @@ +/** + * @file board.cc + * @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +extern "C" { +#include "esp_log.h" +#include "driver/gpio.h" +#include "driver/uart.h" +#include "driver/ledc.h" +#include "driver/gptimer.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "hal/gpio_types.h" +#include "hal/uart_types.h" +#include "esp_check.h" +#include "sdkconfig.h" +#include "i2c_bus.h" +#include "esp_peripherals.h" +#include "periph_sdcard.h" +#include "esp_sleep.h" +#include "driver/rtc_io.h" +} + +#include "board_sweekar.h" +#include "config.h" +#include "board.h" // 添加board.h以获取audio_board_sdcard_init函数声明 +#include "drv8428.h" +#include "aw8646.h" +#include "esp_vfs_fat.h" +#include "audio_mem.h" +#include "esp_timer.h" +#include "base_board_hal_i2c.h" + +#define TAG "board_sweekar" + +static BoardSweekar* s_board_instance = nullptr; + +BoardSweekar* BoardSweekar::GetInstance() +{ + if (s_board_instance == nullptr) { + static BoardSweekar global_board; + s_board_instance = &global_board; + } + return s_board_instance; +} + +BoardSweekar::BoardSweekar() +{ +#ifdef CONFIG_STEPPER_DRIVER_AW8646 + stepper_driver_ = new Aw8646Driver(io_expansion_); +#else + stepper_driver_ = new Drv8428Driver(io_expansion_); +#endif +} + +BoardSweekar::~BoardSweekar() +{ + if (stepper_driver_) { + delete stepper_driver_; + stepper_driver_ = nullptr; + } +} + +void BoardSweekar::SetAudioAmplifier(bool enable) { + // AUD_CTRL 是 codec 侧控制脚,不参与 PA 开关;PA 仍由 IO 扩展板控制。 + io_expansion_.SetPaCtrlMode(enable); + ESP_LOGI(TAG, "Audio Amplifier (via IO Expansion) %s", enable ? "ENABLED" : "DISABLED"); +} + +/*========================== 步进电机相关驱动 ==========================*/ + +/** + * @brief 步进电机初始化函数 + * 配置步进电机所需的GPIO引脚模式,通过IO扩展板设置步进驱动芯片的工作模式 + * 在 stepper_motor.cc 中完成 GPTimer + GPIO 翻转 STEP 脉冲的初始化 + */ +void BoardSweekar::StepperMotorInit(void) +{ + esp_err_t err = ESP_OK; + + // 1) STEP 引脚改为普通 GPIO(不再用 LEDC) + gpio_config_t io_cfg; + io_cfg.pin_bit_mask = 1ULL << STEPPER_STEP_IO; + io_cfg.mode = GPIO_MODE_OUTPUT; + io_cfg.pull_up_en = GPIO_PULLUP_DISABLE; + io_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_cfg.intr_type = GPIO_INTR_DISABLE; + err = gpio_config(&io_cfg); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "步进电机 STEP GPIO 配置失败, 错误码: 0x%x", err); + } + + // 初始电平拉低,保证上电不乱跳 + gpio_set_level(STEPPER_STEP_IO, 0); + + // 2) 检查 I2C 总线是否已初始化 + if (bus_handle_ == nullptr) + { + ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()"); + return; + } + + // 3) 初始化驱动对象并初始化 + if (stepper_driver_) { + err = stepper_driver_->Init(); + if (err != ESP_OK) { + ESP_LOGE(TAG_BOARD, "步进电机驱动初始化失败, 错误码: 0x%x", err); + } + } else { + ESP_LOGE(TAG_BOARD, "步进电机驱动创建失败"); + } +} + +/** + * @brief LCD IO引脚初始化函数(消除与步进电机的耦合) + * + * 配置LCD所需的IO扩展板寄存器,确保LCD复位引脚正常工作 + * 此函数独立于步进电机初始化,专门处理LCD相关的IO配置 + */ +void BoardSweekar::LcdIoInit(void) +{ + esp_err_t err = ESP_OK; + + // 1) 检查I2C总线是否已初始化 + if (bus_handle_ == nullptr) + { + ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()"); + return; + } + + // 2) 执行硬件复位,确保IO扩展板处于已知状态 + err = io_expansion_.ResetIoExpand(); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "IO扩展板硬件复位失败, 错误码: 0x%x", err); + return; + } + else + { + ESP_LOGI(TAG_BOARD, "IO扩展板硬件复位成功"); + } + + // 3) 配置IO扩展板模式(端口方向等) + err = io_expansion_.IoexpandSetMode(); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "IO扩展板模式配置失败, 错误码: 0x%x", err); + return; + } + else + { + ESP_LOGI(TAG_BOARD, "IO扩展板模式配置成功"); + } + + // 4) 初始化LCD复位引脚:设置为高电平 + err = io_expansion_.SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "LCD复位引脚高电平设置失败, 错误码: 0x%x", err); + return; + } + else + { + ESP_LOGI(TAG_BOARD, "LCD复位引脚高电平设置成功"); + } + + // 5) 初始化LED_EN电源为关闭状态 (PMOS高电平关) + // 只有在需要亮灯时,由ActuatorActor主动开启,避免平静状态下常亮 + err = io_expansion_.SetLedEnMode(false); + if (err != ESP_OK) + { + ESP_LOGE(TAG_BOARD, "初始化LED_EN电源(关闭)失败, 错误码: 0x%x", err); + } + else + { + ESP_LOGI(TAG_BOARD, "初始化LED_EN电源(关闭)成功"); + } +} + +/** + * @brief 执行系统关机 + * 内部拉高 SHUTDOWN_CTRL_PIN 引脚切断电源 + */ +void BoardSweekar::SystemShutdown(void) +{ +#ifdef SHUTDOWN_CTRL_PIN + ESP_LOGI(TAG, "Executing System Shutdown... Pulling SHUTDOWN_CTRL_PIN (%d) HIGH", SHUTDOWN_CTRL_PIN); + // 用户指定:拉高可以完成关机动作 + gpio_set_level(SHUTDOWN_CTRL_PIN, 1); + + // 给一点时间让电源完全断开 + vTaskDelay(pdMS_TO_TICKS(1000)); +#else + ESP_LOGW(TAG, "SHUTDOWN_CTRL_PIN is not defined. Cannot execute hardware shutdown."); +#endif +} + +/*========================== 毫米波雷达相关驱动 ==========================*/ + +/** + * @brief 毫米波雷达串口初始化函数 + * + * 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚, + * 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免 + * 与自定义中断冲突。 + */ +void BoardSweekar::MillimeterWaveRadarUartInit(void) +{ + uart_config_t uart_config = { + .baud_rate = RADAR_BAUD_RATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + .flags = { + .allow_pd = 0, + .backup_before_sleep = 0, + }, + }; + + // 1. 设置串口参数 + ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config)); + + // 2. 设置 UART 引脚 + ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突) + // 增加 RX/TX FIFO 深度以处理突发数据 + ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4, + 0, NULL, 0)); +} + +/** + * @brief 毫米波雷达中断引脚初始化函数 + * + * 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能 + * (如需使用中断需单独进行配置)。 + */ +void BoardSweekar::MillimeterWaveRadarGpioInit(void) +{ + // GPIO配置结构体 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚 + .mode = GPIO_MODE_INPUT, // 设置为输入模式 + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉 + .intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置) + }; + + // 配置GPIO + gpio_config(&io_conf); +} + +/*========================== I2C总线及挂载的从设备相关驱动 ==========================*/ + +/** + * @brief I2C总线及从机设备初始化函数 + * + * 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。 + * 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。 + * 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。 + * + * @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因 + */ +esp_err_t BoardSweekar::I2CMasterInit(void) +{ + static const char *I2C_INIT = "I2C_INIT"; + + // 初始化IO扩展板复位引脚 + gpio_config_t reset_io_conf = { + .pin_bit_mask = (1ULL << IO_EXPAND_RSTN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉 + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&reset_io_conf); + + // 执行复位时序:先拉低100ms,再拉高并等待100ms + gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms + gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位 + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + + ESP_LOGI(I2C_INIT, "IO扩展板复位完成"); + + // 创建统一的I2C总线(使用ESP-ADF的i2c_bus) + i2c_config_t i2c_cfg = { + .mode = I2C_MODE_MASTER, + .sda_io_num = I2C0_MASTER_SDA_IO, + .scl_io_num = I2C0_MASTER_SCL_IO, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master = { + .clk_speed = 100000, + }, + }; + + // 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线) + bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg); + if (bus_handle_ == NULL) { + ESP_LOGE(TAG, "Failed to create I2C bus"); + return ESP_FAIL; + } + + vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动 + // ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信 + + // 验证线性马达设备是否存在 + esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR); + } + // 验证IO扩展板设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err); + // 不返回错误,继续初始化其他设备 + } else { + ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR); + } + // 验证陀螺仪设备是否存在 + err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1); + if (err != ESP_OK) { + ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err); + // 不返回错误,继续初始化 + } else { + ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR); + } + + // 为IO扩展板设置总线句柄和设备地址(使用7位地址) + io_expansion_.bus_handle_ = bus_handle_; + io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1; + + // 线性马达的初始化已移至 InitializeAllHardware 中统一调用 Init 方法 + // linear_motor_ 的参数传递将在那里完成,不再此处直接赋值,提高内聚性 + + ESP_LOGI(I2C_INIT, "I2C总线初始化完成"); + return ESP_OK; +} + +/*========================== VBAT to VBAT_5V相关驱动 ==========================*/ + +/** + * @brief 开启VBAT to VBAT_5V + * + * 创建开启升压的电源管理单元 + * + */ +void BoardSweekar::VbatToVbat5vInit(void) +{ + // 配置VBAT_5V引脚为输出模式 + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << VBAT_5V_PIN), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&io_conf); + // 使能VBAT_5V + gpio_set_level(VBAT_5V_PIN, 1); +} + +/*========================== 底座控制串口相关驱动 ==========================*/ + +/** + * @brief 底座控制命令串口初始化函数 + */ +// 根据配置选择通信方式的HAL头文件 +#ifdef CONFIG_BASE_BOARD_COMM_I2C +#include "base_board_hal_i2c.h" +#else +#include "base_board_hal_uart.h" +#endif + +void BoardSweekar::BaseBoardControlInit(void) +{ +#ifdef CONFIG_BASE_BOARD_COMM_I2C + // I2C Mode + if (bus_handle_ == nullptr) { + ESP_LOGE(TAG, "I2C bus not initialized before BaseBoardControlInit"); + return; + } + + // 创建 I2C HAL 实例 + BaseBoardHalI2c *hal = new BaseBoardHalI2c(bus_handle_); + base_board_control_.Init(hal); + ESP_LOGI(TAG, "BaseBoardControl I2C initialized"); +#else + // UART Mode + uart_config_t uart_config = { + .baud_rate = BASE_BOARD_CTL_UART_BAUDRATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + .flags = { + .allow_pd = 0, + .backup_before_sleep = 0, + }, + }; + + // 1. 设置串口参数 + ESP_ERROR_CHECK(uart_param_config(BASE_BOARD_CTL_UART_PORT, &uart_config)); + + // 2. 设置 UART 引脚 + ESP_ERROR_CHECK(uart_set_pin(BASE_BOARD_CTL_UART_PORT, BASE_BOARD_CTL_UART_TX_PIN, BASE_BOARD_CTL_UART_RX_PIN, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 3. 安装 UART 驱动 + ESP_ERROR_CHECK(uart_driver_install(BASE_BOARD_CTL_UART_PORT, + BASE_BOARD_CTL_UART_BUF_SIZE, + BASE_BOARD_CTL_UART_BUF_SIZE, + 0, NULL, 0)); + + BaseBoardHalUart *hal = new BaseBoardHalUart(BASE_BOARD_CTL_UART_PORT); + base_board_control_.Init(hal); + ESP_LOGI(TAG, "BaseBoardControl UART initialized"); +#endif +} + +/*========================== SD卡相关驱动 ==========================*/ + +/** + * @brief SD卡初始化函数 + * + * 初始化SD卡外设,使用1线模式进行通信。该函数负责初始化外设管理器 + * 并配置SD卡,为后续的文件系统操作做准备。 + * + * @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示失败原因 + */ +esp_err_t BoardSweekar::InitializeSdcard(void) +{ + static const char *SDCARD_TAG = "SDCARD_INIT"; + esp_err_t ret; + + ESP_LOGI(SDCARD_TAG, "Initializing SD card"); + + if (is_sdcard_initialized_) { + ESP_LOGW(SDCARD_TAG, "SD card already initialized"); + return ESP_OK; + } + + // 初始化外设管理 + esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG(); + periph_cfg.extern_stack = true; // 将任务栈分配到 PSRAM 以节省 Internal SRAM + periph_set_ = esp_periph_set_init(&periph_cfg); + if (!periph_set_) { + ESP_LOGE(SDCARD_TAG, "Failed to initialize peripheral set"); + return ESP_FAIL; + } + + // 初始化SD卡外设 + ret = audio_board_sdcard_init(periph_set_, SD_MODE_1_LINE); + if (ret != ESP_OK) { + ESP_LOGE(SDCARD_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret)); + return ret; + } + + is_sdcard_initialized_ = true; + ESP_LOGI(SDCARD_TAG, "SD card initialized successfully"); + return ESP_OK; +} + +/** + * @brief 统一的硬件初始化接口实现 + * + * 按照依赖关系顺序初始化所有硬件资源: + * 1. I2C总线(最基础,其他设备可能依赖) + * 2. IO扩展板(可能影响其他设备) + * 3. SD卡(文件系统,供显示和音频使用) + * 4. 其他外设 + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ +esp_err_t BoardSweekar::InitializeAllHardware(void) +{ + static const char *HW_INIT_TAG = "HW_INIT"; + esp_err_t ret; + + ESP_LOGI(HW_INIT_TAG, "Starting unified hardware initialization..."); + + // 1. 初始化I2C总线(最基础) + ret = I2CMasterInit(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret)); + return ret; + } + ESP_LOGI(HW_INIT_TAG, "I2C master initialized"); + + // 2. 创建I2C读任务(IO扩展板需要) + io_expansion_.CreateI2cReadTask(); + ESP_LOGI(HW_INIT_TAG, "I2C read task created"); + + // 3. 初始化SD卡(文件系统,供显示和音频使用) + ret = InitializeSdcard(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret)); + // SD卡失败不是致命错误,继续初始化其他硬件 + ESP_LOGW(HW_INIT_TAG, "SD card initialization failed, but continuing with other hardware"); + } else { + ESP_LOGI(HW_INIT_TAG, "SD card initialized"); + } + + // 4. 初始化LCD IO引脚 + LcdIoInit(); + ESP_LOGI(HW_INIT_TAG, "LCD IO pins initialized"); + + // 5. 初始化底座控制 + if (bus_handle_ != nullptr) { + BaseBoardHalI2c *hal_i2c = new BaseBoardHalI2c(bus_handle_); + base_board_control_.Init(hal_i2c); + ESP_LOGI(HW_INIT_TAG, "Base board control initialized with I2C handle"); + } else { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize base board control: I2C bus is null"); + } + + // 6. AUD_CTRL 为 codec 控制脚,板级初始化后保持拉高,不参与 PA 开关。 +#ifdef AUD_CTRL_PIN + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = (1ULL << AUD_CTRL_PIN); + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + gpio_config(&io_conf); + gpio_set_level(AUD_CTRL_PIN, 1); + ESP_LOGI(HW_INIT_TAG, "AUD_CTRL pin initialized to HIGH"); +#endif + + // 7. 可选外设(根据具体应用需求) + // BaseBoardControlUartInit(); // 底座控制串口(demo5需要) + // ESP_LOGI(HW_INIT_TAG, "Base board control UART initialized"); + + // MillimeterWaveRadarUartInit(); + // MillimeterWaveRadarGpioInit(); + StepperMotorInit(); + + + + ESP_LOGI(HW_INIT_TAG, "Unified hardware initialization completed successfully"); + return ESP_OK; +} + +/** + * @brief 进入低功耗模式 + * + * 根据指定的功耗模式,执行相应的功耗优化策略: + * - IDLE模式:关闭非必要外设,保持快速响应 + * - LIGHT_SLEEP模式:进入轻度睡眠,CPU暂停,外设断电 + * - DEEP_SLEEP模式:深度睡眠,仅RTC运行,功耗最低 + */ +esp_err_t BoardSweekar::EnterLowPowerMode(power_mode_t mode) { + static const char *POWER_TAG = "POWER_MGMT"; + esp_err_t ret = ESP_OK; + + ESP_LOGI(POWER_TAG, "Entering power mode: %d", mode); + + if (mode == current_power_mode_) { + ESP_LOGW(POWER_TAG, "Already in power mode %d", mode); + return ESP_OK; + } + + // 保存当前模式,以便恢复 + power_mode_t previous_mode = current_power_mode_; + + switch (mode) { + case POWER_MODE_NORMAL: + // 正常模式,不需要特殊处理 + break; + + case POWER_MODE_IDLE: + // 空闲模式:关闭非必要外设 + ESP_LOGI(POWER_TAG, "Idle mode: disabling non-essential peripherals"); + + // 关闭SD卡(如果正在使用,需要先卸载) + if (is_sdcard_initialized_) { + // 注意:这里只是示例,实际应用中需要确保没有文件操作 + ESP_LOGW(POWER_TAG, "SD card still active in idle mode"); + } + + // 关闭显示背光 + // 关闭非必要GPIO的上拉/下拉 + // 降低I2C时钟频率 + break; + + case POWER_MODE_LIGHT_SLEEP: + // 轻度睡眠 + ESP_LOGI(POWER_TAG, "Light sleep mode: preparing for sleep"); + + // 设置唤醒源(需要根据具体需求配置) + // esp_sleep_enable_timer_wakeup(1000000); // 1秒后唤醒 + // esp_sleep_enable_ext0_wakeup(GPIO_NUM_XX, 0); // 外部中断唤醒 + + // 进入轻度睡眠 + // ret = esp_light_sleep_start(); + if (ret != ESP_OK) { + ESP_LOGE(POWER_TAG, "Failed to enter light sleep: %s", esp_err_to_name(ret)); + current_power_mode_ = previous_mode; + return ret; + } + break; + + case POWER_MODE_DEEP_SLEEP: + // 深度睡眠 + ESP_LOGI(POWER_TAG, "Deep sleep mode: system will restart after wake-up"); + + // 保存必要的RTC数据 + // rtc_gpio_isolate(GPIO_NUM_XX); // 隔离GPIO + + // 设置深度睡眠唤醒源 + // esp_sleep_enable_timer_wakeup(60000000); // 60秒后唤醒 + + // 进入深度睡眠 + // esp_deep_sleep_start(); + // 注意:深度睡眠后系统会重启,不会返回 + break; + + default: + ESP_LOGE(POWER_TAG, "Invalid power mode: %d", mode); + return ESP_ERR_INVALID_ARG; + } + + current_power_mode_ = mode; + ESP_LOGI(POWER_TAG, "Successfully entered power mode: %d", mode); + return ret; +} + +/** + * @brief 退出低功耗模式 + * + * 从低功耗模式恢复到正常运行模式,重新初始化必要的硬件资源。 + */ +esp_err_t BoardSweekar::ExitLowPowerMode(void) { + static const char *POWER_TAG = "POWER_MGMT"; + + ESP_LOGI(POWER_TAG, "Exiting low power mode"); + + if (current_power_mode_ == POWER_MODE_NORMAL) { + ESP_LOGW(POWER_TAG, "Already in normal mode"); + return ESP_OK; + } + + // 根据之前的功耗模式执行相应的恢复操作 + switch (current_power_mode_) { + case POWER_MODE_IDLE: + // 恢复空闲模式 + ESP_LOGI(POWER_TAG, "Restoring from idle mode"); + + // 重新初始化必要的外设 + // 恢复I2C时钟频率 + // 重新开启显示背光 + break; + + case POWER_MODE_LIGHT_SLEEP: + // 轻度睡眠唤醒后会自动继续执行 + ESP_LOGI(POWER_TAG, "Woken up from light sleep"); + + // 重新配置时钟(如果需要) + // 重新初始化外设 + break; + + case POWER_MODE_DEEP_SLEEP: + // 深度睡眠后系统会重启,不会执行到这里 + ESP_LOGW(POWER_TAG, "Deep sleep recovery should not reach here"); + break; + + default: + break; + } + + // 恢复到正常模式 + current_power_mode_ = POWER_MODE_NORMAL; + ESP_LOGI(POWER_TAG, "Successfully exited low power mode"); + + return ESP_OK; +} + +/** + * @brief 设置硬件模块电源状态 + * + * 提供精细化的电源管理,可以单独控制各个硬件模块的电源状态。 + */ +esp_err_t BoardSweekar::SetModulePower(hardware_module_t module, bool enable) { + static const char *POWER_TAG = "POWER_MODULE"; + esp_err_t ret = ESP_OK; + + ESP_LOGI(POWER_TAG, "%s module %d", enable ? "Enabling" : "Disabling", module); + + // 更新电源状态位图 + if (enable) { + power_state_flags_ |= (1 << module); + } else { + power_state_flags_ &= ~(1 << module); + } + + switch (module) { + case HW_MODULE_I2C: + if (!enable && bus_handle_) { + // 注意:I2C总线通常不建议完全关闭,可能影响多个设备 + ESP_LOGW(POWER_TAG, "I2C bus power control not recommended"); + } + break; + + case HW_MODULE_SDCARD: + if (enable && !is_sdcard_initialized_) { + ret = InitializeSdcard(); + } else if (!enable && is_sdcard_initialized_) { + // 卸载SD卡文件系统 + // 注意:需要确保没有打开的文件 + ESP_LOGW(POWER_TAG, "SD card power down requires file system cleanup"); + } + break; + + case HW_MODULE_LCD: + // LCD背光控制 + // LCD电源引脚控制(如果有) + break; + + case HW_MODULE_AUDIO: + // 音频编解码器电源控制 + // 需要与AudioPlayer协调 + break; + + case HW_MODULE_MOTOR: + // 步进电机驱动器电源控制 + // 电机睡眠模式 + break; + + case HW_MODULE_GYROSCOPE: + // 陀螺仪电源控制 + // 设置陀螺仪为低功耗模式 + break; + + case HW_MODULE_TOUCH: + // 触摸传感器电源控制 + // 设置触摸传感器为睡眠模式 + break; + + case HW_MODULE_RADAR: + // 毫米波雷达电源控制 + // 设置雷达为低功耗模式 + break; + + case HW_MODULE_IO_EXPAND: + // IO扩展板电源控制 + // 设置扩展板为低功耗模式 + break; + + default: + ESP_LOGE(POWER_TAG, "Unknown hardware module: %d", module); + return ESP_ERR_INVALID_ARG; + } + + if (ret == ESP_OK) { + ESP_LOGI(POWER_TAG, "Module %d power %s successfully", module, enable ? "enabled" : "disabled"); + } else { + ESP_LOGE(POWER_TAG, "Failed to %s module %d: %s", enable ? "enable" : "disable", module, esp_err_to_name(ret)); + } + + return ret; +} + + + diff --git a/main/02_physical/boards/board_v1_1_18/board_sweekar.h b/main/02_physical/boards/board_v1_1_18/board_sweekar.h new file mode 100644 index 0000000..55665ac --- /dev/null +++ b/main/02_physical/boards/board_v1_1_18/board_sweekar.h @@ -0,0 +1,181 @@ +#ifndef __BOARD_H__ +#define __BOARD_H__ +#include "config.h" +#include "io_expansion_board.h" +#include "stepper_motor.h" +#include "stepper_driver.h" +#include "i2c_bus.h" +#include "gyroscope.h" +#include "touch_sensor.h" +#include "base_board_control.h" +#include "esp_peripherals.h" +#include "periph_sdcard.h" +#include "esp_sleep.h" +#include "driver/rtc_io.h" + +/** + * @brief 功耗模式枚举 + */ +typedef enum { + POWER_MODE_NORMAL, // 正常运行模式,所有硬件可用 + POWER_MODE_IDLE, // 空闲模式,关闭非必要外设 + POWER_MODE_LIGHT_SLEEP, // 轻度睡眠,快速唤醒 + POWER_MODE_DEEP_SLEEP, // 深度睡眠,仅RTC运行 +} power_mode_t; + +/** + * @brief 硬件模块枚举,用于精细化电源管理 + */ +typedef enum { + HW_MODULE_I2C, // I2C总线 + HW_MODULE_SDCARD, // SD卡 + HW_MODULE_LCD, // LCD显示 + HW_MODULE_AUDIO, // 音频编解码器 + HW_MODULE_MOTOR, // 步进电机 + HW_MODULE_GYROSCOPE, // 陀螺仪 + HW_MODULE_TOUCH, // 触摸传感器 + HW_MODULE_RADAR, // 毫米波雷达 + HW_MODULE_IO_EXPAND, // IO扩展板 +} hardware_module_t; + +/** + * @brief 硬件板级管理器 + * + * 采用高内聚低耦合设计原则,统一管理所有硬件资源。 + * 提供统一的硬件初始化接口和资源访问,避免各模块重复初始化。 + */ +class BoardSweekar +{ +private: + i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄 + esp_periph_set_handle_t periph_set_ = nullptr; // 外设管理句柄 + bool is_sdcard_initialized_ = false; // SD卡初始化状态 + power_mode_t current_power_mode_ = POWER_MODE_NORMAL; // 当前功耗模式 + uint32_t power_state_flags_ = 0xFFFFFFFF; // 各模块电源状态位图(1为开启) + +public: + BoardSweekar(); + ~BoardSweekar(); + + static BoardSweekar* GetInstance(); + + // --- 语义化的高层 API:音频与功放控制 --- + // 开启或关闭外放功放 (PA),供上层 AudioActor/AudioPlayer 调用,屏蔽底层引脚实现 + void SetAudioAmplifier(bool enable); + + IOExpansionBoard io_expansion_; // IO扩展板对象 + Gyroscope gyroscope_; // 陀螺仪对象 + TouchSensor touch_sensor_; // 触摸传感器对象 + BaseBoardControl base_board_control_; // 底座控制对象 + StepperDriver* stepper_driver_ = nullptr; // 步进电机驱动对象 + + StepperDriver* GetStepperDriver() const { return stepper_driver_; } + + // 初始化步进电机 + void StepperMotorInit(void); + + // 初始化LCD IO引脚(消除与步进电机的耦合) + void LcdIoInit(void); + + // 初始化串口 + void MillimeterWaveRadarUartInit(void); + + //初始化毫米波雷达的中断引脚 + void MillimeterWaveRadarGpioInit(void); + + /** + * @brief 执行系统关机 + * 内部拉高/拉低 SHUTDOWN_CTRL_PIN 引脚切断电源 + */ + void SystemShutdown(void); + + // 初始化I2C总线 + esp_err_t I2CMasterInit(void); + + // 初始化VBAT toVBAT_5V引脚 + void VbatToVbat5vInit(void); + + // 初始化底座控制串口 + void BaseBoardControlInit(void); + + // 初始化SD卡(推荐使用统一的硬件初始化) + esp_err_t InitializeSdcard(void); + + // 获取SD卡初始化状态 + bool IsSdcardInitialized() const { return is_sdcard_initialized_; } + + // 获取外设管理句柄(供需要访问SD卡的模块使用) + esp_periph_set_handle_t GetPeriphSet() const { return periph_set_; } + + // 获取I2C总线句柄 + i2c_bus_handle_t GetBusHandle() const { return bus_handle_; } + + /** + * @brief 统一的硬件初始化接口 + * + * 按照依赖关系顺序初始化所有硬件资源,确保各模块可以安全使用。 + * 推荐在主程序启动时调用此函数,而不是分别调用各个初始化函数。 + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ + esp_err_t InitializeAllHardware(void); + + /** + * @brief 完整的统一硬件初始化接口(专为复杂应用优化) + * + * 包含所有必要外设的完整初始化,适用于demo5等复杂应用场景。 + * 这个函数会初始化:I2C总线、IO扩展板、SD卡、LCD IO、底座控制等。 + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ + esp_err_t InitializeAllHardwareComplete(void); + + /** + * @brief 针对特定应用的硬件初始化配置 + * + * 为不同类型的应用提供专门的初始化配置,优化启动流程。 + * + * @param app_type 应用类型(demo5、音频播放器、显示应用等) + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ + esp_err_t InitializeHardwareForApplication(int app_type); + + /** + * @brief 功耗管理接口 - 进入低功耗模式 + * + * 根据指定的功耗模式,关闭非必要硬件、设置GPIO为低功耗状态、 + * 调整时钟频率等。支持多种功耗模式以适应不同应用场景。 + * + * @param mode 功耗模式 + * @return esp_err_t 操作结果 + */ + esp_err_t EnterLowPowerMode(power_mode_t mode); + + /** + * @brief 功耗管理接口 - 退出低功耗模式 + * + * 从低功耗模式恢复,重新初始化必要的硬件资源。 + * + * @return esp_err_t 操作结果 + */ + esp_err_t ExitLowPowerMode(void); + + /** + * @brief 获取当前功耗模式 + * + * @return power_mode_t 当前功耗模式 + */ + power_mode_t GetPowerMode(void) const { return current_power_mode_; } + + /** + * @brief 设置硬件模块电源状态 + * + * 单独控制某个硬件模块的电源状态,用于精细化的功耗管理。 + * + * @param module 硬件模块 + * @param enable true为开启,false为关闭 + * @return esp_err_t 操作结果 + */ + esp_err_t SetModulePower(hardware_module_t module, bool enable); +}; +#endif diff --git a/main/02_physical/boards/board_v1_1_18/board_sweekar_complete_init.cc b/main/02_physical/boards/board_v1_1_18/board_sweekar_complete_init.cc new file mode 100644 index 0000000..52e9456 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_18/board_sweekar_complete_init.cc @@ -0,0 +1,200 @@ +/** + * @file board_sweekar_complete_init.cc + * @brief 完整的统一硬件初始化实现 + * + * 这个文件提供了完整的统一硬件初始化函数,包含所有必要的硬件初始化步骤。 + * 专为demo5等复杂应用场景设计。 + */ + +/** + * @brief 完整的统一硬件初始化接口(专为demo5优化) + * + * 按照依赖关系顺序初始化所有硬件资源: + * 1. I2C总线(最基础,其他设备依赖) + * 2. IO扩展板(控制其他外设) + * 3. SD卡(文件系统,供显示和音频使用) + * 4. LCD IO引脚(显示相关) + * 5. 底座控制串口(通信) + * 6. 底座控制模块(业务逻辑) + * 7. 其他外设(根据应用需求) + * + * @return esp_err_t 初始化结果,ESP_OK表示全部成功 + */ +esp_err_t BoardSweekar::InitializeAllHardwareComplete(void) +{ + static const char *HW_INIT_TAG = "HW_INIT_COMPLETE"; + esp_err_t ret; + + ESP_LOGI(HW_INIT_TAG, "Starting complete hardware initialization..."); + + // 1. 初始化I2C总线(最基础,其他设备依赖) + ret = I2CMasterInit(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret)); + return ret; + } + ESP_LOGI(HW_INIT_TAG, "✓ I2C master initialized"); + + // 2. 创建I2C读任务(IO扩展板需要) + io_expansion_.CreateI2cReadTask(); + ESP_LOGI(HW_INIT_TAG, "✓ I2C read task created"); + + // 3. 初始化SD卡(文件系统,供显示和音频使用) + ret = InitializeSdcard(); + if (ret != ESP_OK) { + ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret)); + // SD卡失败不是致命错误,继续初始化其他硬件 + ESP_LOGW(HW_INIT_TAG, "⚠ SD card initialization failed, but continuing with other hardware"); + } else { + ESP_LOGI(HW_INIT_TAG, "✓ SD card initialized"); + } + + // 4. 初始化LCD IO引脚(显示相关) + LcdIoInit(); + ESP_LOGI(HW_INIT_TAG, "✓ LCD IO pins initialized"); + + // 5. 初始化底座控制串口(demo5需要) + BaseBoardControlUartInit(); + ESP_LOGI(HW_INIT_TAG, "✓ Base board control UART initialized"); + + // 6. 初始化底座控制模块 + base_board_control_.Init(); + ESP_LOGI(HW_INIT_TAG, "✓ Base board control initialized"); + + // 7. 设置IO扩展板的PA控制模式(demo5需要) + io_expansion_.SetPaCtrlMode(true); + ESP_LOGI(HW_INIT_TAG, "✓ IO expansion PA control mode set"); + + // 8. 初始化 AUD_CTRL 引脚(如果定义了的话) +#ifdef AUD_CTRL_PIN + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = (1ULL << AUD_CTRL_PIN); + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + gpio_config(&io_conf); + // 拉高开机 + gpio_set_level(AUD_CTRL_PIN, 1); + ESP_LOGI(HW_INIT_TAG, "✓ AUD_CTRL pin initialized to HIGH"); +#endif + + // 9. 可选外设(根据具体应用需求启用) + // ESP_LOGI(HW_INIT_TAG, "Initializing optional peripherals..."); + // + // // 毫米波雷达(如需要) + // MillimeterWaveRadarUartInit(); + // MillimeterWaveRadarGpioInit(); + // ESP_LOGI(HW_INIT_TAG, "✓ Millimeter wave radar initialized"); + // + // // VBAT升压(如需要) + // VbatToVbat5vInit(); + // ESP_LOGI(HW_INIT_TAG, "✓ VBAT to 5V booster initialized"); + // + // // 步进电机(如需要) + // StepperMotorInit(); + // ESP_LOGI(HW_INIT_TAG, "✓ Stepper motor initialized"); + + ESP_LOGI(HW_INIT_TAG, "=== Complete hardware initialization finished successfully ==="); + return ESP_OK; +} + +/** + * @brief 针对特定应用的硬件初始化配置 + * + * 为不同类型的应用提供专门的初始化配置 + */ +esp_err_t BoardSweekar::InitializeHardwareForApplication(application_type_t app_type) { + static const char *APP_INIT_TAG = "APP_HW_INIT"; + + ESP_LOGI(APP_INIT_TAG, "Initializing hardware for application type: %d", app_type); + + // 基础硬件初始化(所有应用都需要) + esp_err_t ret = InitializeAllHardwareComplete(); + if (ret != ESP_OK) { + ESP_LOGE(APP_INIT_TAG, "Basic hardware initialization failed"); + return ret; + } + + switch (app_type) { + case APP_TYPE_DEMO5: // 宠物游戏demo + ESP_LOGI(APP_INIT_TAG, "Configuring for Demo5 (Pet Game)..."); + + // Demo5需要的额外初始化 + // 触摸传感器、陀螺仪、RGB LED等会在应用层初始化 + + ESP_LOGI(APP_INIT_TAG, "✓ Demo5 hardware configuration complete"); + break; + + case APP_TYPE_AUDIO_PLAYER: // 音频播放器 + ESP_LOGI(APP_INIT_TAG, "Configuring for Audio Player..."); + + // 音频应用需要确保音频编解码器正确初始化 + // 这部分通常在AudioPlayer类中处理 + + ESP_LOGI(APP_INIT_TAG, "✓ Audio player hardware configuration complete"); + break; + + case APP_TYPE_DISPLAY_ONLY: // 纯显示应用 + ESP_LOGI(APP_INIT_TAG, "Configuring for Display Only..."); + + // 显示应用需要确保LCD相关硬件正确配置 + // 这部分通常在Display类中处理 + + ESP_LOGI(APP_INIT_TAG, "✓ Display-only hardware configuration complete"); + break; + + case APP_TYPE_MINIMAL: // 最小化应用 + ESP_LOGI(APP_INIT_TAG, "Configuring for Minimal Application..."); + + // 最小化配置,只保留最基本的功能 + // 关闭非必要外设以节省功耗 + + ESP_LOGI(APP_INIT_TAG, "✓ Minimal hardware configuration complete"); + break; + + default: + ESP_LOGW(APP_INIT_TAG, "Unknown application type, using default configuration"); + break; + } + + return ESP_OK; +} + +/** + * @brief 硬件初始化状态报告 + * + * 提供详细的硬件初始化状态报告,便于调试和问题排查 + */ +void BoardSweekar::ReportHardwareStatus(void) { + static const char *STATUS_TAG = "HW_STATUS"; + + ESP_LOGI(STATUS_TAG, "=== Hardware Initialization Status Report ==="); + + // I2C总线状态 + ESP_LOGI(STATUS_TAG, "I2C Bus: %s", (bus_handle_ != nullptr) ? "✓ Initialized" : "✗ Not initialized"); + + // SD卡状态 + ESP_LOGI(STATUS_TAG, "SD Card: %s", (is_sdcard_initialized_) ? "✓ Initialized" : "✗ Not initialized"); + if (is_sdcard_initialized_) { + ESP_LOGI(STATUS_TAG, " Peripheral Set: %s", (periph_set_ != nullptr) ? "✓ Available" : "✗ Not available"); + } + + // IO扩展板状态 + ESP_LOGI(STATUS_TAG, "IO Expansion Board: %s", (io_expansion_.bus_handle_ != nullptr) ? "✓ Configured" : "✗ Not configured"); + + // 底座控制状态 + ESP_LOGI(STATUS_TAG, "Base Board Control: %s", (base_board_control_.GetUartPort() != 0) ? "✓ Initialized" : "✗ Not initialized"); + + // 功耗管理状态 + ESP_LOGI(STATUS_TAG, "Power Management: %s", (current_power_mode_ == POWER_MODE_NORMAL) ? "✓ Normal mode" : "⚠ Low power mode"); + ESP_LOGI(STATUS_TAG, " Current Mode: %d", current_power_mode_); + ESP_LOGI(STATUS_TAG, " Module Power States: 0x%08X", power_state_flags_); + + // 内存状态 + ESP_LOGI(STATUS_TAG, "Memory Status:"); + ESP_LOGI(STATUS_TAG, " Internal RAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + ESP_LOGI(STATUS_TAG, " PSRAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + + ESP_LOGI(STATUS_TAG, "=== End of Hardware Status Report ==="); +} \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_18/config.h b/main/02_physical/boards/board_v1_1_18/config.h new file mode 100644 index 0000000..c69e4e2 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_18/config.h @@ -0,0 +1,136 @@ +/* 定义引脚分配 */ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +/** + * @file config.h + * @brief 定义了引脚的分配。 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +#include "driver/gpio.h" +#include "driver/i2c_master.h" +#include "driver/i2s.h" +#include "esp_log.h" +#include "esp_rom_sys.h" // 用于 esp_rom_delay_us +#include "esp_timer.h" +#include "esp_mac.h" +#include "driver/ledc.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "driver/gptimer.h" +#include "esp_intr_alloc.h" +#include "driver/uart.h" +#include "esp_err.h" +#include "freertos/queue.h" +#include "soc/uart_reg.h" +#include "linear_motor.h" +#include "gyroscope.h" + +#define TAG_BOARD "SWEEKAR_ESP32" +/*I2C总线引脚定义*/ +#define I2C0_MASTER_PORT I2C_NUM_0 +#define I2C0_MASTER_SDA_IO GPIO_NUM_2 +#define I2C0_MASTER_SCL_IO GPIO_NUM_3 + +/* 步进电机配置 */ +#define STEPPER_STEP_IO GPIO_NUM_42 // 步进电机脉冲输入引脚 +#define STEPPER_TIMER_RES_HZ 1000000 // 步进电机定时器分辨率 1 MHz(1 us 步进) + +/* 定义屏幕驱动控制引脚 */ +#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚 +#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL +#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚 +#define ST7789_PIN_CS GPIO_NUM_46 // SPI片选引脚 +#define ST7789_PIN_BL GPIO_NUM_45 // 背光引脚 +#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚 +#define LCD_BL_ACTIVE_LEVEL 0 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS) + +#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数) +#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数) + +/* 毫米波雷达配置参数 */ +/* 定义毫米波雷达的中断引脚 */ +#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35 +// UART 配置参数 +#define RADAR_UART_NUM UART_NUM_1 // 使用 UART1 +#define UART_TX_PIN GPIO_NUM_40 // GPIO40 作为 TX(根据实际硬件连接调整) +#define UART_RX_PIN GPIO_NUM_39 // GPIO39 作为 RX +#define RADAR_BAUD_RATE 9600 // 雷达波特率 +#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小 + +/* IO扩展硬件配置常量 */ +#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000) +#define I2C_IO_EXPAND_SLAVE_ADDR 0x58 // AW9523BTQR器件地址,v1_1_13的addr1和addr0是0 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚 +#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值 +#define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚 + +/* 定义线性马达的I2C从机配置常量 */ +#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址 + +/* 定义陀螺仪的I2C从机配置常量 */ +#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址 +#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚 + +/* AW触摸芯片配置 */ +#define AW_TOUCH_IRQ_PIN GPIO_NUM_11 // AW触摸芯片中断引脚 +#define NFC_RST_PIN GPIO_NUM_12 // NFC复位引脚 +#define AUD_CTRL_PIN GPIO_NUM_13 // AUD_CTRL引脚 + +/* 原生触摸引脚配置 (v1.1.18已改为上述功能,保留定义需谨慎) */ +// 触摸按键数量配置 +#define TOUCH_BUTTON_NUM 3 +// 触摸通道定义 - 注意:v1.1.18如果不使用ESP32原生触摸,这些定义可能不再适用 +// 但为了兼容编译,可以保留或注释 +#define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11 (Now AW_IRQ) +#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12 (Now NFC_RST) +#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13 (Now AUD_CTRL) + +/* ES8311音频编解码器配置 (ESP-ADF兼容) */ +#define AUDIO_INPUT_SAMPLE_RATE 24000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 +#define AUDIO_INPUT_REFERENCE true + +/* I2S GPIO定义 */ +#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15 +#define AUDIO_I2S_GPIO_WS GPIO_NUM_4 +#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5 +#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6 +#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7 + +/* PA引脚定义 */ +#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC + +/* I2C配置 */ +#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2 +#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3 +#define AUDIO_CODEC_ES8311_ADDR 0x18 +#define AUDIO_CODEC_ES7210_ADDR 0x40 + +/* WS2812 RGB LED配置 */ +#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚 +#define WS2812_NUM_LEDS 2 // WS2812 LED数量 + +/* 创建VBAT to VBAT_5V */ +#define VBAT_5V_PIN GPIO_NUM_NC // VBAT_5V引脚 + +/* 定义按键的中断引脚 */ +#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚 +#define RIGHT_BUTTON_PIN GPIO_NUM_8 // 按键中断引脚 + +/* 底座控制命令串口配置 */ +#define BASE_BOARD_CTL_UART_PORT UART_NUM_0 +#define BASE_BOARD_CTL_UART_TX_PIN GPIO_NUM_43 +#define BASE_BOARD_CTL_UART_RX_PIN GPIO_NUM_44 +#define BASE_BOARD_CTL_UART_BAUDRATE 115200 +#define BASE_BOARD_CTL_UART_BUF_SIZE 256 + +/* 背光控制引脚配置 */ +#define BL_PIN GPIO_NUM_45 + +#endif // _BOARD_CONFIG_H_ diff --git a/main/02_physical/boards/board_v1_1_18/io_expansion_board.cc b/main/02_physical/boards/board_v1_1_18/io_expansion_board.cc new file mode 100644 index 0000000..bfe1679 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_18/io_expansion_board.cc @@ -0,0 +1,1040 @@ +#include "io_expansion_board.h" +#include "millimeter_wave_radar.h" +#include "photo_interrupter.h" +#include "adc_battery_monitor.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_check.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/idf_additions.h" +#include "freertos/portable.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_rom_sys.h" +/** + * @file io_expansion_board.cc + * @brief IO扩展板功能实现类,包含I2C通信、GPIO中断配置、外设控制等功能 + * @details 实现了IO扩展板的初始化(中断引脚、复位引脚)、寄存器读写、步进电机控制(细分模式、使能、方向、睡眠状态)、 + * LCD相关引脚控制(背光、复位、片选)、毫米波雷达中断引脚配置等功能,并提供I2C数据读取任务的创建与管理 + * @author zouyuhua + * @date 2025年8月7日 + * + */ + +/** + * @brief 构造函数 + */ +IOExpansionBoard::IOExpansionBoard() + : bus_handle_(nullptr), + device_addr_(0), + last_port0_state_(0), + last_port1_state_(0), + radar_last_state_(false), + i2c_task_event_group_(nullptr), + xI2CReadTaskHandle_(nullptr), + is_initialized_(false), + interrupt_gpio_(GPIO_NUM_NC), + reset_gpio_(GPIO_NUM_NC) +{ +} + +/** + * @brief 析构函数 + */ +IOExpansionBoard::~IOExpansionBoard() +{ + // 删除任务 + if (xI2CReadTaskHandle_) { + vTaskDelete(xI2CReadTaskHandle_); + } + + // if(pI2CReadTaskStackBuffer) { + // heap_caps_free(pI2CReadTaskStackBuffer); + // pI2CReadTaskStackBuffer = nullptr; + // } + + // if(pxI2CReadTaskBuffer) { + // vPortFree(pxI2CReadTaskBuffer); + // pxI2CReadTaskBuffer = nullptr; + // } + + // 删除事件组 + if (i2c_task_event_group_) { + vEventGroupDelete(i2c_task_event_group_); + } + + // 移除中断处理 + if (interrupt_gpio_ != GPIO_NUM_NC) { + gpio_isr_handler_remove(interrupt_gpio_); + } + + // 删除IO扩展板设备 + // 使用i2c_bus API时不需要手动删除设备句柄 + // bus_handle_由board_sweekar统一管理 +} + +/** + * @brief 静态中断处理函数 + */ +void IRAM_ATTR IOExpansionBoard::GpioIsrHandler(void* arg) +{ + IOExpansionBoard* instance = static_cast(arg); + if (!instance) return; + + // 调试:记录中断触发 + // ESP_EARLY_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "中断触发!"); // IRAM函数中不能使用普通日志 + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // 设置事件标志位 + if (instance->i2c_task_event_group_) { + xEventGroupSetBitsFromISR( + instance->i2c_task_event_group_, + BIT0, + &xHigherPriorityTaskWoken + ); + } + + // 触发上下文切换 + if (xHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); + } +} + +/** + * @brief 初始化GPIO中断检测 + */ +esp_err_t IOExpansionBoard::InterruptGpioInit(gpio_num_t gpio_num) +{ + // 配置IO扩展板中断引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_ANYEDGE; // 改为双沿触发,检测上升沿和下降沿 + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + // io_conf.pull_up_en = GPIO_PULLUP_DISABLE; + // io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE; + + + esp_err_t err = gpio_config(&io_conf); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + // 配置中断服务 + err = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3); + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断服务安装失败,错误码: 0x%x", err); + return err; + } + // 注册中断处理函数 + err = gpio_isr_handler_add(gpio_num, GpioIsrHandler, this); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断处理函数添加失败,错误码: 0x%x", err); + return err; + } + // 创建事件组 + i2c_task_event_group_ = xEventGroupCreate(); + if (!i2c_task_event_group_) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "事件组创建失败"); + return ESP_FAIL; + } + + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d中断初始化完成", gpio_num); + return ESP_OK; +} + +/** + * @brief 初始化硬件复位引脚 + * 设置为上拉,需要复位,需要输出低电平为20us的脉冲信号 + */ +esp_err_t IOExpansionBoard::ResetGpioInit(gpio_num_t gpio_num) +{ + reset_gpio_ = gpio_num; + + // 配置复位引脚 + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.pin_bit_mask = 1ULL << gpio_num; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + esp_err_t err = gpio_config(&io_conf); + gpio_set_level(gpio_num, 1); // 复位引脚拉高 + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d复位引脚初始化完成", gpio_num); + return err; + } +} + +/** + * @brief 计算Port0的字节值,用于配置输入还是输出模式(0为输出模式,1为输入模式) + * @return uint8_t 操作结果 + */ +uint8_t IOExpansionBoard::ByteCalculatePort0() +{ + uint8_t byte_val = 0x00; // 初始化为所有引脚为输出模式(0),然后根据配置设置为输入模式(1) + + // 输入模式配置:将对应位置位(1为输入模式) + if(RADAR_INTERRUPT_CONFIG == CONFIG_PORT0){ //雷达中断引脚 + byte_val |= (1 << RADAR_INTERRUPT_PIN); + } + if(START_PHOTO_INTERRUPTER_CONFIG == CONFIG_PORT0){ //起始光学传感器 + byte_val |= (1 << START_PHOTO_INTERRUPTER_PIN); + } + if(END_PHOTO_INTERRUPTER_PORT_CONFIG == CONFIG_PORT0){ //结束光学传感器 + byte_val |= (1 << END_PHOTO_INTERRUPTER_PIN); + } + if(BATTERY_FULL_CONFIG == CONFIG_PORT0){ //电池充满检测 + byte_val |= (1 << BATTERY_FULL_PIN); + } + if(BATTERY_CHRG_CONFIG == CONFIG_PORT0){ //电池充电检测 + byte_val |= (1 << BATTERY_CHRG_PIN); + } + + return byte_val; +} + +/** + * @brief 计算Port1的字节值,用于配置输入还是输出模式(0为输出模式,1为输入模式) + * @return uint8_t 操作结果 + */ +uint8_t IOExpansionBoard::ByteCalculatePort1() +{ + uint8_t byte_val = 0x00; // 初始化为所有引脚为输出模式(0),然后根据配置设置为输入模式(1) + + // 输入模式配置:将对应位置位(1为输入模式) + if(RADAR_INTERRUPT_CONFIG == CONFIG_PORT1){ //雷达中断引脚 + byte_val |= (1 << RADAR_INTERRUPT_PIN); + } + if(START_PHOTO_INTERRUPTER_CONFIG == CONFIG_PORT1){ //起始光学传感器 + byte_val |= (1 << START_PHOTO_INTERRUPTER_PIN); + } + if(END_PHOTO_INTERRUPTER_PORT_CONFIG == CONFIG_PORT1){ //结束光学传感器 + byte_val |= (1 << END_PHOTO_INTERRUPTER_PIN); + } + if(BATTERY_FULL_CONFIG == CONFIG_PORT1){ //电池充满检测 + byte_val |= (1 << BATTERY_FULL_PIN); + } + if(BATTERY_CHRG_CONFIG == CONFIG_PORT1){ //电池充电检测 + byte_val |= (1 << BATTERY_CHRG_PIN); + } + + return byte_val; +} + +/** + * @brief 复位IO扩展板 + */ +esp_err_t IOExpansionBoard::ResetIoExpand() +{ + if (reset_gpio_ == GPIO_NUM_NC) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位引脚未初始化"); + return ESP_ERR_INVALID_STATE; + } + + // 复位IO扩展板 + gpio_set_level(reset_gpio_, 0); + esp_rom_delay_us(30); + gpio_set_level(reset_gpio_, 1); + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "复位成功"); + } + return ESP_OK; +} + +/** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::IoexpandWriteReg(uint8_t reg_addr, uint8_t data) +{ + return i2c_bus_write_bytes(bus_handle_, device_addr_, ®_addr, 1, &data, 1); +} + +/** + * @brief 从寄存器读取数据 + * @param reg_addr 寄存器地址(如INPUT_PORT0、ID等) + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果(ESP_OK为成功) + */ +esp_err_t IOExpansionBoard::IoexpandReadReg(uint8_t reg_addr, uint8_t* data) +{ + if (data == nullptr){ // 检查输入参数有效性 + return ESP_ERR_INVALID_ARG; + } + + // 使用i2c_bus_read_bytes进行寄存器读取 + esp_err_t err = i2c_bus_read_bytes(bus_handle_, device_addr_, ®_addr, 1, data, 1); + if (err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "读取寄存器失败,错误码:0x%x", err); + return err; + } + + return ESP_OK; +} + +/** + * @brief 读取输入端口0寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::ReadInputPort0(uint8_t* data) +{ + return IoexpandReadReg(INPUT_PORT0, data); +} + +/** + * @brief 读取输入端口1寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ +esp_err_t IOExpansionBoard::ReadInputPort1(uint8_t* data) +{ + return IoexpandReadReg(INPUT_PORT1, data); +} + +//设置IO扩展板为输入模式或是输出模式 +/* +* 这里需要根据实际情况设置IO扩展板的模式,比如输入模式还是输出模式,以及各个引脚的配置。 +* P0_0 对应NFC_RST引脚,需要设置为输出模式,低电平有效。(待测) +* P0_1 对应USB_VBUS引脚,需要设置为输出模式,低电平有效。(待测) +* P0_2 对应BTN_RIGHT_EAR引脚,需要设置为输出模式,低电平有效。(待测) +* P0_3 暂时未使用。 +* P0_4 对应步进电机方向引脚,需要设置为输出模式,根据需求设置。(待测) +* P0_5 对应CHRG引脚(待测) +* P0_6 LCD_DC引脚,需要设置为输出模式,根据需求设置电平。(待测) +* P0_7 对应步进电机的使能引脚,需要设置为输出模式,根据需求设置。(待测) +* +* +* P1_0 对应EG800K_PWR。(待测) +* P1_1 对应LCD_RST,需要设置为输出模式,低电平有效。(待测) +* P1_2 对应LCD_CS,需要设置为输出模式,低电平有效。(待测) +* P1_3 暂时未使用。 +* P1_4 对应步进电机的细分模式M1引脚。(待测) +* P1_5 对应步进电机的细分模式M0引脚。(待测) +* P1_6 对应步进电机的睡眠引脚。(待测) +* P1_7 对应RADAR_O雷达的输出引脚。(待测) +* */ +esp_err_t IOExpansionBoard::IoexpandSetMode(void) +{ + uint8_t ctl_val; + //配置P0_0-P0_7的端口为推挽输出模式 + esp_err_t err = IoexpandReadReg(CTL, &ctl_val); + ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式 + err = IoexpandWriteReg(CTL, ctl_val); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功"); + } + + err = IoexpandWriteReg(CONFIG_PORT0, ByteCalculatePort0()); + + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err); + return err; + } + else{ + // 打印BytecalculatePort0()结果 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功, 0x%02X", ByteCalculatePort0()); + } + + err = IoexpandWriteReg(CONFIG_PORT1, ByteCalculatePort1()); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口失败,错误码:0x%x", err); + return err; + } + else{ + // 打印BytecalculatePort1()结果 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口成功, 0x%02X", ByteCalculatePort1()); + } + // 配置P0_0-P0_7的初始为高电平 + // 配置P1_0-P1_7的初始为高电平 + // P0_6(旧的LCD_BL, 0x40), P0_1(led_en, PMOS高侧驱动, 高电平关, 0x02) + err = IoexpandWriteReg(OUTPUT_PORT0, 0x42); // 0100 0010 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值成功"); + } + err = IoexpandWriteReg(OUTPUT_PORT1, 0x04); // 0000 0100 + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值成功"); + } + + + // AW9523B中断使能配置:0为使能中断,1为禁止中断 + // 使能P0_5(充电检测)和P1_3(充满检测)的中断 + uint8_t int_enable_port0 = 0x00; // 0x00 = 使能所有P0引脚中断 + uint8_t int_enable_port1 = 0x00; // 0x00 = 使能所有P1引脚中断 + + err = IoexpandWriteReg(INT_PORT0, int_enable_port0); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口中断使能失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口中断使能成功: 0x%02X (0=使能)", int_enable_port0); + } + + err = IoexpandWriteReg(INT_PORT1, int_enable_port1); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能失败,错误码:0x%x", err); + return err; + } + else{ + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能成功: 0x%02X (0=使能)", int_enable_port1); + } + + return ESP_OK; +} + +/** + * @brief 设置步进电机的细分模式 + */ +void IOExpansionBoard::SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin) +{ + uint8_t current_val; + switch (mode) { + case 1: //全步输出模式 低低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 2: //非圆 1/2 高低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val |= (1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 3: //1/4 步 低高电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val |= (1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + case 4: //1/8 步 高高电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val |= (1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val |= (1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + default: //全步输入模式 低低电平 + IoexpandReadReg(OUTPUT_PORT_m0, ¤t_val); + current_val &= ~(1 << m0_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m0, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + IoexpandReadReg(OUTPUT_PORT_m1, ¤t_val); + current_val &= ~(1 << m1_pin); + if(IoexpandWriteReg(OUTPUT_PORT_m1, current_val) != ESP_OK){ + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败"); + } + break; + } +} + +/** + * @brief 设置步进电机的使能 + */ +esp_err_t IOExpansionBoard::SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin) +{ + uint8_t current_val; + if(enable){ + // 进入工作状态mode + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << enable_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << enable_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} +/** + * @brief 设置步进电机运行方向 + */ +esp_err_t IOExpansionBoard::StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin) +{ + uint8_t current_val; + if(dir){ + // 方向为正转 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/** + * @brief 设置步进电机是否进入睡眠或者工作状态(高电平进入工作状态,低电平进入睡眠状态) + */ +esp_err_t IOExpansionBoard::SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin) +{ + uint8_t current_val; + if(mode){ + // 进入工作状态mode + // ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入工作状态"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "电机睡眠输出寄存器: 0x%x", current_val); + current_val |= (1 << nsleep_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置电机睡眠输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入睡眠状态 + // ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入睡眠状态"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "电机睡眠输出寄存器: 0x%x", current_val); + current_val &= ~(1 << nsleep_pin); + // ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置电机睡眠输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + + +/*********************************************IO扩展板LCD引脚配置参数***********************************************/ +/** + * @brief 设置 LCD_BL引脚电平(高电平为命令模式,低电平为数据模式) + */ +esp_err_t IOExpansionBoard::SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin) +{ + uint8_t current_val; + if(mode){ + // 进入命令模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val |= (1 << bl_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入数据模式 + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + current_val &= ~(1 << bl_pin); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/** + * @brief 设置 LED_EN 引脚电平(用于控制LCD背光/LED灯电源) + * @param mode true:开启(低电平), false:关闭(高电平) + */ +esp_err_t IOExpansionBoard::SetLedEnMode(bool mode) +{ + uint8_t current_val; + esp_err_t err = IoexpandReadReg(LED_EN_PORT, ¤t_val); + if (err != ESP_OK) return err; + + if(mode){ + // 开启 (PMOS低电平有效) + current_val &= ~(1 << LED_EN_PIN); + } + else{ + // 关闭 (PMOS高电平无效) + current_val |= (1 << LED_EN_PIN); + } + return IoexpandWriteReg(LED_EN_PORT, current_val); +} + +/** + * @brief 设置 LCD_RST引脚电平(高电平为复位模式,低电平为工作模式) + */ +esp_err_t IOExpansionBoard::SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t reset_pin) +{ + uint8_t current_val; + if(mode){ + // 进入复位模式 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入复位模式"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "LCD复位输出寄存器: 0x%x", current_val); + current_val |= (1 << reset_pin); + //打印设置后的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置LCD复位输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } + else{ + // 进入工作模式 + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "进入工作模式"); + IoexpandReadReg(OUTPUT_PORT, ¤t_val); + //打印读出来的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "LCD复位输出寄存器: 0x%x", current_val); + current_val &= ~(1 << reset_pin); + //打印设置后的寄存器值 + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置LCD复位输出寄存器: 0x%x", current_val); + return IoexpandWriteReg(OUTPUT_PORT, current_val); + } +} + +/*********************************************IO扩展板的输入引脚配置以及中断引脚定义***********************************************/ +/** + * @brief 设置 毫米波雷达的中断引脚 + */ +esp_err_t IOExpansionBoard::SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin) +{ + uint8_t current_val; + if(mode){ + // 进入输入模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + current_val |= (1 << interrupt_pin); + return IoexpandWriteReg(INPUT_PORT, current_val); + } + else{ + // 进入输出模式 + IoexpandReadReg(INPUT_PORT, ¤t_val); + current_val &= ~(1 << interrupt_pin); + return IoexpandWriteReg(INPUT_PORT, current_val); + } +} + +/** + * @brief 设置 PA_CTRL引脚电平 + */ +esp_err_t IOExpansionBoard::SetPaCtrlMode(bool mode) +{ + uint8_t current_val; + if(mode){ + // 进入高电平状态 + ESP_LOGI("io_ex:", "read reg"); + IoexpandReadReg(PA_CTRL_PORT, ¤t_val); + current_val |= (1 << PA_CTRL_PIN); + return IoexpandWriteReg(PA_CTRL_PORT, current_val); + } + else{ + // 进入低电平状态 + IoexpandReadReg(PA_CTRL_PORT, ¤t_val); + current_val &= ~(1 << PA_CTRL_PIN); + return IoexpandWriteReg(PA_CTRL_PORT, current_val); + } +} + + + +/** + * @brief I2C数据读取任务主体 + */ +void IOExpansionBoard::I2cReadTask(void* pvParameters) +{ + IOExpansionBoard* instance = static_cast(pvParameters); + if (!instance) { + vTaskDelete(nullptr); + return; + } + // 初始化复位引脚 + esp_err_t err = instance->ResetGpioInit(IO_EXPAND_RSTN); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO复位初始化失败"); + } + + // 执行硬件复位 - 这是解决中断引脚持续拉低的关键 + err = instance->ResetIoExpand(); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板硬件复位失败"); + } else { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板硬件复位成功"); + + // 检查复位后的中断引脚状态 + int interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "复位后中断引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + } + + // 初始化IO扩展板子的中断引脚 + err = instance->InterruptGpioInit(GPIO_INPUT_PIN_SEL); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断初始化失败"); + } + // 设置IO扩展板模式 - 复位后必须重新配置寄存器! + err = instance->IoexpandSetMode(); + if (err != ESP_OK) { + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板模式配置失败"); + } else { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板模式配置成功"); + } + // 设置LCD屏幕复位引脚 + err = instance->SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功"); + } + // 设置LCD屏幕复位引脚为低电平 + err = instance->SetLcdResetMode(LCD_RST_LOW, LCD_RST_PORT, LCD_RST_PIN); + if(err != ESP_OK){ + ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败"); + } + else{ + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功"); + } + + uint8_t current_val_port0_ = 0,current_val_port1_ = 0,current_temp_ = 0; + for (;;) { + // 等待中断事件触发 + if (instance->i2c_task_event_group_) { + xEventGroupWaitBits(instance->i2c_task_event_group_, BIT0, pdTRUE, pdFALSE, portMAX_DELAY); + } + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "IO扩展板中断触发"); + + // 检查中断触发时的引脚状态 + int interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "中断触发时引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + + // AW9523B中断处理说明(根据数据手册): + // 1. 当输入引脚状态变化时,AW9523B会拉低INT引脚(连接到ESP32的GPIO10) + // 2. 通过读取输入端口寄存器(00H, 01H)来清除对应端口的中断 + // 3. 无独立的中断状态寄存器,需要通过输入电平变化来判断中断源 + // 4. 读取INPUT_PORT0 (00H) 清除P0口中断,读取INPUT_PORT1 (01H) 清除P1口中断 + + // 一次性读取两个端口的输入寄存器,避免重复读取和错误的OR操作 + instance->IoexpandReadReg(INPUT_PORT0, ¤t_val_port0_); + instance->IoexpandReadReg(INPUT_PORT1, ¤t_val_port1_); + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "读取端口状态 - Port0: 0x%02X, Port1: 0x%02X", current_val_port0_, current_val_port1_); + + // 检查读取寄存器后中断引脚是否被清除(应该恢复高电平) + interrupt_level = gpio_get_level(GPIO_INPUT_PIN_SEL); + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "读取寄存器后中断引脚状态: %s (0=低电平, 1=高电平)", + interrupt_level ? "高电平" : "低电平"); + + //判断是否有中断来自雷达引脚 + if((RADAR_INTERRUPT_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << RADAR_INTERRUPT_PIN))){ + // 检查雷达引脚状态是否发生了变化,避免重复触发 + bool current_radar_state = (current_val_port0_ & (1 << RADAR_INTERRUPT_PIN)) != 0; + if (current_radar_state != instance->radar_last_state_) { + instance->radar_last_state_ = current_radar_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用毫米波雷达回调函数 + if (instance->radar_) { + instance->radar_->TriggerRadarDetectCallback(); + } + // 调用雷达回调函数(新接口) + if (instance->radar_callback_) { + instance->radar_callback_(); + } + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((RADAR_INTERRUPT_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << RADAR_INTERRUPT_PIN))){ + // 检查雷达引脚状态是否发生了变化,避免重复触发 + bool current_radar_state = (current_val_port1_ & (1 << RADAR_INTERRUPT_PIN)) != 0; + if (current_radar_state != instance->radar_last_state_) { + instance->radar_last_state_ = current_radar_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚1\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用毫米波雷达回调函数 + if (instance->radar_) { + instance->radar_->TriggerRadarDetectCallback(); + } + // 调用雷达回调函数(新接口) + if (instance->radar_callback_) { + instance->radar_callback_(); + } + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + // else{ + // ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "未检测到雷达引脚中断\n"); + // } + + //判断是否有中断来自初始光学传感器引脚 + if((START_PHOTO_INTERRUPTER_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << START_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port0_ & (1 << START_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port0_state_ & (1 << START_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自初始光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用初始光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerStartCallback(); + } + // 调用光学传感器开始回调函数(新接口) + if (instance->photo_start_callback_) { + instance->photo_start_callback_(); + } + // 更新状态 + instance->last_port0_state_ = current_val_port0_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((START_PHOTO_INTERRUPTER_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << START_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port1_ & (1 << START_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port1_state_ & (1 << START_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自初始光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用初始光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerStartCallback(); + } + // 调用光学传感器开始回调函数(新接口) + if (instance->photo_start_callback_) { + instance->photo_start_callback_(); + } + // 更新状态 + instance->last_port1_state_ = current_val_port1_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + // else{ + // // ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "未检测到初始光学传感器引脚中断\n"); + // } + + //判断是否有中断来自结束光学传感器引脚 + if((END_PHOTO_INTERRUPTER_INPUT == INPUT_PORT0) && (current_val_port0_ & (1 << END_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port0_ & (1 << END_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port0_state_ & (1 << END_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自结束光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + // 调用结束光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerEndCallback(); + } + // 调用光学传感器结束回调函数(新接口) + if (instance->photo_end_callback_) { + instance->photo_end_callback_(); + } + // 更新状态 + instance->last_port0_state_ = current_val_port0_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + } + } + else if((END_PHOTO_INTERRUPTER_INPUT == INPUT_PORT1) && (current_val_port1_ & (1 << END_PHOTO_INTERRUPTER_PIN))){ + bool current_photo_state = (current_val_port1_ & (1 << END_PHOTO_INTERRUPTER_PIN)) != 0; + uint8_t old_photo_state = instance->last_port1_state_ & (1 << END_PHOTO_INTERRUPTER_PIN); + if ((current_photo_state ? 1 : 0) != (old_photo_state ? 1 : 0)) { + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自结束光学传感器引脚\n"); + // 读取输入寄存器以清除中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + // 调用结束光学传感器回调函数 + if (instance->photo_interrupter_) { + instance->photo_interrupter_->TriggerEndCallback(); + } + // 调用光学传感器结束回调函数(新接口) + if (instance->photo_end_callback_) { + instance->photo_end_callback_(); + } + // 更新状态 + instance->last_port1_state_ = current_val_port1_; + } else { + // 状态未变化,仍读取寄存器以清除可能的中断标志 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + } + } + + //CHRG引脚充电前为高电平 充电中为低电平 充满电为高电平 + //FULL未充满为高电平 充满电为低电平 + //判断是否有中断来自电池充电引脚 + //根据配置:BATTERY_CHRG_INPUT = INPUT_PORT0, BATTERY_FULL_INPUT = INPUT_PORT1 + + // AW9523B没有独立的中断状态寄存器,需要通过比较前后状态变化来判断中断源 + // 由于读取输入端口会清除中断,我们需要先保存当前状态,然后与上次状态比较 + + //获取当前电池状态 + bool current_charging_state = !(current_val_port0_ & (1 << BATTERY_CHRG_PIN)); // CHRG低电平表示充电中 + bool current_full_state = !(current_val_port1_ & (1 << BATTERY_FULL_PIN)); // FULL低电平表示已充满 + + // 详细的调试信息 + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - Port0: 0x%02X, Port1: 0x%02X", current_val_port0_, current_val_port1_); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - CHRG_PIN: %d (bit %d), FULL_PIN: %d (bit %d)", + (current_val_port0_ & (1 << BATTERY_CHRG_PIN)) ? 1 : 0, BATTERY_CHRG_PIN, + (current_val_port1_ & (1 << BATTERY_FULL_PIN)) ? 1 : 0, BATTERY_FULL_PIN); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - 充电状态: %s, 充满状态: %s", + current_charging_state ? "充电中" : "未充电", + current_full_state ? "已充满" : "未充满"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "电池状态检测 - 上次充电状态: %s, 上次充满状态: %s", + instance->battery_charging_last_state_ ? "充电中" : "未充电", + instance->battery_full_last_state_ ? "已充满" : "未充满"); + + //检查充电状态是否发生变化 + if (current_charging_state != instance->battery_charging_last_state_) { + instance->battery_charging_last_state_ = current_charging_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "电池充电状态变化: %s", current_charging_state ? "充电中" : "未充电"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "充电状态变化详情 - 从 %s 到 %s", + instance->battery_charging_last_state_ ? "未充电" : "充电中", + current_charging_state ? "充电中" : "未充电"); + + if (current_charging_state) { + // 进入充电状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到开始充电"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerChrgCallback(); + } + if (instance->battery_charging_callback_) { + instance->battery_charging_callback_(); + } + } else { + // 退出充电状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到停止充电"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerNotChrgCallback(); + } + if (instance->battery_not_charging_callback_) { + instance->battery_not_charging_callback_(); + } + } + } + + //检查充满状态是否发生变化 + if (current_full_state != instance->battery_full_last_state_) { + instance->battery_full_last_state_ = current_full_state; + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "电池充满状态变化: %s", current_full_state ? "已充满" : "未充满"); + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "充满状态变化详情 - 从 %s 到 %s", + instance->battery_full_last_state_ ? "未充满" : "已充满", + current_full_state ? "已充满" : "未充满"); + + if (current_full_state) { + // 进入充满状态 + ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到电池已充满"); + if (instance->battery_monitor_) { + instance->battery_monitor_->TriggerFullCallback(); + } + if (instance->battery_full_callback_) { + instance->battery_full_callback_(); + } + } + + } + + // 根据AW9523B数据手册:读取输入端口寄存器清除对应端口的中断 + // 读取INPUT_PORT0 (00H) 清除P0口中断,读取INPUT_PORT1 (01H) 清除P1口中断 + uint8_t temp_input_val; + instance->IoexpandReadReg(INPUT_PORT0, &temp_input_val); + instance->IoexpandReadReg(INPUT_PORT1, &temp_input_val); + + ESP_LOGD(TAG_GPIO_IO_EXPAND_DETECT, "中断处理完成,已读取输入端口寄存器清除中断标志"); + } +} + + +/** + * @brief 创建I2C数据读取任务 + */ +void IOExpansionBoard::CreateI2cReadTask() +{ + printf("创建I2C读取任务之前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之前:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + if (xI2CReadTaskHandle_) { + return; // 任务已创建 + } + + xTaskCreateWithCaps( + I2cReadTask, + "i2c_read_task", + I2C_TASK_STACK, + this, + I2C_TASK_PRIORITY, + &xI2CReadTaskHandle_, + MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT + ); + + if (xI2CReadTaskHandle_ == NULL) { + ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to create static I2C read task"); + } else { + ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static I2C read task created successfully"); + } + printf("创建I2C读取任务之后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("创建I2C读取任务之后:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); +} + +/** + * @brief 启动I2C任务 (整合初始化和任务创建) + */ +esp_err_t IOExpansionBoard::StartTask() +{ + // 再创建任务 + if (!xI2CReadTaskHandle_) { + CreateI2cReadTask(); + } + return ESP_OK; +} diff --git a/main/02_physical/boards/board_v1_1_18/io_expansion_board.h b/main/02_physical/boards/board_v1_1_18/io_expansion_board.h new file mode 100644 index 0000000..2697e39 --- /dev/null +++ b/main/02_physical/boards/board_v1_1_18/io_expansion_board.h @@ -0,0 +1,432 @@ +#ifndef IO_EXPANSION_BOARD_H +#define IO_EXPANSION_BOARD_H + +#include +#include +#include +#include +#include +#include +#include "i2c_bus.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include +#include +#include +#include +#include +#include +#include +#include "esp_err.h" +#include "config.h" +#include "portmacro.h" + +// 前向声明,避免循环引用 +class MillimeterWaveRadar; +class PhotoInterrupter; +class AdcBatteryMonitor; + +// 回调函数类型定义 +typedef std::function RadarCallback; +typedef std::function PhotoInterrupterStartCallback; +typedef std::function PhotoInterrupterEndCallback; +typedef std::function BatteryChargingCallback; +typedef std::function BatteryFullCallback; +typedef std::function BatteryNotChargingCallback; + +/* 寄存器地址 */ +#define INPUT_PORT0 0x00 // 输入端口0寄存器 +#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取) +#define OUTPUT_PORT0 0x02 // 输出端口0寄存器 +#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平 +#define CONFIG_PORT0 0x04 // 配置端口0寄存器 +#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式 +#define INT_PORT0 0x06 // 中断端口0寄存器 +#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的) +#define CTL 0x11 // 全局控制寄存器 +#define ID 0x23 // 芯片ID寄存器(0x23) + +/***********************************IO扩展板电机引脚配置参数*************************************/ +/* 设置步进电机方向 */ +#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转 +#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转 +#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4 +#define STEPPER_MOTOR_DIR_CONFIG CONFIG_PORT0 //步进电机方向引脚配置在P0_4 + +/* 设置步进电机细分模式 */ +#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5 +#define STEPPER_MOTOR_M0_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define STEPPER_MOTOR_M0_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_5 + +#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4 +#define STEPPER_MOTOR_M1_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define STEPPER_MOTOR_M1_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_4 + +/* 设置步进电机睡眠引脚 */ +#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式 +#define STEPPER_MOTOR_WORK true //步进电机进入工作模式 +#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6 +#define STEPPER_MOTOR_SLEEP_CONFIG CONFIG_PORT1 //步进电机睡眠引脚配置在P1_6 +#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 + +/* 设置电机的使能引脚 */ +#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7 +#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +#define STEPPER_MOTOR_ENABLE_CONFIG CONFIG_PORT0 //电机使能引脚配置在P0_7 +#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平 +#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平 + +/* 设置毫米波雷达对应IO扩展板的中断引脚 */ +#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7 +#define RADAR_INTERRUPT_CONFIG CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口 +#define RADAR_INTERRUPT_INPUT INPUT_PORT1 //毫米波雷达中断引脚输入状态检测在INPUT_PORT1 +#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态 +#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态 +/* 任务配置常量 */ +#define WRITE_BUF_SIZE 2 // I2C单次写入字节数 +#define READ_BUF_SIZE 2 // I2C单次读取字节数 +#define I2C_TASK_PRIORITY 2 // 任务优先级(中等) +#define I2C_TASK_STACK 4096 // 任务栈大小(4KB) + +// 光学传感器引脚定义 +#define START_PHOTO_INTERRUPTER_PIN 2 // 光学传感器引脚(P0_2) +#define START_PHOTO_INTERRUPTER_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口 +#define START_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0 +#define START_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平 +#define START_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平 + +#define END_PHOTO_INTERRUPTER_PIN 3 // 光学传感器引脚(P0_3) +#define END_PHOTO_INTERRUPTER_PORT_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口 +#define END_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0 +#define END_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平 +#define END_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平 + +/***********************************IO扩展板LCD引脚配置参数*************************************/ +// /* 设置LCD的BL引脚 */ +// #define LCD_BL_PIN 6 //LCD背光引脚对应IO扩展板引脚P0_6 +// #define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0 +// #define LCD_BL_CONFIG CONFIG_PORT0 //LCD背光引脚配置在P0_6 +// #define LCD_BL_HIGH true //LCD背光引脚状态为高电平 +// #define LCD_BL_LOW false //LCD背光引脚状态为低电平 + +/* 设置LED_EN (LCD背光/LED控制)引脚, PMOS高侧驱动 */ +#define LED_EN_PIN 1 //LED_EN对应IO扩展板引脚P0_1 +#define LED_EN_PORT OUTPUT_PORT0 //挂载在输出端口OUTPUT_PORT0 +#define LED_EN_CONFIG CONFIG_PORT0 //配置在P0_1 +#define LED_EN_OFF true //高电平关(PMOS) +#define LED_EN_ON false //低电平开(PMOS) + +/* 设置LCD的RST引脚 */ +#define LCD_RST_PIN 1 //LCD复位引脚对应IO扩展板引脚P1_1 +#define LCD_RST_CONFIG CONFIG_PORT1 //LCD复位引脚配置在P1_1 +#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define LCD_RST_HIGH true //LCD复位引脚状态为高电平 +#define LCD_RST_LOW false //LCD复位引脚状态为低电平 + +/* 设置PA控制引脚 */ +#define PA_CTRL_PIN 2 //PA控制引脚对应IO扩展板引脚P1_2 +#define PA_CTRL_CONFIG CONFIG_PORT1 //PA控制引脚配置在P1_2 +#define PA_CTRL_PORT OUTPUT_PORT1 //PA控制引脚挂载在IO扩展板的输出端口OUTPUT_PORT1 +#define PA_CTRL_HIGH true //PA控制引脚状态为高电平 +#define PA_CTRL_LOW false //PA控制引脚状态为低电平 + +// 电池充电检测引脚定义 +#define BATTERY_FULL_INPUT INPUT_PORT1 // 电池充满检测引脚挂载在IO扩展板的输入端口 +#define BATTERY_FULL_PIN 3 // 电池充满检测引脚对应IO扩展板引脚P1_3 +#define BATTERY_FULL_CONFIG CONFIG_PORT1 // 电池充满检测引脚配置在P1_3 + +#define BATTERY_CHRG_INPUT INPUT_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口 +#define BATTERY_CHRG_PIN 5 // 充电检测引脚(P0_5) +#define BATTERY_CHRG_CONFIG CONFIG_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口 + +#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签 +#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签 + +// GPIO引脚定义 +#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚 +// #define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚 + +/** + * @class IOExpansionBoard + * @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作 + */ +class IOExpansionBoard +{ +public: + /** + * @brief 构造函数 + */ + IOExpansionBoard(); + + /** + * @brief 设置毫米波雷达指针 + * @param radar 毫米波雷达对象指针 + */ + void SetRadar(MillimeterWaveRadar* radar) { radar_ = radar; }; + + /** + * @brief 设置限位开关指针 + * @param photo_interrupter 限位开关对象指针 + */ + void setPhotoInterrupter(PhotoInterrupter* photo_interrupter) { photo_interrupter_ = photo_interrupter; }; + + /** + * @brief 设置电池监控器指针 + * @param battery_monitor 电池监控器对象指针 + */ + void setBatteryMonitor(AdcBatteryMonitor* battery_monitor) { battery_monitor_ = battery_monitor; }; + + /** + * @brief 析构函数 + */ + ~IOExpansionBoard(); + + /** + * @brief 初始化GPIO中断检测 + * @param gpio_num 中断引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t InterruptGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetGpioInit(gpio_num_t gpio_num); + + /** + * @brief 初始化IO扩展板复位引脚 + * @param gpio_num 复位引脚编号 + * @return esp_err_t 初始化结果 + */ + esp_err_t ResetIoExpand(); + + /** + * @brief 初始化I2C主机通信 + * @return esp_err_t 初始化结果 + */ + // esp_err_t IoExpansionI2cInit(); + + /** + * @brief 创建I2C数据读取任务 + */ + void CreateI2cReadTask(); + + /** + * @brief 启动I2C任务(整合初始化和任务创建) + * @return esp_err_t 操作结果 + */ + esp_err_t StartTask(); + + /** + * @brief 写寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要写入的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data); + + /** + * @brief 读寄存器数据 + * @param reg_addr 寄存器地址 + * @param data 要读出的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data); + + /** + * @brief 读取输入端口0寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t ReadInputPort0(uint8_t *data); + + /** + * @brief 读取输入端口1寄存器数据 + * @param data 输出参数,用于存储读取到的数据 + * @return esp_err_t 操作结果 + */ + esp_err_t ReadInputPort1(uint8_t *data); + + // /** + // * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断 + // * @param reg_addr 寄存器地址 + // * @return esp_err_t 操作结果 + // */ + // esp_err_t SetInterruptStatus(bool status); + + /** + * @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平 + * @return esp_err_t 操作结果 + */ + esp_err_t IoexpandSetMode(); + + /** + * @brief 设置步进电机的细分模式 + * @param mode 模式:1/2/4/8/16/32/64 + * @return esp_err_t 操作结果 + */ + void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin); + + /** + * @brief 设置步进电机的方向 + * @param dir 方向 + * @param OUTPUT_PORT 输出端口 + * @param pin 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin); + + /** + * @brief 设置步进电机的睡眠模式 + * @param 是否进入睡眠模式 + * @param 输出端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin); + + /** + * @brief 设置步进电机的使能引脚状态 + * @param 使能状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin); + + /** + * @brief 设置LCD的BL引脚状态 + * @param BL状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin); + + /** + * @brief 设置 LED_EN 引脚电平(用于控制LCD背光/LED灯电源) + * @param mode true:开启(低电平), false:关闭(高电平) + */ + esp_err_t SetLedEnMode(bool mode); + + /** + * @brief 设置LCD的RST引脚状态 + * @param RST状态 + * @return esp_err_t 操作结果 + */ + esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin); + + /** + * @brief 设置PA控制引脚状态 + * @param mode PA_CTRL状态(true为高电平,false为低电平) + * @return esp_err_t 操作结果 + */ + esp_err_t SetPaCtrlMode(bool mode); + + /** + * @brief 设置雷达中断引脚 + * @param 毫米波雷达的中断引脚模式 + * @param 输入端口 + * @param 引脚号 + * @return esp_err_t 操作结果 + */ + esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin); + + /** + * @brief 计算Port0的字节值 + * @return uint8_t 操作结果 + */ + uint8_t ByteCalculatePort0(); + + /** + * @brief 计算Port1的字节值 + * @return uint8_t 操作结果 + */ + uint8_t ByteCalculatePort1(); + + /** + * @brief 设置雷达中断回调函数 + * @param callback 雷达中断回调函数 + */ + void SetRadarCallback(RadarCallback callback) { radar_callback_ = callback; } + + /** + * @brief 设置光学传感器开始中断回调函数 + * @param callback 光学传感器开始中断回调函数 + */ + void SetPhotoInterrupterStartCallback(PhotoInterrupterStartCallback callback) { photo_start_callback_ = callback; } + + /** + * @brief 设置光学传感器结束中断回调函数 + * @param callback 光学传感器结束中断回调函数 + */ + void SetPhotoInterrupterEndCallback(PhotoInterrupterEndCallback callback) { photo_end_callback_ = callback; } + + /** + * @brief 设置电池充电中断回调函数 + * @param callback 电池充电中断回调函数 + */ + void SetBatteryChargingCallback(BatteryChargingCallback callback) { battery_charging_callback_ = callback; } + + /** + * @brief 设置电池充满中断回调函数 + * @param callback 电池充满中断回调函数 + */ + void SetBatteryFullCallback(BatteryFullCallback callback) { battery_full_callback_ = callback; } + + /** + * @brief 设置电池非充电中断回调函数 + * @param callback 电池非充电中断回调函数 + */ + void SetBatteryNotChargingCallback(BatteryNotChargingCallback callback) { battery_not_charging_callback_ = callback; } + + // 公共成员变量 + i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄 + uint8_t device_addr_; // I2C设备地址 + +private: + // 静态成员函数 + MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调 + PhotoInterrupter* photo_interrupter_ = nullptr; // 限位开关指针,用于触发回调 + AdcBatteryMonitor* battery_monitor_ = nullptr; // 电池监控器指针,用于触发回调 + static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数 + static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数 + + // 成员变量用于状态跟踪 + uint8_t last_port0_state_ = 0; // 上次检测到的Port0状态 + uint8_t last_port1_state_ = 0; // 上次检测到的Port1状态 + bool radar_last_state_ = false; // 雷达引脚上一次的状态 + bool battery_charging_last_state_ = false; // 电池充电状态上一次的状态 + bool battery_full_last_state_ = false; // 电池充满状态上一次的状态 + + // 回调函数成员变量 + RadarCallback radar_callback_ = nullptr; + PhotoInterrupterStartCallback photo_start_callback_ = nullptr; + PhotoInterrupterEndCallback photo_end_callback_ = nullptr; + BatteryChargingCallback battery_charging_callback_ = nullptr; + BatteryFullCallback battery_full_callback_ = nullptr; + BatteryNotChargingCallback battery_not_charging_callback_ = nullptr; + + // PhotoInterrupter* photo_interrupter_ = nullptr; // 光学传感器指针,用于触发回调 + // /** + // * @brief 分配静态任务所需的内存 + // * @return bool 分配是否成功 + // */ + // bool AllocateStaticTaskMemory(); + + // /** + // * @brief 释放静态任务分配的内存 + // */ + // void FreeStaticTaskMemory(); + + // 实例成员变量 + EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组 + TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄 + bool is_initialized_ = false; // 初始化状态标记(新增) + gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚 + gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚 + + // StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM) + // StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM) +}; + +#endif \ No newline at end of file diff --git a/main/02_physical/boards/board_v1_1_18/power_management_config.h b/main/02_physical/boards/board_v1_1_18/power_management_config.h new file mode 100644 index 0000000..da609fb --- /dev/null +++ b/main/02_physical/boards/board_v1_1_18/power_management_config.h @@ -0,0 +1,178 @@ +/** + * @file power_management_config.h + * @brief 功耗管理配置和策略定义 + * @author Embedded Software Expert + * @date 2025年1月 + * + * 这个文件定义了功耗管理的配置参数、策略和优化建议, + * 为系统提供灵活的功耗管理方案。 + */ + +#ifndef POWER_MANAGEMENT_CONFIG_H +#define POWER_MANAGEMENT_CONFIG_H + +#include "esp_sleep.h" +#include "driver/rtc_io.h" +#include "esp32/rom/rtc.h" + +/** + * @brief 功耗管理配置结构体 + */ +typedef struct { + // 睡眠模式配置 + uint64_t light_sleep_duration_us; // 轻度睡眠持续时间(微秒) + uint64_t deep_sleep_duration_us; // 深度睡眠持续时间(微秒) + + // 唤醒源配置 + bool enable_timer_wakeup; // 启用定时器唤醒 + bool enable_gpio_wakeup; // 启用GPIO唤醒 + bool enable_touch_wakeup; // 启用触摸唤醒 + gpio_num_t wakeup_gpio_num; // 唤醒GPIO编号 + int wakeup_level; // 唤醒电平(0或1) + + // 功耗优化配置 + bool disable_bt_in_sleep; // 睡眠时关闭蓝牙 + bool disable_wifi_in_sleep; // 睡眠时关闭WiFi + bool reduce_cpu_frequency; // 降低CPU频率 + uint32_t cpu_frequency_hz; // CPU频率(Hz) + + // 外设功耗配置 + bool power_down_sdcard; // 睡眠时关闭SD卡电源 + bool power_down_display; // 睡眠时关闭显示电源 + bool power_down_audio; // 睡眠时关闭音频电源 + bool power_down_motor; // 睡眠时关闭电机电源 + + // RTC内存配置 + bool preserve_rtc_memory; // 保留RTC内存 + size_t rtc_memory_size; // RTC内存大小 +} power_management_config_t; + +/** + * @brief 默认功耗管理配置 + */ +#define DEFAULT_POWER_CONFIG { \ + .light_sleep_duration_us = 1000000, /* 1秒 */ \ + .deep_sleep_duration_us = 30000000, /* 30秒 */ \ + .enable_timer_wakeup = true, /* 启用定时器唤醒 */ \ + .enable_gpio_wakeup = false, /* 不启用GPIO唤醒 */ \ + .enable_touch_wakeup = false, /* 不启用触摸唤醒 */ \ + .wakeup_gpio_num = GPIO_NUM_NC, /* 无GPIO唤醒 */ \ + .wakeup_level = 0, /* 低电平唤醒 */ \ + .disable_bt_in_sleep = true, /* 睡眠时关闭蓝牙 */ \ + .disable_wifi_in_sleep = true, /* 睡眠时关闭WiFi */ \ + .reduce_cpu_frequency = true, /* 降低CPU频率 */ \ + .cpu_frequency_hz = 80000000, /* 80MHz */ \ + .power_down_sdcard = true, /* 睡眠时关闭SD卡 */ \ + .power_down_display = true, /* 睡眠时关闭显示 */ \ + .power_down_audio = true, /* 睡眠时关闭音频 */ \ + .power_down_motor = true, /* 睡眠时关闭电机 */ \ + .preserve_rtc_memory = true, /* 保留RTC内存 */ \ + .rtc_memory_size = 4096, /* 4KB RTC内存 */ \ +} + +/** + * @brief 各功耗模式的详细配置 + */ +static const power_management_config_t idle_mode_config = { + .light_sleep_duration_us = 500000, // 500ms轻度睡眠 + .deep_sleep_duration_us = 0, // 不使用深度睡眠 + .enable_timer_wakeup = true, + .enable_gpio_wakeup = true, + .wakeup_gpio_num = GPIO_NUM_0, // 按键唤醒 + .wakeup_level = 0, + .disable_bt_in_sleep = false, // 保持蓝牙连接 + .disable_wifi_in_sleep = false, // 保持WiFi连接 + .reduce_cpu_frequency = true, + .cpu_frequency_hz = 40000000, // 40MHz + .power_down_sdcard = false, // 保持SD卡(可能有后台任务) + .power_down_display = true, // 关闭显示背光 + .power_down_audio = true, // 关闭音频 + .power_down_motor = true, // 关闭电机 + .preserve_rtc_memory = true, + .rtc_memory_size = 2048, +}; + +static const power_management_config_t light_sleep_config = { + .light_sleep_duration_us = 0, // 直接进入轻度睡眠 + .deep_sleep_duration_us = 0, + .enable_timer_wakeup = true, + .enable_gpio_wakeup = true, + .wakeup_gpio_num = GPIO_NUM_0, + .wakeup_level = 0, + .disable_bt_in_sleep = true, // 关闭蓝牙 + .disable_wifi_in_sleep = true, // 关闭WiFi + .reduce_cpu_frequency = true, + .cpu_frequency_hz = 40000000, + .power_down_sdcard = true, // 关闭SD卡 + .power_down_display = true, // 关闭显示 + .power_down_audio = true, // 关闭音频 + .power_down_motor = true, // 关闭电机 + .preserve_rtc_memory = true, + .rtc_memory_size = 4096, +}; + +static const power_management_config_t deep_sleep_config = { + .light_sleep_duration_us = 0, + .deep_sleep_duration_us = 60000000, // 60秒深度睡眠 + .enable_timer_wakeup = true, + .enable_gpio_wakeup = true, + .wakeup_gpio_num = GPIO_NUM_0, + .wakeup_level = 0, + .disable_bt_in_sleep = true, // 关闭蓝牙 + .disable_wifi_in_sleep = true, // 关闭WiFi + .reduce_cpu_frequency = true, + .cpu_frequency_hz = 10000000, // 10MHz + .power_down_sdcard = true, // 关闭SD卡 + .power_down_display = true, // 关闭显示 + .power_down_audio = true, // 关闭音频 + .power_down_motor = true, // 关闭电机 + .preserve_rtc_memory = true, + .rtc_memory_size = 8192, +}; + +/** + * @brief 功耗统计和监控结构体 + */ +typedef struct { + uint64_t total_sleep_time_us; // 总睡眠时间 + uint64_t total_wake_time_us; // 总唤醒时间 + uint32_t sleep_count; // 睡眠次数 + uint32_t wake_count; // 唤醒次数 + uint32_t average_sleep_duration_us; // 平均睡眠时长 + uint32_t average_wake_duration_us; // 平均唤醒时长 + float estimated_power_saving_percent; // 估计的功耗节省百分比 +} power_statistics_t; + +/** + * @brief 功耗优化建议 + * + * 基于硬件特性和使用模式,提供功耗优化建议 + */ +typedef enum { + OPTIMIZATION_NONE = 0, + OPTIMIZATION_REDUCE_CPU_FREQ, // 降低CPU频率 + OPTIMIZATION_DISABLE_UNUSED_PERIPHERALS, // 关闭未使用的外设 + OPTIMIZATION_USE_LIGHT_SLEEP, // 使用轻度睡眠 + OPTIMIZATION_USE_DEEP_SLEEP, // 使用深度睡眠 + OPTIMIZATION_OPTIMIZE_GPIO_STATES, // 优化GPIO状态 + OPTIMIZATION_USE_RTC_MEMORY, // 使用RTC内存 + OPTIMIZATION_BATCH_OPERATIONS, // 批量操作 +} power_optimization_t; + +/** + * @brief 功耗管理事件回调 + */ +typedef void (*power_event_callback_t)(power_mode_t old_mode, power_mode_t new_mode, void* user_data); + +/** + * @brief 功耗管理事件 + */ +typedef enum { + POWER_EVENT_MODE_CHANGE, // 功耗模式改变 + POWER_EVENT_SLEEP_START, // 睡眠开始 + POWER_EVENT_SLEEP_END, // 睡眠结束 + POWER_EVENT_WAKEUP, // 系统唤醒 + POWER_EVENT_OPTIMIZATION_TRIGGER, // 功耗优化触发 +} power_event_t; + +#endif // POWER_MANAGEMENT_CONFIG_H \ No newline at end of file diff --git a/main/02_physical/boards/config.h b/main/02_physical/boards/config.h new file mode 100644 index 0000000..19468d2 --- /dev/null +++ b/main/02_physical/boards/config.h @@ -0,0 +1,26 @@ +#ifndef BOARD_CONFIG_H +#define BOARD_CONFIG_H + +#include "sdkconfig.h" + +// 根据menuconfig的配置选择不同版本的config.h文件 +#ifdef CONFIG_BOARD_VERSION_V1_1_11 + #include "boards/board_v1_1_11/config.h" +#elif defined(CONFIG_BOARD_VERSION_V1_1_12) + #include "boards/board_v1_1_12/config.h" +#elif defined(CONFIG_BOARD_VERSION_V1_1_13) + #include "boards/board_v1_1_13/config.h" +#elif defined(CONFIG_BOARD_VERSION_V1_1_14) + #include "boards/board_v1_1_14/config.h" +#elif defined(CONFIG_BOARD_VERSION_V1_1_16) + #include "boards/board_v1_1_16/config.h" +#elif defined(CONFIG_BOARD_VERSION_V1_1_17) + #include "boards/board_v1_1_17/config.h" +#elif defined(CONFIG_BOARD_VERSION_V1_1_18) + #include "boards/board_v1_1_18/config.h" +#else + // 默认使用v1.1.11版本,避免编译错误 + #include "boards/board_v1_1_13/config.h" +#endif + +#endif // BOARD_CONFIG_H \ No newline at end of file diff --git a/main/02_physical/boards/module.cmake b/main/02_physical/boards/module.cmake new file mode 100644 index 0000000..f360aee --- /dev/null +++ b/main/02_physical/boards/module.cmake @@ -0,0 +1,35 @@ +# 根据 menuconfig 中选择的板卡配置,自动匹配 boards/board_v* 目录 +# 这样新增板卡时,只要: +# 1. 增加对应的 Kconfig 项,例如 CONFIG_BOARD_VERSION_V1_1_18 +# 2. 新增目录 02_physical/boards/board_v1_1_18/ +# 就不需要再修改 main/CMakeLists.txt + +set(BOARD_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}") +set(MAIN_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/../..") +set(SELECTED_BOARD_DIR "") + +file(GLOB BOARD_CANDIDATE_DIRS RELATIVE "${BOARD_ROOT_DIR}" "${BOARD_ROOT_DIR}/board_v*") + +foreach(board_dir ${BOARD_CANDIDATE_DIRS}) + if(IS_DIRECTORY "${BOARD_ROOT_DIR}/${board_dir}") + string(REGEX REPLACE "^board_" "" board_suffix "${board_dir}") + string(TOUPPER "${board_suffix}" board_suffix_upper) + set(board_config_var "CONFIG_BOARD_VERSION_${board_suffix_upper}") + + if(DEFINED ${board_config_var} AND ${board_config_var}) + set(SELECTED_BOARD_DIR "02_physical/boards/${board_dir}") + break() + endif() + endif() +endforeach() + +if(NOT SELECTED_BOARD_DIR) + message(FATAL_ERROR "Please select a board version in menuconfig") +endif() + +target_sources(${COMPONENT_LIB} PRIVATE "${SELECTED_BOARD_DIR}/board_sweekar.cc") +target_sources(${COMPONENT_LIB} PRIVATE "${SELECTED_BOARD_DIR}/io_expansion_board.cc") +target_include_directories(${COMPONENT_LIB} PRIVATE "${SELECTED_BOARD_DIR}") + +# 添加到 main 目录,使类似 "boards/config.h" 的包含路径保持兼容 +target_include_directories(${COMPONENT_LIB} PRIVATE "${MAIN_ROOT_DIR}") diff --git a/main/04_hal/audio_codec/audio_codec.cc b/main/04_hal/audio_codec/audio_codec.cc new file mode 100644 index 0000000..66b5e3f --- /dev/null +++ b/main/04_hal/audio_codec/audio_codec.cc @@ -0,0 +1,247 @@ +#include "audio_codec.h" +#include "esp_log.h" +#include "es7210.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + +static const char *TAG = "AudioCodec"; + +// 静态成员初始化 +AudioCodec* AudioCodec::instance_ = nullptr; +SemaphoreHandle_t AudioCodec::mutex_ = nullptr; + +AudioCodec::AudioCodec() + : board_handle_(nullptr), + is_initialized_(false), + current_mode_(AUDIO_CODEC_MODE_DECODE), + current_volume_(100) +{ +} + +AudioCodec::~AudioCodec() { + Deinitialize(); +} + +AudioCodec* AudioCodec::GetInstance() { + // 双重检查锁定模式确保线程安全 + if (instance_ == nullptr) { + if (mutex_ == nullptr) { + mutex_ = xSemaphoreCreateMutex(); + } + + if (xSemaphoreTake(mutex_, portMAX_DELAY) == pdTRUE) { + if (instance_ == nullptr) { + instance_ = new AudioCodec(); + } + xSemaphoreGive(mutex_); + } + } + return instance_; +} + +esp_err_t AudioCodec::Initialize() { + if (is_initialized_) { + ESP_LOGW(TAG, "AudioCodec already initialized"); + return ESP_OK; + } + + ESP_LOGI(TAG, "Initializing AudioCodec"); + + esp_err_t ret = InitializeBoard(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize audio board: %s", esp_err_to_name(ret)); + return ret; + } + + // 先设置初始化标志,然后启动编解码器 + is_initialized_ = true; + + // 默认启用双向模式,同时支持播放和录音 + ret = StartCodec(AUDIO_CODEC_MODE_BOTH); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to start codec in both mode: %s", esp_err_to_name(ret)); + is_initialized_ = false; // 如果启动失败,重置标志 + return ret; + } + + ESP_LOGI(TAG, "AudioCodec initialized successfully with both encode and decode enabled"); + return ESP_OK; +} + +esp_err_t AudioCodec::InitializeBoard() { + // 初始化音频板 + board_handle_ = audio_board_init(); + if (board_handle_ == nullptr) { + ESP_LOGE(TAG, "Failed to initialize audio board"); + return ESP_FAIL; + } + + ESP_LOGI(TAG, "Audio board initialized successfully"); + return ESP_OK; +} + +esp_err_t AudioCodec::StartCodec(audio_codec_mode_t mode) { + // 检查音频板是否已初始化,而不是检查整体初始化状态 + if (board_handle_ == nullptr) { + ESP_LOGE(TAG, "Audio board not initialized"); + return ESP_ERR_INVALID_STATE; + } + + esp_err_t ret = ESP_OK; + + switch (mode) { + case AUDIO_CODEC_MODE_DECODE: + ESP_LOGI(TAG, "Starting codec in decode mode"); + ret = audio_hal_ctrl_codec(board_handle_->audio_hal, AUDIO_HAL_CODEC_MODE_DECODE, AUDIO_HAL_CTRL_START); + break; + + case AUDIO_CODEC_MODE_ENCODE: + ESP_LOGI(TAG, "Starting codec in encode mode"); + ret = audio_hal_ctrl_codec(board_handle_->audio_hal, AUDIO_HAL_CODEC_MODE_ENCODE, AUDIO_HAL_CTRL_START); + if (ret == ESP_OK) { + // 设置ADC音量 + ret = audio_hal_set_volume(board_handle_->adc_hal, 100); + if (ret != ESP_OK) { + ESP_LOGW(TAG, "Failed to set ADC volume: %s", esp_err_to_name(ret)); + } + + // 设置ES7210麦克风增益 + ret = es7210_adc_set_gain((es7210_input_mics_t)(ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2 | ES7210_INPUT_MIC3), GAIN_37_5DB); + if (ret != ESP_OK) { + ESP_LOGW(TAG, "Failed to set ES7210 gain: %s", esp_err_to_name(ret)); + } else { + ESP_LOGI(TAG, "ES7210 gain set to 37.5dB"); + } + } + break; + + case AUDIO_CODEC_MODE_BOTH: + ESP_LOGI(TAG, "Starting codec in both modes"); + ret = audio_hal_ctrl_codec(board_handle_->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START); + if (ret == ESP_OK) { + // 同时设置播放和录音参数 + audio_hal_set_volume(board_handle_->adc_hal, 100); + es7210_adc_set_gain((es7210_input_mics_t)(ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2 | ES7210_INPUT_MIC3), GAIN_37_5DB); + } + break; + + default: + ESP_LOGE(TAG, "Invalid codec mode: %d", mode); + return ESP_ERR_INVALID_ARG; + } + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to start codec: %s", esp_err_to_name(ret)); + return ret; + } + + current_mode_ = mode; + + // 设置初始音量(仅在播放模式下) + if (mode == AUDIO_CODEC_MODE_DECODE || mode == AUDIO_CODEC_MODE_BOTH) { + SetVolume(current_volume_); + } + + ESP_LOGI(TAG, "Codec started successfully in mode %d", mode); + return ESP_OK; +} + +esp_err_t AudioCodec::StopCodec() { + if (!is_initialized_) { + ESP_LOGW(TAG, "AudioCodec not initialized"); + return ESP_OK; + } + + ESP_LOGI(TAG, "Stopping codec"); + // 修复:直接使用audio_hal_codec_mode_t类型 + esp_err_t ret = audio_hal_ctrl_codec(board_handle_->audio_hal, (audio_hal_codec_mode_t)current_mode_, AUDIO_HAL_CTRL_STOP); + if (ret != ESP_OK) { + ESP_LOGW(TAG, "Failed to stop codec: %s", esp_err_to_name(ret)); + } + + return ret; +} + +esp_err_t AudioCodec::SetVolume(uint8_t volume) { + if (!is_initialized_) { + ESP_LOGE(TAG, "AudioCodec not initialized"); + return ESP_ERR_INVALID_STATE; + } + + if (volume > 100) { + ESP_LOGW(TAG, "Volume %d exceeds maximum, setting to 100", volume); + volume = 100; + } + + // 转换为HAL音量范围 (0-63) + int hal_volume = (volume * 63) / 100; + esp_err_t ret = audio_hal_set_volume(board_handle_->audio_hal, hal_volume); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set volume: %s", esp_err_to_name(ret)); + return ret; + } + + current_volume_ = volume; + ESP_LOGI(TAG, "Volume set to %d%% (HAL volume: %d)", volume, hal_volume); + return ESP_OK; +} + +esp_err_t AudioCodec::GetVolume(uint8_t* volume) { + if (!volume) { + return ESP_ERR_INVALID_ARG; + } + + *volume = current_volume_; + return ESP_OK; +} + +esp_err_t AudioCodec::SetAdcVolume(uint8_t volume) { + if (!is_initialized_) { + ESP_LOGE(TAG, "AudioCodec not initialized"); + return ESP_ERR_INVALID_STATE; + } + + if (volume > 100) { + volume = 100; + } + + esp_err_t ret = audio_hal_set_volume(board_handle_->adc_hal, volume); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set ADC volume: %s", esp_err_to_name(ret)); + return ret; + } + + ESP_LOGI(TAG, "ADC volume set to %d", volume); + return ESP_OK; +} + +audio_board_handle_t AudioCodec::GetBoardHandle() { + return board_handle_; +} + +bool AudioCodec::IsInitialized() { + return is_initialized_; +} + +esp_err_t AudioCodec::Deinitialize() { + if (!is_initialized_) { + return ESP_OK; + } + + ESP_LOGI(TAG, "Deinitializing AudioCodec"); + + StopCodec(); + Cleanup(); + + is_initialized_ = false; + ESP_LOGI(TAG, "AudioCodec deinitialized"); + return ESP_OK; +} + +void AudioCodec::Cleanup() { + if (board_handle_) { + audio_board_deinit(board_handle_); + board_handle_ = nullptr; + } +} \ No newline at end of file diff --git a/main/04_hal/audio_codec/audio_codec.h b/main/04_hal/audio_codec/audio_codec.h new file mode 100644 index 0000000..af45c86 --- /dev/null +++ b/main/04_hal/audio_codec/audio_codec.h @@ -0,0 +1,74 @@ +#ifndef AUDIO_CODEC_H +#define AUDIO_CODEC_H + +#include "esp_err.h" +#include "audio_hal.h" +#include "board.h" +#include "esp_peripherals.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// 使用audio_hal中已定义的模式类型,避免重复定义 +typedef audio_hal_codec_mode_t audio_codec_mode_t; + +// 为了代码可读性,定义别名 +#define AUDIO_CODEC_MODE_DECODE AUDIO_HAL_CODEC_MODE_DECODE +#define AUDIO_CODEC_MODE_ENCODE AUDIO_HAL_CODEC_MODE_ENCODE +#define AUDIO_CODEC_MODE_BOTH AUDIO_HAL_CODEC_MODE_BOTH + +class AudioCodec { +public: + // 获取单例实例 + static AudioCodec* GetInstance(); + + // 初始化音频编解码器(默认启用双向模式) + esp_err_t Initialize(); + + // 音量控制 + esp_err_t SetVolume(uint8_t volume); + esp_err_t GetVolume(uint8_t* volume); + + // ADC音量控制(录音) + esp_err_t SetAdcVolume(uint8_t volume); + + // 获取音频板句柄 + audio_board_handle_t GetBoardHandle(); + + // 检查是否已初始化 + bool IsInitialized(); + + // 反初始化 + esp_err_t Deinitialize(); + +private: + AudioCodec(); // 私有构造函数 + ~AudioCodec(); + + // 禁止拷贝构造和赋值 + AudioCodec(const AudioCodec&) = delete; + AudioCodec& operator=(const AudioCodec&) = delete; + + static AudioCodec* instance_; + static SemaphoreHandle_t mutex_; + + audio_board_handle_t board_handle_; + bool is_initialized_; + audio_codec_mode_t current_mode_; + uint8_t current_volume_; + + esp_err_t InitializeBoard(); + void Cleanup(); + esp_err_t StartCodec(audio_codec_mode_t mode); + esp_err_t StopCodec(); +}; + +#ifdef __cplusplus +} +#endif + +#endif // AUDIO_CODEC_H \ No newline at end of file diff --git a/main/04_hal/audio_codec/module.cmake b/main/04_hal/audio_codec/module.cmake new file mode 100644 index 0000000..a60c841 --- /dev/null +++ b/main/04_hal/audio_codec/module.cmake @@ -0,0 +1,16 @@ +# main/04_hal/audio_codec/module.cmake + + +# 判断 menuconfig 中的开关 +if(NOT CONFIG_ENABLE_HAL_AUDIO_CODEC AND NOT EARLY_EXPANSION) + message(STATUS " [Skip] audio_codec module disabled by menuconfig.") + return() +endif() + +list(APPEND MODULE_SRCS + "04_hal/audio_codec/audio_codec.cc" +) + +list(APPEND MODULE_INCLUDE_DIRS + "04_hal/audio_codec" +) \ No newline at end of file diff --git a/main/04_hal/base_board_hal/base_board_hal.h b/main/04_hal/base_board_hal/base_board_hal.h new file mode 100644 index 0000000..e7244ed --- /dev/null +++ b/main/04_hal/base_board_hal/base_board_hal.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include "esp_err.h" + +/** + * @brief Base Board Hardware Abstraction Layer + * Abstracts the communication transport (UART vs I2C) and sensor reading. + */ +class BaseBoardHal +{ +public: + virtual ~BaseBoardHal() = default; + + /** + * @brief Initialize the hardware interface + */ + virtual esp_err_t Init() = 0; + + /** + * @brief Send raw data to the base board + * @param data Pointer to data buffer + * @param len Length of data + */ + virtual esp_err_t Send(const uint8_t *data, size_t len) = 0; + + /** + * @brief Read raw data from the base board + * @param data Pointer to data buffer + * @param len Length of data to read + */ + virtual esp_err_t Read(uint8_t *data, size_t len) = 0; + + /** + * @brief Get the current angle from Hall sensor (or via query) + * @param[out] angle Output angle in degrees (0.0 - 360.0) + * @return ESP_OK on success + */ + virtual esp_err_t GetAngle(float *angle) = 0; +}; diff --git a/main/04_hal/base_board_hal/base_board_hal_i2c.h b/main/04_hal/base_board_hal/base_board_hal_i2c.h new file mode 100644 index 0000000..6e55c30 --- /dev/null +++ b/main/04_hal/base_board_hal/base_board_hal_i2c.h @@ -0,0 +1,65 @@ +#pragma once + +#include "base_board_hal.h" +#include "i2c_bus.h" +#include "esp_log.h" + +class BaseBoardHalI2c : public BaseBoardHal +{ +public: + static constexpr uint8_t kBaseSlaveAddr = 0x22; + // TMAG5273 default address often 0x35 or defined by config + static constexpr uint8_t kHallSensorAddr = 0x35; + + BaseBoardHalI2c(i2c_bus_handle_t bus_handle) + : bus_handle_(bus_handle) {} + + virtual ~BaseBoardHalI2c() + { + // i2c_bus handles device management internally if used via i2c_bus_create + // But here we just use the bus handle directly. + } + + virtual esp_err_t Init() override + { + if (!bus_handle_) return ESP_ERR_INVALID_STATE; + + // Check if device is alive + esp_err_t err = i2c_bus_probe_addr(bus_handle_, kBaseSlaveAddr << 1); + if (err != ESP_OK) { + ESP_LOGW("BaseBoardHalI2c", "Base board not found at 0x%02X", kBaseSlaveAddr); + // Don't fail init, maybe it's sleeping + } else { + ESP_LOGI("BaseBoardHalI2c", "Base board found at 0x%02X", kBaseSlaveAddr); + } + + return ESP_OK; + } + + virtual esp_err_t Send(const uint8_t *data, size_t len) override + { + if (!bus_handle_) return ESP_ERR_INVALID_STATE; + + // i2c_bus_write_bytes expects: bus, addr, reg_addr, reg_len, data, datalen + // The data pointer in i2c_bus_write_bytes is (uint8_t *), not (const uint8_t *) + // This is a common issue in legacy C APIs. We have to cast away constness. + + return i2c_bus_write_bytes(bus_handle_, kBaseSlaveAddr << 1, NULL, 0, (uint8_t*)data, len); + } + + virtual esp_err_t Read(uint8_t *data, size_t len) override + { + if (!bus_handle_) return ESP_ERR_INVALID_STATE; + + return i2c_bus_read_bytes(bus_handle_, kBaseSlaveAddr << 1, NULL, 0, data, len); + } + + virtual esp_err_t GetAngle(float *angle) override + { + // TODO: Implement TMAG5273 read logic using i2c_bus_read_bytes + return ESP_ERR_NOT_SUPPORTED; + } + +private: + i2c_bus_handle_t bus_handle_; +}; diff --git a/main/04_hal/base_board_hal/base_board_hal_uart.h b/main/04_hal/base_board_hal/base_board_hal_uart.h new file mode 100644 index 0000000..63f715e --- /dev/null +++ b/main/04_hal/base_board_hal/base_board_hal_uart.h @@ -0,0 +1,45 @@ +#pragma once + +#include "base_board_hal.h" +#include "driver/uart.h" + +class BaseBoardHalUart : public BaseBoardHal +{ +public: + BaseBoardHalUart(uart_port_t port) : port_(port) {} + virtual ~BaseBoardHalUart() = default; + + virtual esp_err_t Init() override + { + // Assuming UART is already initialized by board.cc or similar + return ESP_OK; + } + + virtual esp_err_t Send(const uint8_t *data, size_t len) override + { + if (port_ >= UART_NUM_MAX) { + return ESP_ERR_INVALID_STATE; + } + int written = uart_write_bytes(port_, (const char *)data, len); + return (written == (int)len) ? ESP_OK : ESP_FAIL; + } + + virtual esp_err_t Read(uint8_t *data, size_t len) override + { + if (port_ >= UART_NUM_MAX) { + return ESP_ERR_INVALID_STATE; + } + int read = uart_read_bytes(port_, data, len, pdMS_TO_TICKS(100)); + return (read == (int)len) ? ESP_OK : ESP_FAIL; + } + + virtual esp_err_t GetAngle(float *angle) override + { + // TODO: Implement angle reading via UART (query command or report parsing) + // For now, return not supported or cached value if we had one + return ESP_ERR_NOT_SUPPORTED; + } + +private: + uart_port_t port_; +}; diff --git a/main/04_hal/base_board_hal/module.cmake b/main/04_hal/base_board_hal/module.cmake new file mode 100644 index 0000000..8b135ff --- /dev/null +++ b/main/04_hal/base_board_hal/module.cmake @@ -0,0 +1,13 @@ +# main/04_hal/base_board_hal/module.cmake + +# 注意:此文件夹可能没有 cpp 源文件,仅有头文件。如果有源文件,请追加到 MODULE_SRCS。 + +# 判断 menuconfig 中的开关 +if(NOT CONFIG_ENABLE_HAL_BASE_BOARD_HAL AND NOT EARLY_EXPANSION) + message(STATUS " [Skip] base_board_hal module disabled by menuconfig.") + return() +endif() + +list(APPEND MODULE_INCLUDE_DIRS + "04_hal/base_board_hal" +) \ No newline at end of file diff --git a/main/04_hal/stepper_driver/aw8646.cc b/main/04_hal/stepper_driver/aw8646.cc new file mode 100644 index 0000000..cdd98ed --- /dev/null +++ b/main/04_hal/stepper_driver/aw8646.cc @@ -0,0 +1,213 @@ +#include "aw8646.h" +#include "config.h" +#include "esp_log.h" +#include "io_expansion_board.h" + +// Define AW8646 specific pins for Board v1.1.16 +// P0_0 -> DRV_T0 +// P0_6 -> DRV_T1 +// Only if NFC_RST_PIN is defined (implying it's moved to GPIO, freeing up P0_0) +#ifdef NFC_RST_PIN +#define AW8646_USE_CURRENT_CONTROL +#define AW8646_T0_PIN 0 +#define AW8646_T0_PORT OUTPUT_PORT0 +#define AW8646_T1_PIN 6 +#define AW8646_T1_PORT OUTPUT_PORT0 +#endif + +Aw8646Driver::Aw8646Driver(IOExpansionBoard &ioExp) : io_expansion_(ioExp) +{ +} + +esp_err_t Aw8646Driver::Init() +{ + esp_err_t err = ESP_OK; + + // 1. 默认处于休眠和禁用状态,防止发热! + err = io_expansion_.SetMotorSleepMode( + STEPPER_MOTOR_SLEEP, + STEPPER_MOTOR_SLEEP_PORT, + STEPPER_MOTOR_SLEEP_PIN + ); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set sleep mode: 0x%x", err); + return err; + } + + // 2. Disable Enable Pin (High = Disable for AW8646) + err = io_expansion_.SetMotorEnableMode( + true, // High -> Disable + STEPPER_MOTOR_ENABLE_PORT, + STEPPER_MOTOR_ENABLE_PIN + ); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set enable mode: 0x%x", err); + return err; + } + +#ifdef AW8646_USE_CURRENT_CONTROL + // 3. Initialize T0 and T1 pins for Current Control + // Default to Low (0, 0) for now. + uint8_t output0_val = 0; + err = io_expansion_.IoexpandReadReg(OUTPUT_PORT0, &output0_val); + if (err == ESP_OK) { + output0_val &= ~(1 << AW8646_T0_PIN); // Set T0 Low + output0_val &= ~(1 << AW8646_T1_PIN); // Set T1 Low + err = io_expansion_.IoexpandWriteReg(OUTPUT_PORT0, output0_val); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set T0/T1: 0x%x", err); + } + } else { + ESP_LOGE(TAG, "Failed to read port 0: 0x%x", err); + } +#endif + + // 4. Set Microsteps (Default to 1/8 step) + err = SetMicrosteps(8); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set microsteps: 0x%x", err); + return err; + } + + // 5. Set Default Direction + err = SetDirection(true); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set direction: 0x%x", err); + return err; + } + + ESP_LOGI(TAG, "AW8646 Driver Initialized (EN Logic Inverted, T0/T1 Configured)"); + return ESP_OK; +} + +esp_err_t Aw8646Driver::Enable(bool enable) +{ + esp_err_t err = ESP_OK; + if (enable) + { + ESP_LOGD(TAG, "Enabling AW8646 (sleep + enable=Low)"); + + // Ensure Sleep is High (Work) + err = io_expansion_.SetMotorSleepMode( + STEPPER_MOTOR_WORK, + STEPPER_MOTOR_SLEEP_PORT, + STEPPER_MOTOR_SLEEP_PIN + ); + if (err != ESP_OK) return err; + + // Enable Pin: Low to Enable + err = io_expansion_.SetMotorEnableMode( + false, // Low -> Enable + STEPPER_MOTOR_ENABLE_PORT, + STEPPER_MOTOR_ENABLE_PIN + ); + } + else + { + ESP_LOGD(TAG, "Disabling AW8646 (disable=High + sleep)"); + + // Enable Pin: High to Disable + err = io_expansion_.SetMotorEnableMode( + true, // High -> Disable + STEPPER_MOTOR_ENABLE_PORT, + STEPPER_MOTOR_ENABLE_PIN + ); + if (err != ESP_OK) return err; + + // Sleep Pin: Low to Sleep + err = io_expansion_.SetMotorSleepMode( + STEPPER_MOTOR_SLEEP, + STEPPER_MOTOR_SLEEP_PORT, + STEPPER_MOTOR_SLEEP_PIN + ); + } + return err; +} + +esp_err_t Aw8646Driver::SetDirection(bool dir) +{ + uint8_t mode = dir ? STEPPER_MOTOR_RIGHT : STEPPER_MOTOR_LEFT; + + return io_expansion_.StepperMotorSetDir( + mode, + STEPPER_MOTOR_DIR_PORT, + STEPPER_MOTOR_DIR_PIN + ); +} + +esp_err_t Aw8646Driver::Sleep(bool sleep) +{ + uint8_t mode = sleep ? STEPPER_MOTOR_SLEEP : STEPPER_MOTOR_WORK; + return io_expansion_.SetMotorSleepMode( + mode, + STEPPER_MOTOR_SLEEP_PORT, + STEPPER_MOTOR_SLEEP_PIN + ); +} + +esp_err_t Aw8646Driver::SetTriLevelPin(uint8_t port_reg, uint8_t config_reg, uint8_t pin, int state) +{ + uint8_t val; + esp_err_t err = ESP_OK; + + if (state == 2) { // Hi-Z -> Input + // Set as Input + err = io_expansion_.IoexpandReadReg(config_reg, &val); + if (err != ESP_OK) return err; + val |= (1 << pin); // Set Input + err = io_expansion_.IoexpandWriteReg(config_reg, val); + } else { // 0 or 1 -> Output + // Set as Output + err = io_expansion_.IoexpandReadReg(config_reg, &val); + if (err != ESP_OK) return err; + val &= ~(1 << pin); // Set Output + err = io_expansion_.IoexpandWriteReg(config_reg, val); + if (err != ESP_OK) return err; + + // Set Level + err = io_expansion_.IoexpandReadReg(port_reg, &val); + if (err != ESP_OK) return err; + + if (state == 1) val |= (1 << pin); + else val &= ~(1 << pin); + + err = io_expansion_.IoexpandWriteReg(port_reg, val); + } + return err; +} + +esp_err_t Aw8646Driver::SetMicrosteps(int microsteps) +{ + // AW8646 Microstep Table (Rising Edge Only) + // 1 (Full): MODE1=0, MODE0=0 + // 2 (1/2): MODE1=0, MODE0=Z (Hi-Z) + // 4 (1/4): MODE1=0, MODE0=1 + // 8 (1/8): MODE1=Z, MODE0=0 + // 16 (1/16): MODE1=Z, MODE0=1 + // 32 (1/32): MODE1=1, MODE0=Z + + int m1 = 0; + int m0 = 0; + + switch(microsteps) { + case 1: m1 = 0; m0 = 0; break; + case 2: m1 = 0; m0 = 2; break; // Z + case 4: m1 = 0; m0 = 1; break; + case 8: m1 = 2; m0 = 0; break; // Z + case 16: m1 = 2; m0 = 1; break; // Z + case 32: m1 = 1; m0 = 2; break; // Z + default: + ESP_LOGW(TAG, "Unsupported microsteps: %d, defaulting to 1/8", microsteps); + m1 = 2; m0 = 0; + break; + } + + ESP_LOGI(TAG, "Setting Microsteps to 1/%d (M1=%d, M0=%d)", microsteps, m1, m0); + + esp_err_t err; + err = SetTriLevelPin(STEPPER_MOTOR_M1_MADE_PORT, STEPPER_MOTOR_M1_CONFIG, STEPPER_MOTOR_M1_PIN, m1); + if (err != ESP_OK) return err; + + err = SetTriLevelPin(STEPPER_MOTOR_M0_MADE_PORT, STEPPER_MOTOR_M0_CONFIG, STEPPER_MOTOR_M0_PIN, m0); + return err; +} diff --git a/main/04_hal/stepper_driver/aw8646.h b/main/04_hal/stepper_driver/aw8646.h new file mode 100644 index 0000000..52fd2d6 --- /dev/null +++ b/main/04_hal/stepper_driver/aw8646.h @@ -0,0 +1,27 @@ +#ifndef AW8646_DRIVER_H +#define AW8646_DRIVER_H + +#include "stepper_driver.h" +#include "io_expansion_board.h" +#include "esp_log.h" + +class Aw8646Driver : public StepperDriver +{ +public: + explicit Aw8646Driver(IOExpansionBoard &ioExp); + virtual ~Aw8646Driver() = default; + + esp_err_t Init() override; + esp_err_t Enable(bool enable) override; + esp_err_t SetDirection(bool dir) override; + esp_err_t Sleep(bool sleep) override; + esp_err_t SetMicrosteps(int microsteps) override; + +private: + esp_err_t SetTriLevelPin(uint8_t port_reg, uint8_t config_reg, uint8_t pin, int state); + + IOExpansionBoard &io_expansion_; + const char* TAG = "Aw8646Driver"; +}; + +#endif // AW8646_DRIVER_H diff --git a/main/04_hal/stepper_driver/aw8646.pdf b/main/04_hal/stepper_driver/aw8646.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c1c7464ddc2c4f345708b1abfbe4fcfae0470558 GIT binary patch literal 1485355 zcmeFYbyQT}-!G1VC@3h1h}6I!4Ff}WBOTHyF+;<^Fm!jLgeWZ`-Q7rcH;A-!O6MK$ zQ%~LdeeSwz{eFKuXU&>9XP^D<{od!iUwhAMc@Z&sCI&Y2*9(jN!{|%^MgUCT6rG0$ zBxs8;hQX=y>`g3945&fEaHt-_1ZF9shk#OvaDf?_I2oB4*_qf_*%_H>8968!87cqh zg`|=(F@VEtV1|f%fGP|Q0U*0GQ-fq+kbjc1Gcqx9g261Tf04_>VGvsbD4eQyzqqS# zvnr?bS64bcQpMJ@#)jJAj*ag8;bZ^{13Lo~6M!3F0fU$rnm{1{TN@KgBY=q#)B!1w zm4TIki4l+mW@KcfM+#>BeFN|Y4zsla$f^Les0820OVisy;WkKvw5X{;N+t+%D3zkP zpzIrQK?#7Ms)VeBFhEIESX@?4TJDWHKv<4}4j`>0!axlI8n6KMnSciRKs_iB!VJ`7 zqH^XCVPq2)6Jnv~K)QvVgFVTormASO3%OyiU8L+5eea4Sv6T}Dxfx-019`rVjmIyru zdP^JNEssCAh(K)&;3if#qY7}tRZkygi{K?ALrVF5{8koX@RtNDTe$fxe~1AHY7Vu4 zS|V&fObkq*e@}xn_b(z#8-`nB84O?+AO}4wBmv`pAh7y}9sh;^c>_tn{GSmZz4(Xa z|DM9(KP5pbB_s2n)BLHHg~eZjAO>89Ft~*t(j$6SR^}!Kx9JB$>hq_uNPb+mX$if_ zDqgaioTO)Dre|bVVq)WBW#_t0OfE*o|3CnPE5Tsqykvi+Y12RQ^q;+v8Eazb_)qri z^o&eOjGSCxFxPG3{yX-6j^2Nf1ZfS|pGnV4)*RYg+*I5g)Ku7<+f>z*(^T4Ag1ow& z0h)cAtD8NW8k%aGBbx)7bDD#j@|z=@{tvSO(yl+IgQov_KKM7&0rj8eBUN+YYAIUq z^I`;xiVi39lKpFG{wMuyw7EoJ2DUfDR6>N8%+}Tf!o|U92!^m38q%|Ia&pkKa56*a z_4OG!>A_&A0hE;q$^zjq__r)1ENu{amIlzjSTHg{SU6bpq4Z2F?CkU``d|n>a>ih$ zXVQmouraf;>9exx{gG$LOhb+%gPXY<2ER$)-^XndD?+XRZuui6%}w}zPxw5bn~X$W z{!Me+@(&^&(0^ooBMosgnf`{Wr(|5%RY$ z{)Myuao4}#q`$lTkGuZ%#lLX&KkoV$ob-2>|8dvfzW5i;{>NSarIY?qHz6x9UNZZe zst9@ZM^*JlRmS{}stoy3Lgi#kFD#3!TJ_*&5|)NAWKDc?iYzw~a9b!J-(Qs);HI2= z3zD-%n44HaZ2&B{m-2c>$aB`)b44VD0YV85g}#Ns5CFE@#@lL77+L9=!;Jne4Q~kk zsKA9`ww4G0m>DEx0& z5y14D2h(pROuxB+e{%u<<^ulB1^k-}_%|2uZ!X~9T)@A%fPZrV-*VCZUAx}e{I@MP z9sjb$5^+VgkTPuH_TZ%Ss9RgIart&IKkQ=`5OYnAAxuawSn2f4WKqi z?xGHeH;M>k<%B$cqsR_m{v9g?1wr{YiiR8p?93d7`T*uzqmeSiV3r7EPcbF{^Q{9w zVqgICtq(wA%mC(FH-N-g04%o#g2Y$>EVnj-ZWxL&GIKC9>#?%|SZ*yw@H}0+=#xtj|@7?t+)7)2k7^}`fZ{OfDxpm zr*CuPsTA!#IK}yvQ)kT^ZuC&NSd#|Qg+sl#}5S&`iv?eEpzesiazcGUTnTGpic&drw;#IMxZ+r0Qj z6z=U_=W?-n%+h)FQR`}D@lF3cQ3H0zyDi^LNMB`ZcvkI#E7cIAq4oDC+;>Hj&B!x{ zcs}_o6n$>A(J&X3Oc>u+`z*PtwJ(ClGydiqLXZhBsvFfPlMvtOX;wDF{(^Dt6$MqN zr(C=DnVtvL(-9uL%n>lCJ1yHmXZxOvteVd5(*CcVwMm#F)z-b-AQ~fKE6;nPov%H| zzS4Q$gMFPs<9(PTSnjBO79VXT)i}H>fVLF8>5~zhBb~mnDUuc!Q>9OHX_gXXJMb;z z6y=rTVb#6dpN^v#!H^yr8M2?Ex|P{as~FG%AdQ}*RRj0Ftq*(?h}pQNT%+DK9et{o zBy?{P9uSLCcyv;f9P-Z?Apg5l$a0&Btz2c+(c=bR~_|7p3 zh)@hq91&q1qr+E0@~)BO;%W=^>JZ!HbmuX#^rlAze$EgfKX0c77pPb=agKPcPQF_TV1nk0(SB#Jr)qQjDxUu_aoKL2)67Wi?fYN69e zI#;cx$JsUUc?Mp|c^tX+_av8#4~}f!*y+5fjUHkFb1%C& zVSzl|k~3hUd!zS5+fNOTd^wJ~<^|B$2)ydz^gKLv8xshffF!O!X_2Diwv3IM(_XSu zkE49`T*fmk`mslDE+yvCjQqR835f-bYdkjRokF3wBb>?9a6SR*t(@(bAz*^ky;31YhsIExn_Q_j5xuL8e2y|3U$ z@Eoy3ea?IuqY!^Y=8M@p0`UvX?>0Y0ea{rhe0im)pk%~&^pBk%4QEG_Dc(JyBLgoQ_ z;EUKI@04}sY+Dgp6?t-!=@3qN{YfUgmh;nl%S{|J5vpHOLg<1O#;yg>96e>9>|8Q? zS_RTBK2Ws)KXGh*JoClzONVt~qDT3r!h^zq_^rJpycNCE{uqU-=8K(S&apUq9|bN{ zFm39&EMAwfOPiBofIpTYuh6n_;^jZn<~aj`Ceb4 zGG+NI4tf17PYkcxqlUpS&$VLero_8GqA3t#F|5c*N-g5oWED;H=vo(n^jc_=bo12! z#<8{qY~PXD$V`3T3|meyy#lR_4B}?^N96R7}#g7Rb^&=)8ED;9;zkX{| z(u*U5Yr6MDLi@AR@O)upyF^YAnjq0qo4`b82IY9O219mjZmL<;z1PvvHGm)LqdGq( zawb(ryb6}03{~^mHORZEt~v$%);UAgImgG74G6>PMv0d_X;0LWvdggUE;tx+R=rG+ zQV61x9(S}=%k%sBw&%5eU?`cLCG+NerzVAsYMDG7*Rr-{5Y|*A#HSbvYN3S6^|#{$@qpWcy4}g{DdeO zxictyB|y@iUK6sI?DMTS-haRSoD)~EElOU@S|*pyIHl%gD0Om(Vh^u~duz`LEy zv^T~9L)xA-=svq99Pl8KO&UC}Bd(UCbj+x|HQW-zIX!)v?Kn0yHp~V5Gn9nBo$?@C zqj8Px$Z>p2e(&zn^6#8xRwvd@xF)XJ%hkk2*6(#%rTYPzbPE|qm{HbsL9vNdpD%(i z;AvV7E9wy_s@09C9SY$f+CvVpT zKV}De<*-=W)Qo1=9UtLUqSudRr)lG)iicU21${PvE9=P_LN=C#0!yVAJsnDVM4X@m zYz+fHLcgI(w-uQaMKV5!47DL?p<#TeGY9uaTZq=U!}Lb&J}7)6o(Q6@dI)^rqoq`t z_CoWJh^k0w7S&qfP4(t_ii|PoLJ{T#KwXLYXf*%s6TGNp&kKBi1l~e6LO$6%6 z$w(aO;)&*C4nBds@a<3^t&c6z+SrcceeMqrPsaQBrgb#si)_YFE-49->M_`wira)a zAv!pv=k&eE)!hY}tTrrlhtmtZ&qw{UsYG9VmYQBZ3{M=M#Oj~ZJd22kvbU@*hCN9q zrDH8boFzY9mQRQC*zw{F!-skKzxi-hU@VN!u85MbbpFadO7=8gefWa2Ougg6#q2`F-bp$YD%8^E)-;5ZlscediOeLOtPIYKG- zH)YYDYNY=rcOErmZn7!U6eX z(Q`csEuYma_0pZ1>gJ&3ATCFRVMB_upcd_bJmoj}L)`Ak5LXv0b9E6NCX%=v{ALN; zx9Pp~0McGI0ikx0WU0y*)ZDloS&7W(?kLH9KOv9K!X8>1KI1CnbS&Oeh~LbXay33r zhxFwLTGt3A#(k~%<`*;^F3aFxpi_jFHPuvaYV)kUNo?>;X#0pi-;#Nfjo`ET`Tbs} z#$i89!P+KenWnGFK$6W0W+#2wBrDUo3C;1BO|E(`N?-AS!$;RbR0Otw2Yvh|ntTzp z;C7nW7pWW&+MZ0h$&#&f4am`$qob7Z(5m>4{FbEM>Z9gY)dr7$u$%3!vL@q-2faFu za(@2OWye0?gH5?%X;}eFfVfHKdovSiw%6lToIxFYvNh#h;u;y>;uv8D%*8odQvmwZ zsOlF{P6T}X{Y#_bhu@izrR46XbPqe)4jxtR3naluB>H0_1ElK-K>y>X2h9~H) zMV^kdgSvC|+9|!cL9eBF7PUjLS zAWm0J#A$3iFSxU`IijJKRq%ZvsZo(1G4%Yspif3ZYN-?l=z5zL3q+rk|!*BDDOFS#-y>al#Obrt{ik z2io4cd5b$LHU)Px92-;{2jdPmO;v|OGg+TLqRK&asT+=!wI&%%nWy+6lpDkzp#EYD3BY${0!9L1*3M7SEgKHdaBdaXnXH++^@ zU^Fs%%6p*!xKEBr^{ZJ=BhI&YVD#yowZwdvA+glDrsc`=oyBbsK;o`+efkXEA^ONXRla9K6Irb1w=JhHj(anEaTzImUH zF-=3aL_|s7bp6*afs62k+MW0d9q`KB@fP+riF(UNR)z72@gemp9Y3AaB?Kbs9)k-N zrLk+*y~aMW=V622#`y@J8qal9tQKzY;{Rm#G^0sbc!^r=gklO%P!@c0)gi=;RlHlg z|7iM`-N_E8@2wgOub)rX7|ws2R0N_RT_J1hiKbl1Y1n`zne~luC@dmdT(WWzzh!xWKc~g zKdI|6cN=b1JjeR1`Ga5@ixvk|bFQ*8HBx+hEakNxCn5to{?E`5(xrke&_n23rIP!cFwdL86vOJPx^= z38ZRbDQIb9^4GPP3ET!DY^(J;Z^&6%?~fi#?Cc;}Jqsujt^8{n zkrEQLzQqM^ziuU}nm`c7NWA(M`1~6xyyf->R48a;aD$$5GO~gM?Tl^-kkXhy!g^NX zP!l6#1b`jPfkbJ4ccTY0G2Xz6MmB#cDRhI%(zCI#0&eah_kl4o-cV@YT5zl4Z?kXo zQT@%3g^>{?fkeek3E~`uqkwZ+QIe z6p-2<3W8Y~|F-QGw{G%MG{xUBuWq|GN=G!u$W*i2b(xA7Nwv7sG}eE`NlL z{a+8;E#&=Y3``I<@=&-i%)$z0c{4aUK*BI{7+ev#GY~Sfn1M( zTfuH1aDbtnxy@e?I427$3rJB$&&CYE@*Cd&b0gj@{{CC%KR|h8k|Hw*z`@S`572xo z;n@9!^3=5=>7%DykHTL#g{LFZ?mrE@A5I1U5Zx1TdieU0gj!4S#^UxmO-&{(?fy5u zAds#y9oB*u7L;@wy zA%L!6e|$7}eM|xxowbm*quYy2{IP43I{PE&R}wk*s~f#M3?IC&q2AmbxR_&A#!yjd#i1@7!Fo5O5uDzm8O9uJ}mF&2?N#)BE_Q z`6+Flj7nMg9|GRw3@PEOt0%XOvHcLYlfUVJ(u*sn#d|##m-D{i<8+o{v4O<>d+E{| z_WL4hjjo-T_isD>AHS?RV{u?5Qp`kG$G!JC=yP%~UlW)iS+=sxXJzw7X?*q1p3vB; zu~&Q^oj3OJM7ef97=03AC~|2+AD6c5v~%r7O2=$H8pPqmy5{{_#uwETXg*T;{b-$y-FNpvMUHUmp zGF7U75?Mk`JpyadAbs~C9K9q?*0qD8?3w!d_l;*xdWW)jH1XjHTPv!w)onk=XX{dT zjfWLv{X94v31zF8`WYA#+my%aZHCB7N>4rlkBBf)Py!oIM>{&aYxf3~e==F(t2-6K z1+`f<9ag?#=%jy|=n-vybs_B(TWk2$wc;g0Tc1!_r@n=<+^V^bTSr#b|0vl~-G2YR zru2ku6sbzZRPM_nl7-0db(fgn3!!yivwBMvSNpoigzOA_GiHawS9r05JSl(NZRG#$HTWa8~!Jli|a2q zrQ@#8A$M!Zi$x#kz`1`;S9BN}n&JZeRwTv3Xq;o|)lX-}*EwvR>FQ&28S#4-!fg}2 zhA63p)oi>K6eF&5nv~Ea#^-F}@I!rL`lL-1FFDg7k}`y-y1NsPWP8faxFFw{O=``7 zD|>s}BCg17zRq3?HIl+)C;0kTkuaXgcUG!A7U&FyrMF3a3q5c}c?#U5GSf+_&70WPo4Xyk1_c3!T=EOPx`ZkF)ouGo@C2{-#7o8iJ^( z_7VkkqFcP+9<RJEq3j#yK1gRsBjsU ziJ@rK^!)Zfs=up}HI`3KTXj%|`l6PYQ^SnU<)&RN02s+VN_3=I5*=PFBZN;)YYqTX zFLGN>4t0PZZE&%<4`(%WX$YFA3J-U`Db6qX6t44%$2GR6URX#rk`}lahh@fp5}c!p zJ^S_$hVGoPr>ykhVfX371bq($!3Hv5~d(Ii=DRC zb^>E&wLbL^d0h8_08yq1x|19s5gvYE??0*0D=Wr#T%&rL+_^CnW9eCpmEKex-dN3r z0GhjzLDN!j-)t+eUT+sL_yyrUCLXDCFS1@g5f9H5eH0n)GJoc*APErOb<6w|L@BfS z<6tOAFtdfpVh{Y5*EC8uVzlSvqD?j2sB;5EX&7}G^>MfjAYLJ?dwL}Qy(Fay$3Nu2 zc)U#NvThgWs;}-O*Y#SPEmX7o^U&@dZK8o0KHaGqTlj=VuawveOoFEO-68uj8e&xE zx-=c)DdEW_QeG`T%{s+Fc`&XzT(lhdpHa4ErFWxQzwZOSW$c%bbZ=5Bh-II5wNKMh z*T)}33?R2rEO}5zPUyaJvvjHciBfk~xhy4&W$977e zQ7Z{-8IvT!H({efvviSzRrZ9(*wcd!dX8qQxz?!U#Ig-AEw~WBOw;h(B99G1hgP8e zSVb8qc8U_M(UaV?J!0&zDmyP6No)Aj)5*4Am zELp{mn>aZZsC%w~RX7Y3b-_ojB&*cX>gX7DoduA1n`}dHp&FK#2ag9e>}qO-+4DtS zG8@_6JN8J3&i;OmU?Hw+d}n)PJP&F9}6FIe>(*?-vC0X*K`taOm2rFUCq_beM& z?U}6eKE$2kvYf=W)yMb+e(R84@6OVZl8;G~%V*ZkCONY*>%`1b!CYMOsrC&1fl3w^ z3}2px6_0s6r=g&0#$(JV9@ijEa)9Gvc{Y3iO^lY5Av2wsc~N9LoL9wj*t_fAc# z`FHBhz>w!{(vGbZ4MwCS5hj_LNr?9eQ+&GyW>NoVx; z!^0J!ou-}>2&6-HhbeU;4}rgCN5PR~A{ZnmHpcGS6F8&fRA@S#VZ;{i^8UTimh;XT z6kJ>!Ff3sIR37&kO5uw%Xj+wJ6_X%0; z>IliDD;X=&fq>yn*~@O8xYvhH(pzQtVe*FEk>SO16_4YXxr-UBDTb*D`JyV=;PrFU z1KmFmY??0SQ~I-5+@iBjDqzofM{?uKkHl7AJeTr5BDk(}EAfb`gp!{Rgq!pE>{Hei zM)bdTX-z*iFgTfnua2?WI=E^4y0VTlUW($agX_tPGXLTeGG34FGOnm_L&%7XN`F{$J*=UtY}JL$*(jL zwUAshErqsq{_8;Fy!J1iE}cxlO2<`7X&KX{t@R|37t!^0J%ysNVdd{e98yN>>xxN0 zY>{XWtr>vhNPn?e6(=9`C5OLJ?TVWc1^Vr|O{yyTdRm+=l?pPeV-N*9oy8<4@rUCo zt{|T%=8&cG{yuc)#JX2mjQJa?Dtz!TA`47##8=H>m`(p=-ORTDmH30DrF6C;6%-H< z>-uElj!flJvH2IE^^la1BE6hgx_aha^;YCV-#>f+gXC(@FJ{*AGT1j?wf+~{VqqCY zVI3;j1=e+%2yMxS#F(sEiZ4x7A<{q+UEB@%y_g>j$vc&g)>uu`%(ownyJlOkn7}^O zyFzf{da;(i<_au8mzG#ZFjJWE$2OWq1T6y-w$w;r{LGvQ@A7lQbB>#Ol7*f&2}xEgW7!VlVxu? z&ZcG7hW<|XkdR&e31^V^c){mVG^#*hvGi6OeX_2O(sR(aXi<%vTJucO(=mlt40Hnv zP>491>~v|^CLF_&&9G~?+h@01;3!VJ4Q2CC{0cZl!c_J zzI{0z2I@oQT#FejI7k1~WQYM-@lBcx*hHiJrTF;~{#qeJtHz9bno*tFrKx&JF2lK1 zKXTB-vQmy2Z_($T&s7$l4NSfkdvcdXKO&r`SY1#KIo~nq|IqTyni6YX(e$y_NV0o#t&eG_jXKqu=y6OR|zjtn>OmQ9hQqaoS_(*foN7>k9o_9X(pO&Nsan zaUn4+?a+|~c+^Dg2(0NuKF0ey&eZ643@6jL2jLHyNr6OTPe@(NVa*b2-p9)0_uFme ztI@41nu^b&Y(WomJ}E^Jl)m0ZD#{Vh42U>^EGeGbl~BuEn~y@|#;;#4w0!Kxpp2NV z7(C_9Tc7MUEZ<}=6JEY7h%ULAe@;%QD@uHAf$YBEnJ#f1rZHA+u4$>x-zw_V$Q11LmXMNMA_V*@$wAeIcfg* z`RCh6gR7!lCimVz`{%@yJ!3%NJ)#c7E(m0m`!gF_Qin{k^vZ@m zgw1u27^rgNXO{?BdL>;Hcz1EbmgJfNtaW$f@5G zj-jRkCQX#e?#Voj6L~D4RNQFbUlp9H7L*Q+DxOOn#rOPSD|OK@C6y(#iJR_Fqc6JCD$#qc3e&0 zn8<1u;6&(7FJBJQ+>G?df(a_R&8u}XChVCd^-PXyd%lMC zq*;!Gl+QlYWI*oYwdJ(XDB^&Y;_9ieUo_S&Fq1prA@ex_f!y{x$=?hxY7tjEO^nZ< zS)QE~)G%lV9AJCF>jp>leBQDbZ)`%-7Knsdf9#;D}umCY~#5mwGO)9 z4(~S$J1Y4RAv7CG-=XY;ALS=1-Lt z0+t|78<8|N+_LAdH?C~D)2F+akI53SzS44I`FS7Jex2$-!X{l^B5sco7DS0ck~-f# z8i$kr+U^w3yGnC^tne(Ykwu7s>*nW|A z_y^_cN*XdbRX`3i$nsLAneF=PN}3w)!l9_?6MA|9vGk_C(cHj8j;GYX1Ro~7Wq7&h zb9|HUqz6s?EF)8h^R9~7k(Z)1drtdnA5XF0KoZKYTF^DA(wHeqUZ{v;jVhdplPFMViA#;WYq_>sP3=NyHk zK~v40G(&e~BQ4+IYkY7K`><{QO=%AgVrVgIiqFIQxT7O&N2@nM?fpGde0)ds&Q0Ug z=x|&9ECy`8LV#1S;%YGQN6U&g4>}dkQ|GRV1<|HLT0J*Z0|qTm4_K0Ps!!IKpRg8# z`|Gv(r>P0KDlayv%U{;mig!L{J0xU^$9`O6GP&~(&+ipYn_W|+vwf#i@yRonMhuUEVKU;gu7zIeq{&NHo zJjZ*>WgeJo!Ck6~^}*`Cd+*w3xmt?vJ&b2VgoTjHPMq)v*fi&_9Z-83?MRNtTe=nv z1qJP6k$d=$@E;+8!!!!hJNQYLX_^6LDLEZmp#ow;VmElF^_R+ox~pa!SuJvH)sT04 zgzt`9nMv?#`Zm5(Glg?A-Ti~U#d9-W)Bf1*I|H_1@_vn!%gh}`O2u_QKF)c{qdPll zKzsfBVC-9{)aw0`45VU3%Neh@tg09eRM}LxFM#N6D3L4p;k@}$Z$`BJ;6;poh)>83 ztob(7_4-1^p=riV0cIk?dX#ZE*dO(XzK3eon9u`y5fy}%?@F1wA)#1pua5E|eD4;w z^$^FlX|kPb-Oe^ChNR_e`~Jnu5D44~5fDSxG@KU0NQiN0{Sx`=ft2InF$Mq*GdGby zj)&&o)eAuvxyC-vOqp1K!6g=PEz;)5K3`aeUqK){MX9G6QabK2+fGPSvDPTZJ0y6Zq>304xCaEk9xgJH zqx?Y%d_q^5FpZ=UFiXGak(kf28~?PTUG*WMmw6ge1BS|X2X1hrgf=VDMuj7vFP$N) zS8g{5v`0uKXo_50Mo_F=2tSJv9#w0~dn0dtU7NKwV9)u-TLuEt~E^R~TyW-Mg;z6u+z zINqSUGcNVkP$Us_?2PqUA02I6{zMv%CTZe)aDBmBt zg~!ht$CJf4y(oKVzcbNNb>zJmeW%o7_D7FxQjr0jHkKt=u&TuR=?Tzs4Ewq?MM zSf@+>gOHFcg0ZmpcdyjJAh)#Stb*P znp_!XTyzUc#PZaTF72mqll?;lMTjIj@Z@KI-uGmNs_S)Vxl1$e8dm4l^+`y@Y`Qjg z+2umu;u;W}W-U-olwL*5kLCuJT+>c_*lGB};%q0fHdSkIyv#?ZW&Uf%Ip@XBWx_kY z0b*9NErr8=*hQXeJ1;SMmN3>H?T3TDM-f7W&*&XGhl5-s=CSoOqJh&dX+St_f}SP> zu+OgJ7ERypb5 zZS+Oeet*=Vg+XbtbpMy)nr9bzx%kV7UrXd2-@{Hj(E+?tyN=uUE6Yof1(w3wqSqgd zY)b&f`-uhoNvdU+ zEmE;7rBUJ|!#5C=MOB_RJ1;;;Kw(jN=Zfj%n336q?mVV_h$3I3=sX9*6fYbM&eU<= z!Q_rAi$Ed9KQxv%v|P^bHImJWtJ=s3zDhqNx$w28K_u(W_`C1XvVE`Hx~xyN-|6r_ z_ub<&_UQi2z9*OyVk6hZ^1@<+1G2)pNJh1l|5bq zSHrC5m+?n4HP3Q(Ih$y5LzZ$v)YaNl_u}SW`zqRsi%90=xV%vu%VV<|F&hyt-)gjw z_kC6!LS8Ogb~rCOsGHL(2qX@V_w<^eM-Kdj6$fV@OSy83Ssm6W zNqqIgU7-ajJpR#8&W;$JdWjrKLzU?30`_p9Wn3TWn+3tEhMM~7r!CB3SH{4Sguu^XOf@KS!kNQl1F1% zL7MEx@m$IkK^kJ{w3cos_ggQfypNcEX<}WUr|*S*X(JcwC~iIFe~z6*ot%MogH{*@U&Hbq$@0`YkjMz~B?ybYhSbGiAQkHjJKE4PRZYF+%nI(1uu8R=z#KjTeyV zx|$n7Y{f8As));1xE zG5JFciDXVn-C=tk`m)anU-_ssAGMszd6*t^Vq;5Z>ZAe-L2u4$A6+KkWIc4Z-wpZx zG)cXb;X3Qi?AW``wnfN;IVhyN&9PQD79WV5U*EKjj=}yORm9zA`u!adxmJxI z8V&PjWH;v|`UdW?1tFcVKj>&fy(kJZjJ%7L6wJWwBCet)rmoHEN{KG%_X7t0@x(%& z`)hYcxLiNZ&zkoyQBdMj+%WxT)1t#KC@PFJ=T(kS*QRBF>7iAPuqwA7>yAFnP^uKTE?A8{1_=5?`$eG>h1p^={u25 zu=I(BT{DJ1E~G2AKH8V=S6rFVX@rtwr!V zDQy|UV;Y)f!m;`?nrM(q>FK!75kz}sUOk(&Jd%g^yF03D=F7N3`#nf8YBf5-8ww?u z#A8Me{0NlrSuP*tovdM8`9xe3rmEnc`Ov-MlU8`!xN3wqa9NzgsnC@JU8;m)saSUQ zjk@`(ZdGVkyc&GIFuu-`s_@`1WpeBbTXe^+uq~29>hUDFMHeoCH5`Q@Osu>1 z7tagaaKJB5Ns}YCG%psLklz=gXu(q+1`zy*Q)pz~`#*Nx?@!K|kT84W%eD+{)bTcHqa?4`X_9G54z) zA!`RfzUAw$jQ^Ty4mJ>!owa`dnwFDgp;i7Zmot-t9f0S~gb zHd{Q;vue4K+3*4}`DpmZIYoMD}8Oq6dntA>$A>a?kR`(+1ZsuvN+ z<^6=u4{!InAp8FR;SiAAyS@`rfc%5ofA|yq?VhRs#!js_a6L!R|K(OKRyKAvfD z0($$$Z$|CEw$A;_TeaLjzZkV`-)Y*HLcPzDOqC+~jP3p-7RQvaSDqSWp|PJSm`bT4 z0-i~yvYARMvXTy}9o~6G?9R)YF3HM&#?wainj*Z6EO1GXKw8)yE1fJZLsi1}fU_sp(3YZ{Scmu)v8Noh`nGBF(MmWs z?N4x~9Y|NMRzZDWz*Af^gTluZ8O09w2j9Oum|Jho39&z$ zT2}T0{#!*SNYsG!0TXc>b~X1kOEm6R;%h`>bXS&|)^k!HJ?T=oJKK}W5oS?c%Q0pU zh`Dl7@Yxo4D^galj9V8K&r_;l)8hCpd6}zW`l;Tyw3b@tlS3TRyUufH z^V2huBqYqut!)`|3NDgCd8ZF*P7|Mz%9Xjf(oMjk`h}U2ES(G0mmFegbt7!hT3pax z1hhYBxWC|Pt^2)-0X^W!Y-E#xs*914f>&<;Ar%cJk(fT7sC_d*RDHpV-ISE$|DyLX555Usmbw z0ekrmYsTLsPFT7c1z0=@+n?At^bXDwe^Y#rc)uv#SoK&#lS19{d3Q}zUbLTa<%H=G z1NvJn^Jbtz;;-6*K{Gc0rg?Ac$(4fl>{Sf$OW}JWL9b(z;0YovN9Eh>@p3zXPbeqk z67-pU1MNm}2zqw(BhTS^;Axryj$5;SyRz6-*a)thJ#+@MK7u_?h2j~ zl!@bcY)1^PQ;?N++td`un@1wVa|+_EHDhFyA2!n}j(XNQdy*$gS{HR<6)o+q8t4>j zx0eQ_a5^rz5cuu&;l;J<^rdd(C9AwH|MoFS{#7CkoQwX&Noy^kW{_?8{yg@*`~X(t zcX^DXGd1=*50m~Edv_Tf$Fd~~+P0WwihnVFd_W@cu#n3=&siA}`=}%QDGa@o_XJl1W?Jokv66a?`*5~$B4&JMw)M@zTN+u2k zTjZ|fDrf78I|Zt0t_#!`cYN;=Q!~G9dk*Tx;CC00R0xGx=--%d2?xTl5Q(#1@6V6g z$mY{PUHwSAS`-v4`QjwxBv{Ot?xU-=qjCVh^h6fz^sth|WYA`Wv6<3S6*NByeqCFO zqHmxI)k#Y%_O`N+%sFQB%`t5=$oEaT)_Il#O$O!Va*_3ibNX(o#{dML@|y1k>eRHA zm6hjR1XOjxAShi?8Au5emcq~Qe!084ZW)7H8PS%m_)J6YmOjdCx?7P(oT!x=!A@AI zZ5YG%ow~jdWr1AY*kYl__8XcH0T$}YKzOA%+O8(9l}C>)E-}sSw zJKL-f5O@&F9>|&$7>T;`Ox2>^E0Wj2V^qK-Vfl>oEfyS_wy4BK${JiwK6J75bA$Hw z!Z)v*n2r3v(vH8O*p_L@%A9aCS`i%}8OEvfI}{EneNcj3qYGY5%4?zF|D!39^VCr-yB8_0C?r=laPFsmhkR?0HF=bCK?y2JA!w+F>|*;uJj! zY}6TgWz%qccSc*$l)TjPg1SMudzP4(`8UjQ)pc$@&lb=xDIfy~Y6y13D1b3)?wjIydmT=g%T!UHmTBa-*%2Aa#m96U zCxqaT5k%sux5$#u%H!s~$>P=Ibse|upagY2VICytaN>MaMekD^CxE#27^|_|u^70<}=&*@hyGYTz zNf1Nt0t5%4jy58PF-g60p%9TXEG%*WNp0Qk7EDD2iI_H$2QEIu!Wnty5XI)j%520< z;h1l&93s@ak8xIEgD`xk+`8K0IOOY^48E@0@K^m0OAy!kM;!!An9^ z(e$G0JHvHc+fJ}lYLrW6K)Qkzp{ZS^z~P1ug_eFA!aqaj)2VE10dq~aDs>%za|lFB zQ$88$R3c@vv&|Y^c-DwBJ*UHN(J=l(yBA>l9(f4|dXj5w=zZQ{JWzMJP=KQ^{QbLu zH%{@p%hr`J{N{B|ndsr@G}&Nj{+%1M{53Yh6q@`&T*!D#1{9T*F4`kQSt2xq#p>q1 z0{fThQBrkuO%t3jk9@g2o3g5w+<43n?Nhbv9^M%7GX=draelXD)-aEc z13S37!Gatbf-yo#+Ws+B|J%Ku1qU;7IUb@jD1>ljPcK(`*^fv(v?TW(;gAyB%EFl2 zDZ||-2t8={BYBQ3_3R4%!7ZZmpN~* z{g8f9gO(PrQ%M?M*sK`nLOWdw6X>#&9(+7lvo>Ohu=~S4t@Q(1hWe%dydt@qtM~+W z;r%6_tj*S3?b&&i=!uc8uU$u7T~nD?Py}yD1Ib|puWm7|xOt)<6Zgk{!P~TO5AKmI zq_x1>PFQWL%C{h63l(@cR%$6nMeY9D1#R%DMoL#FQCs3k6R^z^7!Qr}d7<(2m$1Wa z6(5Ea`;ZAtqKcrf|K zsw;COaICBZ7Bat{PCs*&G=G_vqzDDAM`Vapr(WsN6`IR)imM}I&OeEI5;PcW5oJmb zeiogZ?_N#CeT+AvQ;B7m&u*RRiMX`s{f33u%dSf&9(ieIzZD5Jp}5YW36DdogqEBr z0!ZHcOXe!%)1`D0Y=o6+-!+8JMLMUlJv}rW3#6GEvM4t2?9t4@TPACBB^KDcH{1&q zT_VZd(dn!l&?XVfK@?Eb%Bxi7v8tAEu9p(#eW1D>1t%g=w3`@*-;mWt9W6#$m{<{_ zxX&`EK&)wdhO<>$cm<)*ztthg4U+4KWq?;UM z5!agTop*Rj4>BOM2Rx)Fze+UnwlY{2h9UQdR8=1JL5EATsyfo@3soO5{sJd~+EQ>1 z4(Z+g@Oe`e<_62=vFxEYE|W&uXZ9g5Jyq$s$>?S*an-|bY-=*OmDZh+>y#M`2G;e& zm;KA7MzZ=;y$Fv5ypyBaQ#Hwn=8uoZczsEnZD|CgP5Pn%PI}F%0yxO(hHT3G)oLu> zmsSmcT+`=IDrxL~qULC&(4%t0dX+)%dIJ3Fik)=7xJBj*H9?YaKwFuR9z~ZFl#0_k zQERBo$JRN$)73q+_S0+3ER3uQ*T~examdm$+zF!Io9J2Oje;};8Xl183Y+KELpU%# zfxM$j4>I7e?pB0i0YDe?Y&=KIlsNiYjXJniAWfaN6&Z+?vS&l=5_gsc8Ew3u1oq84 zGI*V2ZzC)lChYBU_K&BJ=mj*0I=TZQ!4!SARQlB6da>Vd8R_*i3MajjY7VpU=BV&N?1A-f&@G)RhXu_Uc}SiY>O<49y?5Jqv`7ToDfqbdX@*_8`m`7Ahc#yo z+6l4z7|Wr6eYrF)oMcE2-Jx+Us;VUS^NK{P2s!-p3;tow#jWIYiXNoY?K3Hp4~@QD zXgRgc2yOIy5K!zT?s?^B{$Q6!6@v$~O=o9Mvkw>(W3+Z-51xw-AGK%3#-GWJ)e6m> z5Q9W@3GNy1xJSCNhMkB5amy06DuZOX>x9-))2EPv!}my9it^JR1eHMnznmZQPsA-V zb~C2qexKYgqXa0EdLYBKLHKB2+4uqfOU!)GvxIa{K*|kNrABG^H9<2(_Qoetrl(N9 zdf7hwFV`XS_|oL~K|*r5^Op{h59WQl@mCejOBJoAl@m6E6T+9u<~y3LXvu{L4v#fe zR3j8SCQXsZ2Sqx%sR&Ra@bOd8Bz1N*z7GO-xr-;ysx-GQ+i2YcRkCB6A22*>-nR~o zU3M>hu%)4&YKEE4s50n5J{qD^q^dLNJ!*~i!9^DvZNGclarIC-Ulqx;o68J5p*-BZ zgrtR~D0EL?{&Z2G`t3|qzP+%#=la54<}|X$9CgFX0wnoEV{=&>wqu~$>=y@(%Jf}# zCxexnAmdRGusErf{2VjxgHk#px8<`d%<}H1sNLzCnE5JM5T*&0%CdvN?z*+mQldIK zYyrEdW>YnDxxAYwciEX{-*i|1=OcG~%&PisM_3t*HKqksCqZRjg$b*k>)Py~< z-!I9Ckmu-0&R7fNoOzC&Xu%r9W3#JtpIR9|3iCgTo8NlSK3ylwuM4Y*l`eUBO63^0 z%-;uf0xh-oT#Iu*(GiU0K$+bjOgnr%z1=Oy@zP#&(;f0a6euajwz)sQ>8MejGMF7Y zHe7Xm0&ea|%jM@Oy@MLp2(h@FgyVZrAxCx*CWa+hZkcYqVh<#(#||yO9Twz=FK*rF z)pR0tKN6hUY#d40s@Wcm8f)!!6`Glt^XYO?Gsn4Kv{4+QPuvOTv}pV;qRgq|vN7d| z{b7j&CGPGtn!4`8@qx_|XQhErS}Q&i(q&!=@!Cmj+gqJ#Rc?GW?x9h>*`2Qmq&o)G zH|zu;3e9Fp{9O9i30w8x?kG6ld~SF(!*bVoKl! zpp_P$?`au@JY~#HN3N%@RLbfL;`dH2Ym3p&A>!TJ3Io>mL$xu#km3&wiAf~ic0=`| z$xqj!*>q#q1cI7`&Cfe>*;Bk{^BYGQeaAG-xT)M}13>I>QA%~)6Y?Qjz_ac0ALC~#+w?*y5j#?j<$2{03Lu9xm?Zj8~E-$}ITWv-jEXv}C^5nT^ z^OQ8w>JlbW>PO0t%m!uQk}dMSBV}jqfm;!Yt`S=_%x;(|puv=`ANM^xWO3;HV^12v z6jhisG7k2VAV`Ge?wNZd)<-$Ugy@JE)ia^7u&{=M*LNzibGF3B1c&84iD{N}yYvQM zV0byzdK^cMh7R5|!$@Z=B{pVs%s;HG!b-v<&&Nboyx1)fzcePYSb%kmaW!o6j%LKx z>P=yC?}h{8g~GuSq$*Uhvkb`0`tPg|RVwCS?ylE&Phko_Zl4vfluh<7R0@nIuSFjtIFd2N8{G%SU1^#tw?uqexn6>5su#@_q;C&i zx)DFJce6i_Rhv3IUz~Bk@_wnIJ!j~qf24I93%Q;~n9kYn>5CU7zhkEpzcFBUbGlwG zUA5tW2$96pX-f(&4G^lBH*cmuq=pbN&5+fdN~AloV+shNBu(>)oI=Jpid-U*Y2f<2 z;qU|+Q!y_Ua5vw9OhO_%Puwt9XY-We=h~eRH%j`x%kZ{`x}UPfL3aH!yiQyLLC!UE zqbJZ#Xg~M)GtN6h$jHVr1ypt#r_UUe?#s1Y1SP(-UfOfi!$nco z4ihRl7<93;d}(>n%`|O-NNJa8ftMhSEv{9{14{bE_L@O_GF0VBV3>`z%ZFGvt;83$>xdHMFZ^zxeqr~3n z%Ge9Wfz1M+{JnyC#bSj1Gr~G2Na6muuVZE6=1$dU3&5RR3)6>BN8s?%=AnWuCa#9) zdhaU>KQOg&RC1{# zGW+5f_@|2=$AqcXwo7UiWSm6_YEDP*#NcDyU9@mV%dHsQ#4>yKFR}CYX(@~- z>XieH6C;z%Vh6#&hN%lI1<{WER3`cceo+B=7dt=-{ZHK%m+==&N)34Nla;WjfFxj{jDIwaT0jYx7Ld9B zpVJkY26VWLzhT&)$M#z+_|GT#=YRe!Uht<_@U!SY zQr}rv|LULrPAvH4$^O&1{AES_W*7bnF2>)e!2c+?ep|NxBDj7P_Oo6!#$Rdhe+AdS z^$>mr&)*~JcdY+UB8usEtp6k9{@+Fv)312{TSWciN&qmq|H~2etMdOCQUC9_7r(=b z>GuWqS6KZzr~hRv{cnUYe&NLbIjrPeEOf2R|7p--`hA`MPvVN{w@C6Y;_6pnzv2pj zf&g&pKjZ4x(|^;V{}@-+;~kK3XyTzUuxAt3S@^e;HSQjZuIC z{}`i~0QaDujP%bP|GP2jZzBRfU~|AN4d9jkx|DI5e?#BQzoBpDUy+2%{Qn{J4WPl9 ze-G&Y&(QDxy{tEYQ3v4QfXm^RDi6TAng1YO{t5Y}{V$O3U!DC&wEm0l)c-)fX=zzl z{^pgmDjiB=u)@D!lfL+JFV6IwJ>V(CJ9lBl&DHJs-Q)R336XqA0mXa%`ao^fo9e$p z7*O+-WIp`(OY&L^2euP4@zjRosj1j%`>CZwervJSlbP)TWv`P~Q_q%0yW1oNv~cUb zHOE2vn%9@jNzZntl??Y=9;W*G{u{?3wiD>HSzD6eg!ELNl3m&u(e{-lXJMgZ#aM}W zeXeK_`J5$+#nO{9!e~V1;{?KY&xAH1P}%z@M{cp6~j%SI8j-W`N z&FdX`dQE&dNgRwW_;Mr%le0$g2M1v-Ke1-g=lC`z=M$(D>Y@X%J;(*}e&oIC6ux z&Rg3=2gGA9g8(UI;i(5r)|dpYHrgKKX&%dX*{#yMmN&>qH{z9YVYzUm-C`wZbC4sx zL#U*4u*i+DXcY~XG$K2<+=64Bg*$cu9-7Qabga}&wu0vlKxXmva-~=$6ddHer}jc` zv@1DIbG;1-tkHtMoxH`fTHTN>Z;U_!@%+F?6$7jl&BF{ojL8db+!IP?Xwe}7`iTK8 z1u;3N)I0&&?{?cUyC(Sv(<0h3FL?=5I)7`)ox7eLTRP*u(H%ENXfZE#19`^T*;$)O zW>xPC4^BYI*1mB+N2@NDIBN?G)*4?ja`iw#o+Ajt4jj4(LvM2gKTiO|6%LZ3#-mAq z0|nDa357hU>gs%j#I{K3cix?}9~cT@HUKD)l`Ww93N~FB{KQX%4b$CshBSbcMAWR$ zL4LAbLg>>spM?NOXF?7mTqCfk2OIdq zCAlc$4B*N@tx*&(qYRygf)4BjdSC)hIDv zSBxfaQN~)n2K7K1xK8@y;BPNok&S7AWsWexc@z%ncP;!ydbdQDKA|o=mv1nyjwPN} zJsrAeLWRtj1Z=*`L!XqFv0-XlFYTBv47udU!)F35f{CU8Bw{jf3oZ834?(D?=mGQX zhAIb1s(nX)CEQgA?_sV^3pw4ij!mt`FyAhoVbNkRs}2jg(>n9QD?aN7+cT|ivP0JC zR6|jCuuVgVZYLm!1U%>C_C9vm6kA@?8Q0od2^(IU>Tf1lebdE*cSk<}rBAjsRr7CV z)hLD0P;bxsR1+>gXJ(DRkKr2Cjiv(Y>fp5OgqW(4)@P#5+*}}bs$(-92sfWh=ShGT z);9~2A@FPM2rJUrQfWTAEZ&W|EH;TkPi9pWQPjZK+6qNv)!eGsF!>P?y+u_?TWGYf z*7e~o7w2M;3V7<7Z^z84@upbBsXSL_rk01jA%^G0RI{th{tPMjOsAFP_G`;s|WS!LA`oVuO8H^2leVfy?Riu9@MJ`_3A;rdQh(()T;;e z>OsAFP_G`;s|WS!LA`oVuO8I@A3dmFznS_U{8H=HgZeA^=s&_s|LOHt59-x}di9`Q zJ*Za?>eYjK^`Kros8i>)f z^$TqH$3!=umGiG92^i_=spuGS=~$Vmm>B^|hl#npf$dMv!`?u^;HU0H{fEiGz(~XL zb14H`6TpsC04fMzK>+@!=on~!CLIHoHjp#0vvRQ2Gq3{?H-gUg!t(ZjLI972<^L2d z09M3Ltpo6)5G^kK-v9{*UHjjZhpokL)I(WX*VI7I{%;DziuyndVLeQ%lfVl{`S=TEly@i{wr-5flh z_{_VaaZ^iaTn-8x#QR6K3h5p)Mii`=YY^%tIq;QB(3s3B!nMlbWhc^AHy=$K=UolN z1ac|mzvG4k{?G6RUQdU6tq< zll?~K#}bH0Qf!1{5zQHKnTJ6d%8U=_vDM+BO;Cdj1UyU{qZGaA*vRTR$Jn6goUC^K z?*0jZWgZU)e4q4lzrsTS{Z3fQGC^SWrPe$g=Tsc5nE3FoopgQU3o0O-2PJAEGes-xdZ=r^fys9tyx@6JpjPUkHQ7I4d6`*SQ`Z`mCuatvqV#xh^p9o=B zyGUn0#`nu|x*O$J5zvdu_StQ?u*e_a=S}c|p zL7$RJ1yRg~rwUSiEG5b@pR5jn4fa^eU102#5?ol-?A`5`1*wxepY27g`io(klV z5W~I)6>3R-^a@(?o5I^`XfM+B5I$kZ2Jia2*qWZ8#sqR0s@}S0`QlaE2bnXbAC6TY z?~@AmD4Zj9Tu_WsE?&x|PXO=FJnAzI4kL;ORux3v=FWLRWVLOYfwka%4m8P!az2Ws^!X3c}@X>%fzwEO36uJ+HC>h7Hu4C$*t|0qxQ!c^cvb@ zY^E55$O_ugcShaKbWlSk?_G=ry8-mZYD=v_8^I4X!g0&vn0+c)x(<~^#c9nw;T@@z z49a7Q)icqE&%13l|d`8Mf2XW3r|MZETu6 znDl*H#%;#4a5$R>zp*GV>ZJ7-G8DOh%KhGqh|ZD{q$kBl=QP<}h?s0&sVj@=6Ode& zvb>1s3JM$Kgnmeia81TeQ(a?FC)sLVRC2G~U_oMmzQ7ac4-cE-s=dR{%UxfBPtY&VfWkcBs8pWC@Wy8aaOP`b2^e^K11b3J{IFq zZ?s8?q?wU#HAUm!CIm3m8-eUdD7OrjCCCsdV2%xJ<_57?P+NmI_A?8?0CBcEt!T-l zpy)xfJlc&%R#fM}{Gri&a;A_kExeQ4W2O!GJ^-uCpEH)* zh(qn!T_Pj8F}K(aa5~uD2fCA!G>oXT>W%u5rFxiQng~BHhwdUe$6A$UI~jzQr0Y)! zUg>Ny406YzCf|)kFJOQ;Vi}y6;#zJpVdi*7nc@(e=B-gp zgeRAS$Ncn|Fq70Gn)(8Ogh@8%ZR1Pos{OwXfRy8_RbUD&Ml(2V5}k4yA26!vUlICK z6~Pf4OIX`t&k7X*V+YIcv3=NWJy;hZuoF*-#ABf2N6#N<96>Xqh%G1`nZ;xko5Z|v zKJA})+pGZ?=9hNH-$kjHTom%bXT%^j-Nt=y?W5qNtN(hpu8NwZf=)6hC_kz?L};t` zP<4!EI@v-Zas`c5z)lE_*{UH#?sfa~&evxu=Q!&(zg0gSD?kyO(%G5#z-HQl;`WHm zE$Xc1nfQZ8&Fy?@D|Id(rJei5#P#v=`D8n%pZwh|k$Rt$z-1))ifC8c&0#F}p?%dZ zn8n@}WMpsc{kN-`JKn;nT_Xgk_Qv%=1ja1}gqp92t443VI7*?BVS3P+FFiOg-0r8IzXf4KwFF3T`IL^>jBa`M^#TE$)OUgx`rhC>~ZJbG! zb4=RT8PwDBeWI*;Fry9Hfq2j8<;0r#Q%Y0}w;FQ0^c_+>vXL#=+|NMY`Qr-K?c_hd zuh;l0Ojj$bc^hB1gJRJgD6X2{A3gp}jcBmdS0tC$WMfMgV=PiM>uZA`?V6ltmad77 z(a@abwwaRZd&;pdqE#(GZ}D8P6DQrp7sAg<ZiWXQPY|>IK=x zbs^ToYga><83f#g zpd9@H$DJX>b16Df(jHS_j$r@MS!;5`FO1w)xFqpr%sUC2(KzmIHch~_lxu_CDytvl z#SP(Qs+Gx3O6GBEgl4(w89)W0=7ztaa$|#IiK!GB=KJiMIFpnL8it?<6Ml;i-i)r^ z^A3)|$?mb5V$^yO4`nC!{H)QYC{mZKFl;GcZFA{2jP3^<7{VdD*9~LTJ=P-_#IsLE z4cRj~Xthb8$TZ6%(~4YUSTzX6rnZ0dmNfwbYI7C?0?zp{seQJvBBo4v^X>y#(2NPS z()rL^4w>0^nBK#u0(PN~qW3#YM@b;!VYY>SSOnPclzj!bU@#H)uC|bgmoIX!q*}a1gDz$dXf6@@^P(PSm zFWN|P(V`0K6k^TkL(;f_km?%)SJ)$oy~W2jeF+WWEMB6SO@nM1wLT-|;8;+1`HXXZ zL9HtFjWu;Fq$Kd)o32pgLP0B93WKggq}hH{&^GfEkBde11v{QOn+;GTuj_kNvBXWg@-XFUP75s^5md zCrfF=qLU(yrWW}GD+OL?%#X7zGpemsJA}VP^nlg2b!+k73fG?*1FC17ZZf9elT6+S zA^+O+WLDqGw1S*rUZ|1byKHN?W;7ZS&m%`PJJlbWO2hA!^&(k&N|o{QK^=7a-zy^G zdx16XsDGW}w~LtMm7?HvfH&hx*k8m84134gX(*WHK>C>guudO~M@=0VCa;9jHyBR{ znYZ}~N9ryjkACCfL9vQDJZbpBSR{Gxm)L#8&N~}%r7(eZ5MAB7)Xx?SI@0)rQE5ng z3X=$E7>8vYV3Vk`%t8FWiHZiYPB=ueIw-piCq@Bjbf_nXu$alg3x699Dvq&4>VB_^ zu{jM1W7G4z2tSv`2OUI>Qc0u{kg$zkLnweeg9i(1#NLm9FAhTqfhJ86b#bAy#w!J^ z{@q|00Y8*1i6n%A%|1!q-TqwujE_g(25Scb;!_|kq~=QfdzJffJ_68G$fI#k5=tL8 zK7E@oH$Hr9wq*q5B=QFNADN-dO#((2xpkrz5V8>o=o2)^`Z2OK3XDk~5 z_(b=yq#^-Xd}lN{Q+5}5mZ+mRRNo}a4x7bGBksd2@2+7=#)!V=3M9UA<2jDOj;X86 zlt|VJd?HUk#%6 zkf0&u+ca=>qeliJ0lxAsv9J|mI912n2Xj!t@cxHwsqheBFfR_^(7xO-1oci@$`J6a zS^6m>0RfV^!dB$dvHeTPwi~niZzugP?u~VBQwgFVW-=NPBIza4?Q9P-O~4Wb(okKe zG@VvOFJ3LAMtEoq?wQldjI@xxOXMGw=#YDyLRk>0QED#aAjikJ7xM(y7jaKtTsXaK z9Ye&cu|iPq_%(Rz2T--My@T|&_h)FlwZg-ub#K)rkGG|Be6IQq>L_IL!7fU##Q>TAy4A1tVL zwKU&+JkDlAUqX6b_Sc^s$t8-rp6+zETb`1feK-_~pmRKXFmP>-KX~K>(9EFI~-Fd@OYG-ChyxGy6#SyU5B1>1G^rhls z(!2Kq%O91l7K8oCr12$#qe`${@aHu>@3P@)UVvK5uBZQne)n^B=pR!}lGIXGwiY_( z)cm}-02}n@JkOugLw`B8fAf+55?X&rvA8V1p;ngPP%F!CsFmdx)T%)(Y-{CU4VX~k zmj{rvjwX5ra>9Jn^3bzKPDC(_gHNRDjtj76w`> zRyqx8nV&n@~a|$BZI$s`&XC#af1H+oF6MK zE7RX*;6^l-A}|}HJy0^e`cZ%spd83t1~AM~lcE{uRgF)oVDydx6FwbS^2pCj6=5H{ zPd;zc`6LdP=+e+7o9gLAP9Nyf!ud+1Bk zHkk`#38)>E6)aVqhBmKk3BTNy>%QDh)FjpPs8Y=C%QjMLaeH1~lFMH99Nt9Y1ZUH| zAP5o+4Z7EsXC2J7r{HV7EF&x7;BXg(kl$_{_C$K?_m)o$d$UDcTqGt&I)7G-4UEqE4tgg5pC`MQk7L+!t9Px?Ookn z=K?|dqGtcd$%vxWNgax*otKH%hpU~)c>W`3PB&zwIpo^dvubT9i$URKh#s=uuAhb5UZ^u&6^d39KSvgcrJ?MrYIPTQOJyML zu^9_i!ID6!V;Kq|tkeMWS}0POO!b(s>MW_Z++M4k#lhQYVMp|JmDi*{99Xk}atb>E zMa&Fo zQI|UwQKjQRa+f1YdwoXRUNWN2K$)3RN_;5RtzOc4Jl;Ll9}OB5f)bhi7;1y=tF@+a zm*Lq7aSYZeAgR~JeD_Q}&O3PNM;z!&JF$>hz_l0NuJk3&<7`IpAs^hp%k|jn>d8q! zGFvt`ZYrf0e2juL?X0NE0^`C+3CQ8HN$4=ilHS7D)!rJ~iDBpMxK-N_`-Mv^+2^qb z3prUR-;p2dGUKqpv}F4-jO)Eki{Ya*RDvbXXUq!b`j3v2AKr}b(*t|H`4Sz0_9g&m zq+V9(%lWz!*j@~Riyf#0H!#iCj#CVR4~J~u$>JF?>fHjxtE%3Mn^8dt^wYeH+78* zNxN3WBPS-+aG5Sk+h;|~1G;zRJG;xSFRD3;bu*&+-z%} z>^~AVB1FYpYy{0LOW6qDh zd3iLgjm<7b0UI;d*=t9-U%1}(pE+UkkV5kawiChlfq(1ZTE-|4emt9f?qA=YXGbV! znnE*~Ks%!3bb|x_1n2I|H+Vhup0sa|^!h4VrWA}V!dmHQh`>WWGMGik;>u53dSPaf zrK3#$ZD7>nGCw$ovm+xXin{Vb=Oo2OC*2X`6)-V-X^_EO6aBHS&+4vkGTxkoNQ8P$ zl(J>*PIqN|4RK#7vRh3$aJ}gzQ%=9Ps_aGkys6@M@d(Z8brXonwA_HJqXST~DznKN z%;qK?o&1KoJ*?&wv7!so6C=IpmDR_y_xN!EOjJ!5jg4=_SX%!#%ts@BfYU9p~7gd22X2iaoP?R zUC@R+3oQVVum(*`*+HIYdDcLjT<4J?*Dtsnj2VrKIG*Ngd!2l}3qfq&E8|n=Z13%W z_6Dtc)n|SY&l5bqcR@O;I|2~owA7MH`-K(mVAFjW==I)GhLzy(d_+m3*kM>Px`&dn?D*^Vt2rq z5#mDWdw6YZh)3RA5`V-n3eijHPG)h(jNI9XRS48cy#um&7os;VAwzX7*xI;INj<_E zknF5+WHzzH(J>>9wlLb-s*HNxeBlAQ>0oad#RUW@V8UZQa)(VK;tX&Mz4f35Xze@7Gd^Q_k1Ute zyL6tC(K}@35od`hGxTj31r%Fzn2k-c(F3d3rxl%b;|X#44hO!HBC*EFTayrFK>tf;0v>lK z`d${GDlK|t5GtB&0awQSqs`jEwI?Z6a$VVSN^{emjSSThWL4rU6?(Q@wX+^TeZW$I zQX^rz#FC{8nH2ROGFdDgq_4!OAY$phyQ)rb{IIkLe)F;&(~}#ZGcWPk(ZQtB0juX; z>S{z^pW?LTw_Ez+SalZSv}PCD3Cly>A;0E}3KcNBN)^tB#!-E&;RKZiY^9pz z4#IUiSi_<2Mmt^=u-G>}tVxt42z0zzzGyuRtm%(C5nX+iCRAJ;ep0B%0YE(y#>54h zNh*QwkeD`T=1~JV5K`^>2ULjq@T|}RIZ%om`V%GT5Y*)ZTTTwDu>DiVBDESm>|dZ1 zn)--)3w|J>k&6e0G3p>3(}unx993d@m>Ol%_?AV)eM7_dc2%W(g#HRTdXlz{Z90}( zF0*S4OkoI1R8Rd%LPF|mH*F<;4|*IDDb{X*+7EF-F@Jdt%=_nJiz3c7lNIM0Msx`y_2^UYn`m?2yHqf}46Z;Jp-}L7d^hKNQ^f`19 z-fY1ZMg&&-hLvO1Ak20nzGeH`j$qX00VxH zBSW<~D~k16*Btma{_p#QsQ$e9x;NZWGlK{DD=W_*ygoBm)0iG~!koZKbh#SZ*%@}> z(#NYZz)A7YrlwZ&qIIU7DXy&9-m*B+!f9zR=9(kN^a0OZHps5n8>Av<*8vjQ_+f#TNv)E>r>6G6CYce?d1xbXQR{F-xm7jv)HX)~pe7 zDH6C{9SyICek}Jaz*K1;r%Po1D}s?Xo&RieL|`! z?2t*}zC>r3Hfprq+qa@2hl&i@UUC+RQ1F~i=SL$SxIeqWK%_*yG+2v|MLQ6;Na5!9 zY}mvIf5M#F$);P&@-AVqqHNys>M}!YhxN`}C#XEE}_F}yk`|<$L&C{ zDW3#d=-0>Z0z`OC+8tk?zRO4tO4nh**ZHSeQQ$$b)O_E?7WxQZ7cbK+hRZfJVjT+- z>kfHf@?g%5rc1N?FzxDCB45%B8)p}{mB}K!pc;1-3zFzC=sgB_VO%(ZE)^kkn7kG; z{VFaIeb!~rvZN}aYJF1r&L*0)*Y9)e>0Nr&I-TtHrd^pWCe9(5-F|+RY*sNQSWn~N z98WjTf>Oa)C^NI;E{XYB4V%Z0*o})|uzsebjniRJ@*Ej^>DqbA#_g3!9V@eGAn4Lr zlJNA?MIQePrXk1yj0yzl zoTgPj%{B+;sD59G+RvHAyIhqlTS3)gM2Ww!+$?y`S%pc&Cv$T=;>D+~cqqilDk{Xm zLn3^*TJ(r%sf2(GRuObVKrGlomro9Hk_dwE7(}W~z3#!e8kv;P z8PE)y`2^ndSy0^TL>n5!nLE43P0^5WmdMWdi$aZlB9gf*P^vxZt+*^iy#QgqyK3

OG)f>E@hoT& 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 z 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�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

sVK3jwsn+Br^X6)T# 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%0DgH@2Vx-tHotv2lL#0W_*Hs& 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¬iZbX-4&~->4G~C68=n{8!H>0oC;EF$xbOF( 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%0AuriLTTqNzYK?UDB01O0uTcCgWlL)fl9gRns@ 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�at2yFnl}ck6H6

h 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%0Al;@o(?V4GB7>{BlzO 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 z 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∨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

rW|OaaUOZ`Jmt`}F?Bm%VWV6|Q%#HhMUILd` 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

^KA<_tbc##?sPkauqN zK5DFzI`U+1Z}b%}MCFp_!65>v7p9$mQ0VE{m(+M7cHBQs{YX48I^Po3n(p~G;|i3h z4dsP;_4g>YPbqaL64X5XB1}9*Lp^U5oNLbTi=%f0##~JhiA0!5c^vDir_GWWxJ>&F zdeE*W5_T$5lhJ6dX2lM7C%?sX7cs1DtD@(Qcx~8&QJrKj&BhGz*e1eg^rsFTr1pRg z!VWo$#T5OlUf{5Ul3O?YLQyX-KWnx&^r{o^?1lOgiJKPR6in~gZeN#R%{Ha+s^SZW~ibLym`20gNe7O6|*O!}n+>?URoR*qJw0BRv zbPmcH#E&BvMSRO_o^mhH@HoGRDF-oFKE2=c{RaXNg-NdVwir;!v9s+;@r(^UD+vGV zl}$nIxNd>G{LTY~hd z1l;)<{i%JIau41bcwJ3hpaa;_n&vZ6lUuGNgc8qH zoz^aGULg+?#FixDo2~GVPVr?kPyuE2g1~hAcH^jopQq3Tq#0pz-Pv9+X&{@?u_j@x6{s@ZYt} z*eGER|D_^=>6>>_cLJHqsu8^Y7WL0GMOrK;StFx$)L(Ws$lwCaRE{F>sSP~BXH;}< zt(Ymut1WIMQ|@w}ykMYrM!kJkby*9p-0l0qovd&7*fQaB*Ohu})mL`BD@WeM*0}Kc zF60GQnRFHAj$&09$^a=pLai&KUX|~s$nvdWiH$iF^$K%|!w=Q9$fkS$)fCH@CV}uL z<$mxCFz5xGTnAv{g9X@|{(cHozpIZ(jLXFPHbU21HApQq{3MR@i|FYkttI7QdP8d$ z7eZb>Z3gqLn=Kl@1)#u39Zb`Y+9&IaYv-e<-i+sWOJw#i^-`KWtgt)pD& z)xc_4>6Oc*m$#g9rYP%`(KQLnU-D%e`xmKhZJ;cS{do)7fVXUs1sEZlT}Ls^G4NiR zgPMJdc$c?!y&`L>9`jE>C8nugF~m_Vf!2n&dk}?ZxEG`?+OgqNdMkMZ{@&ag;VVg< z7X?HHCD(?2!1MmEHS44mN*jZ|Pv&JU$}HpxOnsgk(!<{1m!W!C+_3ngN}KI%XhfDl z+>Dkf(^nJ0oqW4Y9r$Xf%p}UgRq6Y(P4gb=J!>Gs46tEn8J_0O4in;tR8J3q)cR!% zUNhVM3kVU#ldWT3ZKiptVnnw>SzeWw2oKP11;EvuiasKyEc^HR^62%?PA;i2EE2qh#qf#

Sw&h&*NLa1Q+1N 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
Y`n4-oE
+#include "esp_err.h"
+
+/**
+ * @brief Abstract base class for stepper motor driver chips.
+ * 
+ * This interface abstracts the low-level control of the stepper motor driver,
+ * such as enabling/disabling, setting direction, sleep mode, and microstepping configuration.
+ * It does NOT handle step generation (that is handled by the StepperMotor class using GPTimer).
+ */
+class StepperDriver
+{
+public:
+    virtual ~StepperDriver() = default;
+
+    /**
+     * @brief Initialize the driver hardware (GPIOs, IO Expander, etc.)
+     * @return ESP_OK on success
+     */
+    virtual esp_err_t Init() = 0;
+
+    /**
+     * @brief Enable or disable the motor driver output.
+     * @param enable true to enable, false to disable
+     * @return ESP_OK on success
+     */
+    virtual esp_err_t Enable(bool enable) = 0;
+
+    /**
+     * @brief Set the motor direction.
+     * @param dir true for one direction (e.g. UP/CW), false for the other (e.g. DOWN/CCW)
+     * @return ESP_OK on success
+     */
+    virtual esp_err_t SetDirection(bool dir) = 0;
+
+    /**
+     * @brief Set the motor driver to sleep mode to save power.
+     * @param sleep true to sleep, false to wake up
+     * @return ESP_OK on success
+     */
+    virtual esp_err_t Sleep(bool sleep) = 0;
+
+    /**
+     * @brief Set microstepping mode.
+     * @param microsteps Microstepping value (e.g., 1, 2, 4, 8, 16, 32, etc.)
+     * @return ESP_OK on success
+     */
+    virtual esp_err_t SetMicrosteps(int microsteps) = 0;
+};
+
+#endif // STEPPER_DRIVER_H
diff --git a/main/05_executors/adc_battery_monitor/adc_battery_monitor.cc b/main/05_executors/adc_battery_monitor/adc_battery_monitor.cc
new file mode 100644
index 0000000..de47bfd
--- /dev/null
+++ b/main/05_executors/adc_battery_monitor/adc_battery_monitor.cc
@@ -0,0 +1,167 @@
+#include "adc_battery_monitor.h"
+#include 
+
+#define TAG "AdcBatteryMonitor"  ///< 日志标签,用于ESP-IDF日志系统
+
+AdcBatteryMonitor::AdcBatteryMonitor(BoardSweekar& board, adc_unit_t adc_unit, adc_channel_t adc_channel, float upper_resistor, float lower_resistor)
+    : board_(board) {
+    
+    // Initialize ADC battery estimation
+    adc_battery_estimation_t adc_cfg = {
+        .internal = {
+            .adc_unit = adc_unit,
+            .adc_bitwidth = ADC_BITWIDTH_DEFAULT,
+            .adc_atten = ADC_ATTEN_DB_12,
+        },
+        .adc_channel = adc_channel,
+        .upper_resistor = upper_resistor,
+        .lower_resistor = lower_resistor
+    };
+    adc_cfg.charging_detect_cb = [](void *user_data) -> bool {
+        AdcBatteryMonitor *self = (AdcBatteryMonitor *)user_data;
+        return self->IsCharging();
+    };
+    adc_cfg.charging_detect_user_data = this;
+    adc_battery_estimation_handle_ = adc_battery_estimation_create(&adc_cfg);
+
+    // Initialize timer
+    esp_timer_create_args_t timer_cfg = {
+        .callback = [](void *arg) {
+            AdcBatteryMonitor *self = (AdcBatteryMonitor *)arg;
+            self->CheckBatteryStatus();
+        },
+        .arg = this,
+        .name = "adc_battery_monitor",
+        .skip_unhandled_events = false,
+    };
+    ESP_ERROR_CHECK(esp_timer_create(&timer_cfg, &timer_handle_));
+    ESP_ERROR_CHECK(esp_timer_start_periodic(timer_handle_, 1000000));
+}
+
+// 注册ADC电池回调函数
+void AdcBatteryMonitor::AdcBatteryMonitor_Init(void) {
+    ESP_LOGI(TAG, "注册ADC电池回调函数");
+        // 设置默认的电池状态回调函数
+    OnNotCharging([]() {
+        ESP_LOGI(TAG, "电池未充电状态回调 - 默认处理");
+    });
+    
+    OnFull([]() {
+        ESP_LOGI(TAG, "电池充满电状态回调 - 默认处理");
+    });
+    
+    OnCharging([]() {
+        ESP_LOGI(TAG, "电池充电中状态回调 - 默认处理");
+    });
+}
+
+AdcBatteryMonitor::~AdcBatteryMonitor() {
+    if (adc_battery_estimation_handle_) {
+        ESP_ERROR_CHECK(adc_battery_estimation_destroy(adc_battery_estimation_handle_));
+    }
+    
+    if (timer_handle_) {
+        esp_timer_stop(timer_handle_);
+        esp_timer_delete(timer_handle_);
+    }
+}
+
+bool AdcBatteryMonitor::IsCharging() {
+    // 通过IO扩展板读取充电检测引脚状态
+    // BATTERY_CHRG_PIN连接到P0_5,对应INPUT_PORT0
+    uint8_t port0_data = 0;
+    esp_err_t err = board_.io_expansion_.ReadInputPort0(&port0_data);
+    
+    // 如果读取失败,返回false
+    if (err != ESP_OK) {
+        return false;
+    }
+    
+    // 检查BATTERY_CHRG_PIN位状态
+    // 当引脚为低电平时表示正在充电
+    return (port0_data & (1 << BATTERY_CHRG_PIN)) == 0;
+}
+
+bool AdcBatteryMonitor::IsDischarging() {
+    return !IsCharging();
+}
+
+uint8_t AdcBatteryMonitor::GetBatteryLevel() {
+    // 如果句柄无效,返回默认值
+    if (adc_battery_estimation_handle_ == nullptr) {
+        printf("adc_battery_estimation_handle_ 为空!\n");
+        return 0;
+    }
+    
+    float capacity = 0;
+    esp_err_t err = adc_battery_estimation_get_capacity(adc_battery_estimation_handle_, &capacity);
+    if (err != ESP_OK) {
+        printf("返回值出错!\n");
+        return 0; // 出错时返回默认值
+    }
+    return (uint8_t)capacity;
+}
+
+void AdcBatteryMonitor::OnChargingStatusChanged(std::function callback) {
+    on_charging_status_changed_ = callback;
+}
+
+void AdcBatteryMonitor::CheckBatteryStatus() {
+    bool new_charging_status = IsCharging();
+    if (new_charging_status != is_charging_) {
+        is_charging_ = new_charging_status;
+        if (on_charging_status_changed_) {
+            on_charging_status_changed_(is_charging_);
+        }
+    }
+}
+
+// 三个电池状态回调函数的实现
+void AdcBatteryMonitor::TriggerNotChrgCallback() {
+    if (on_not_charging_callback_) {
+        on_not_charging_callback_();
+    }
+}
+
+void AdcBatteryMonitor::TriggerFullCallback() {
+    if (on_full_callback_) {
+        on_full_callback_();
+    }
+}
+
+void AdcBatteryMonitor::TriggerChrgCallback() {
+    if (on_charging_callback_) {
+        on_charging_callback_();
+    }
+}
+
+// 注册电池状态回调函数的实现
+void AdcBatteryMonitor::OnNotCharging(std::function callback) {
+    on_not_charging_callback_ = callback;
+}
+
+void AdcBatteryMonitor::OnFull(std::function callback) {
+    on_full_callback_ = callback;
+}
+
+void AdcBatteryMonitor::OnCharging(std::function callback) {
+    on_charging_callback_ = callback;
+}
+
+//CHRG引脚充电前为高电平 充电中为低电平 充满电为高电平   
+//FULL未充满为高电平 充满电为低电平
+bool AdcBatteryMonitor::IsFull() {
+    // 通过IO扩展板读取电池充满检测引脚状态
+    // BATTERY_FULL_PIN连接到P1_3,对应INPUT_PORT1
+    uint8_t port1_data = 0;
+    esp_err_t err = board_.io_expansion_.ReadInputPort1(&port1_data);
+    
+    // 如果读取失败,返回false
+    if (err != ESP_OK) {
+        return false;
+    }
+    
+    // 检查BATTERY_FULL_PIN位状态
+    // 当引脚为低电平时表示电池已充满
+    return (port1_data & (1 << BATTERY_FULL_PIN)) == 0;
+}
\ No newline at end of file
diff --git a/main/05_executors/adc_battery_monitor/adc_battery_monitor.h b/main/05_executors/adc_battery_monitor/adc_battery_monitor.h
new file mode 100644
index 0000000..bbd441e
--- /dev/null
+++ b/main/05_executors/adc_battery_monitor/adc_battery_monitor.h
@@ -0,0 +1,47 @@
+#ifndef ADC_BATTERY_MONITOR_H
+#define ADC_BATTERY_MONITOR_H
+
+#include 
+#include 
+#include 
+#include 
+#include "02_physical/boards/board_sweekar.h"
+
+class AdcBatteryMonitor {
+public:
+    AdcBatteryMonitor(BoardSweekar& board, adc_unit_t adc_unit, adc_channel_t adc_channel, float upper_resistor, float lower_resistor);
+    ~AdcBatteryMonitor();
+
+    bool IsCharging();
+    bool IsDischarging();
+    bool IsFull();  // 电池充满检测函数
+    uint8_t GetBatteryLevel();
+
+    // 注册电池状态回调函数
+    void AdcBatteryMonitor_Init(void);
+    // 三个电池状态回调函数
+    void TriggerNotChrgCallback();  // 触发未充电回调
+    void TriggerFullCallback();     // 触发充满电回调
+    void TriggerChrgCallback();     // 触发充电中回调
+    
+    // 注册电池状态回调函数
+    void OnNotCharging(std::function callback);  // 注册未充电回调
+    void OnFull(std::function callback);        // 注册充满电回调
+    void OnCharging(std::function callback);   // 注册充电中回调
+
+    void OnChargingStatusChanged(std::function callback);
+
+private:
+    BoardSweekar& board_;  // 添加对BoardSweekar的引用
+    adc_battery_estimation_handle_t adc_battery_estimation_handle_ = nullptr;
+    esp_timer_handle_t timer_handle_ = nullptr;
+    bool is_charging_ = false;
+    std::function on_charging_status_changed_;
+    std::function on_not_charging_callback_;  // 未充电回调函数
+    std::function on_full_callback_;          // 充满电回调函数
+    std::function on_charging_callback_;      // 充电中回调函数
+
+    void CheckBatteryStatus();
+};
+
+#endif // ADC_BATTERY_MONITOR_H
diff --git a/main/05_executors/adc_battery_monitor/module.cmake b/main/05_executors/adc_battery_monitor/module.cmake
new file mode 100644
index 0000000..9ca36f8
--- /dev/null
+++ b/main/05_executors/adc_battery_monitor/module.cmake
@@ -0,0 +1,16 @@
+# main/05_executors/adc_battery_monitor/module.cmake
+
+
+# 判断 menuconfig 中的开关
+if(NOT CONFIG_ENABLE_EXEC_ADC_BATTERY_MONITOR AND NOT EARLY_EXPANSION)
+    message(STATUS "  [Skip] adc_battery_monitor module disabled by menuconfig.")
+    return()
+endif()
+
+list(APPEND MODULE_SRCS
+    "05_executors/adc_battery_monitor/adc_battery_monitor.cc"
+)
+
+list(APPEND MODULE_INCLUDE_DIRS
+    "05_executors/adc_battery_monitor"
+)
diff --git a/main/05_executors/base_board_control/base_board_control.cc b/main/05_executors/base_board_control/base_board_control.cc
new file mode 100644
index 0000000..172388d
--- /dev/null
+++ b/main/05_executors/base_board_control/base_board_control.cc
@@ -0,0 +1,257 @@
+#include "base_board_control.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_log.h"
+
+static const char *TAG = "BaseBoardCtrl";
+
+esp_err_t BaseBoardControl::Init(BaseBoardHal *hal)
+{
+    if (hal == nullptr)
+    {
+        ESP_LOGE(TAG, "Init: hal is null");
+        return ESP_ERR_INVALID_ARG;
+    }
+    hal_ = hal;
+    return hal_->Init();
+}
+
+esp_err_t BaseBoardControl::GetAngle(float *angle)
+{
+    if (hal_ == nullptr)
+    {
+        return ESP_ERR_INVALID_STATE;
+    }
+    return hal_->GetAngle(angle);
+}
+
+esp_err_t BaseBoardControl::SendSetAngleAbs(uint16_t angle_deg,
+                                            uint8_t  speed_percent,
+                                            uint8_t  flags)
+{
+    if (hal_ == nullptr)
+    {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    // 角度限制在 0~359 之间
+    if (angle_deg > 359)
+    {
+        angle_deg = static_cast(angle_deg % 360);
+    }
+
+    // 速度百分比限制在 0~100
+    if (speed_percent > 100)
+    {
+        speed_percent = 100;
+    }
+
+    uint8_t payload[4];
+
+    payload[0] = static_cast(angle_deg & 0xFF);        // LSB
+    payload[1] = static_cast((angle_deg >> 8) & 0xFF); // MSB
+    payload[2] = speed_percent;
+    payload[3] = flags;                                         // 预留/扩展位
+
+    return SendFrame(0x01, payload, sizeof(payload));
+}
+
+esp_err_t BaseBoardControl::SendSetAngleRel(int16_t  delta_deg,
+                                            uint8_t  speed_percent,
+                                            uint8_t  flags)
+{
+    if (hal_ == nullptr)
+    {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    if (speed_percent > 100)
+    {
+        speed_percent = 100;
+    }
+
+    uint8_t payload[4];
+
+    // int16_t 直接按补码低字节在前的顺序发
+    uint16_t delta_u = static_cast(delta_deg);
+
+    payload[0] = static_cast(delta_u & 0xFF);          // LSB
+    payload[1] = static_cast((delta_u >> 8) & 0xFF);   // MSB
+    payload[2] = speed_percent;
+    payload[3] = flags;                                         // 预留/扩展位
+
+    return SendFrame(0x02, payload, sizeof(payload));
+}
+
+esp_err_t BaseBoardControl::SendSetMotorMove(MotorMode mode, uint8_t speed_percent, uint16_t duration_ms)
+{
+    if (hal_ == nullptr)
+    {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    if (speed_percent > 100) {
+        speed_percent = 100;
+    }
+
+    uint8_t payload[4];
+
+    payload[0] = mode;
+    payload[1] = speed_percent;
+    payload[2] = static_cast(duration_ms & 0xFF);
+    payload[3] = static_cast((duration_ms >> 8) & 0xFF);
+
+    return SendFrame(0x03, payload, sizeof(payload));
+}
+
+esp_err_t BaseBoardControl::SendSetLedRgb(uint8_t mode,
+                                          uint8_t target_mask,
+                                          uint8_t r,
+                                          uint8_t g,
+                                          uint8_t b,
+                                          uint8_t speed)
+{
+    if (hal_ == nullptr)
+    {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    if (speed > 100)
+    {
+        speed = 100;
+    }
+
+    uint8_t payload[7];
+
+    payload[0] = mode;         // 灯效模式
+    payload[1] = target_mask;  // 位掩码,指示哪些 LED 生效
+    payload[2] = r;
+    payload[3] = g;
+    payload[4] = b;
+    payload[5] = speed;        // 呼吸/渐变速度
+    payload[6] = 0;            // Reserved,写死为 0
+
+    return SendFrame(0x10, payload, sizeof(payload));
+}
+
+esp_err_t BaseBoardControl::SendFrame(uint8_t cmd,
+                                      const uint8_t *payload,
+                                      uint8_t payload_len)
+{
+    if (hal_ == nullptr)
+    {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    // LEN = CMD(1) + payload_len
+    uint8_t len = static_cast(1u + payload_len);
+
+    // 总长度 = HEAD1 + HEAD2 + LEN + (CMD + payload_len) + CRC = 3 + len + 1
+    size_t frame_len = static_cast(3u + len + 1u);
+    if (frame_len > kMaxFrameLen)
+    {
+        ESP_LOGE(TAG, "SendFrame: frame too long, len=%u", static_cast(frame_len));
+        return ESP_ERR_INVALID_SIZE;
+    }
+
+    uint8_t frame[kMaxFrameLen];
+
+    // 帧头
+    frame[0] = 0xAA;
+    frame[1] = 0x55;
+
+    // LEN 字段:从 CMD 开始计数
+    frame[2] = len;
+
+    // CMD
+    frame[3] = cmd;
+
+    // payload
+    for (uint8_t i = 0; i < payload_len; ++i)
+    {
+        frame[4u + i] = payload[i];
+    }
+
+    uint8_t crc = CRC8(&frame[2], len + 1);  // 从 LEN 开始算起
+
+    // CRC 放在数据之后
+    frame[3u + len] = crc;
+
+    const int kMaxRetries = 5;
+    const int kRetryDelayMs = 50;
+
+    for (int i = 0; i < kMaxRetries; i++)
+    {
+        esp_err_t err = hal_->Send(frame, frame_len);
+        if (err == ESP_OK)
+        {
+            // 等待从机处理并准备好 ACK
+            // 增加延时以确保从机有足够时间写入 I2C 缓冲
+            vTaskDelay(pdMS_TO_TICKS(20));
+
+            uint8_t ack_buf[kAckFrameLen] = {0};
+            err = hal_->Read(ack_buf, kAckFrameLen);
+            if (err == ESP_OK)
+            {
+                // 校验 ACK
+                if (ack_buf[0] == 0xAA && ack_buf[1] == 0x55 &&
+                    ack_buf[2] == 0x01 && ack_buf[3] == 0xFF)
+                {
+                    uint8_t crc = CRC8(&ack_buf[2], 2);
+                    if (crc == ack_buf[4])
+                    {
+                        return ESP_OK; // 握手成功
+                    }
+                    else
+                    {
+                        ESP_LOGW(TAG, "ACK CRC Fail: Recv=0x%02X Calc=0x%02X", ack_buf[4], crc);
+                    }
+                }
+                else
+                {
+                    ESP_LOGW(TAG, "Invalid ACK: %02X %02X %02X %02X", 
+                             ack_buf[0], ack_buf[1], ack_buf[2], ack_buf[3]);
+                }
+            }
+            else
+            {
+                ESP_LOGW(TAG, "Read ACK Failed: %s", esp_err_to_name(err));
+            }
+        }
+        else
+        {
+            ESP_LOGW(TAG, "Send Failed: %s", esp_err_to_name(err));
+        }
+
+        // 重试前等待
+        vTaskDelay(pdMS_TO_TICKS(kRetryDelayMs));
+    }
+
+    ESP_LOGE(TAG, "SendFrame Failed after %d retries", kMaxRetries);
+    return ESP_FAIL;
+}
+
+uint8_t BaseBoardControl::CRC8(const uint8_t *data, size_t len)
+{
+    uint8_t crc = 0x00;
+
+    for (size_t i = 0; i < len; ++i)
+    {
+        crc ^= data[i];
+
+        for (int b = 0; b < 8; ++b)
+        {
+            if (crc & 0x80)
+            {
+                crc = static_cast((crc << 1) ^ 0x07);
+            }
+            else
+            {
+                crc = static_cast(crc << 1);
+            }
+        }
+    }
+
+    return crc;
+}
diff --git a/main/05_executors/base_board_control/base_board_control.h b/main/05_executors/base_board_control/base_board_control.h
new file mode 100644
index 0000000..5d2e98f
--- /dev/null
+++ b/main/05_executors/base_board_control/base_board_control.h
@@ -0,0 +1,63 @@
+// base_board_control.h
+#pragma once
+
+#include 
+#include "esp_err.h"
+#include "base_board_hal.h"
+
+class BaseBoardControl
+{
+public:
+    /** 帧最大长度,按你的协议冗余留一点空间 */
+    static constexpr size_t kMaxFrameLen = 16;
+    /** ACK 帧长度: HEAD(2) + LEN(1) + CMD(1) + CRC(1) = 5 */
+    static constexpr size_t kAckFrameLen = 5;
+
+    BaseBoardControl() = default;
+    ~BaseBoardControl() = default;
+
+    esp_err_t Init(BaseBoardHal *hal);
+
+    /** 发送绝对角度命令 CMD=0x01 */
+    esp_err_t SendSetAngleAbs(uint16_t angle_deg,
+                              uint8_t  speed_percent,
+                              uint8_t  flags = 0);
+
+    /** 发送相对角度命令 CMD=0x02 */
+    esp_err_t SendSetAngleRel(int16_t  delta_deg,
+                              uint8_t  speed_percent,
+                              uint8_t  flags = 0);
+
+    /** 电机工作模式枚举 */
+    enum MotorMode
+    {
+        MotorOff = 0,
+        MotorForward = 1,
+        MotorBackward = 2
+    };
+
+    /** 发送电机开环控制命令 CMD=0x03 */
+    esp_err_t SendSetMotorMove(MotorMode mode, uint8_t speed_percent, uint16_t duration_ms);
+
+    /** 发送 RGB 命令 CMD=0x10 */
+    esp_err_t SendSetLedRgb(uint8_t mode,
+                            uint8_t target_mask,
+                            uint8_t r,
+                            uint8_t g,
+                            uint8_t b,
+                            uint8_t speed);
+
+    /** 获取当前角度 */
+    esp_err_t GetAngle(float *angle);
+
+private:
+    BaseBoardHal *hal_ = nullptr;
+
+    /** 通用打包 + 发送接口:传 CMD 和 payload,内部加头、LEN、CRC */
+    esp_err_t SendFrame(uint8_t cmd,
+                        const uint8_t *payload,
+                        uint8_t payload_len);
+
+    /** CRC8 工具函数 */
+    static uint8_t CRC8(const uint8_t *data, size_t len);
+};
diff --git a/main/05_executors/base_board_control/module.cmake b/main/05_executors/base_board_control/module.cmake
new file mode 100644
index 0000000..dfa063d
--- /dev/null
+++ b/main/05_executors/base_board_control/module.cmake
@@ -0,0 +1,16 @@
+# main/05_executors/base_board_control/module.cmake
+
+
+# 判断 menuconfig 中的开关
+if(NOT CONFIG_ENABLE_EXEC_BASE_BOARD_CONTROL AND NOT EARLY_EXPANSION)
+    message(STATUS "  [Skip] base_board_control module disabled by menuconfig.")
+    return()
+endif()
+
+list(APPEND MODULE_SRCS
+    "05_executors/base_board_control/base_board_control.cc"
+)
+
+list(APPEND MODULE_INCLUDE_DIRS
+    "05_executors/base_board_control"
+)
diff --git a/main/05_executors/gyroscope/gyroscope.cc b/main/05_executors/gyroscope/gyroscope.cc
new file mode 100644
index 0000000..af1b475
--- /dev/null
+++ b/main/05_executors/gyroscope/gyroscope.cc
@@ -0,0 +1,625 @@
+#include "gyroscope.h"
+#include "freertos/idf_additions.h"
+
+Gyroscope::Gyroscope()
+{
+    bus_handle_ = nullptr;
+    on_shake_callback_ = nullptr;  // 初始化回调函数
+    on_pickup_callback_ = nullptr; // 初始化拿起回调函数
+    on_putdown_callback_ = nullptr; // 初始化放置回调函数
+    on_tilt_callback_ = nullptr;   // 初始化倾斜回调函数
+    timer_handle_ = nullptr;         // 初始化定时器句柄
+    pGyroscopeTaskStackBuffer_ = nullptr;
+    pxGyroscopeTaskBuffer_ = nullptr;
+    
+    // 初始化滤波相关变量
+    last_filtered_x_ = 0;
+    last_filtered_y_ = 0;
+    last_filtered_z_ = 0;
+    is_first_sample_ = true;
+}
+
+Gyroscope::~Gyroscope()
+{
+    // 删除定时器
+    DeleteTimer();
+    
+    if (pGyroscopeTaskStackBuffer_) {
+        free(pGyroscopeTaskStackBuffer_);
+        pGyroscopeTaskStackBuffer_ = nullptr;
+    }
+    if (pxGyroscopeTaskBuffer_) {
+        vPortFree(pxGyroscopeTaskBuffer_);
+        pxGyroscopeTaskBuffer_ = nullptr;
+    }
+}
+
+/**
+ * @brief 创建500ms周期定时器
+ * @return esp_err_t 创建结果
+ */
+esp_err_t Gyroscope::CreateTimer()
+{
+    if (timer_handle_ != nullptr) {
+        ESP_LOGW(TAG_GYROSCOPE, "定时器已存在");
+        return ESP_OK;
+    }
+
+    // 配置定时器参数
+    esp_timer_create_args_t timer_args = {};
+    timer_args.callback = &TimerCallback;  // 静态回调函数
+    timer_args.arg = this;                 // 传入实例指针
+    timer_args.name = "gyro_timer";        // 定时器名称
+    timer_args.dispatch_method = ESP_TIMER_TASK;  // 使用任务调度
+    timer_args.skip_unhandled_events = false;     // 不跳过未处理事件
+
+    // 创建定时器
+    esp_err_t err = esp_timer_create(&timer_args, &timer_handle_);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG_GYROSCOPE, "创建定时器失败: 0x%x", err);
+        return err;
+    }
+
+    // 启动定时器,500ms周期重复
+    err = esp_timer_start_periodic(timer_handle_, 50000); // 50000微秒 = 50ms   20hz
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG_GYROSCOPE, "启动定时器失败: 0x%x", err);
+        esp_timer_delete(timer_handle_);
+        timer_handle_ = nullptr;
+        return err;
+    }
+
+    ESP_LOGI(TAG_GYROSCOPE, "50ms周期定时器创建并启动成功");
+    return ESP_OK;
+}
+
+/**
+ * @brief 停止并删除定时器
+ */
+void Gyroscope::DeleteTimer()
+{
+    if (timer_handle_ == nullptr) {
+        return;
+    }
+
+    // 停止定时器
+    esp_err_t err = esp_timer_stop(timer_handle_);
+    if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
+        ESP_LOGE(TAG_GYROSCOPE, "停止定时器失败: 0x%x", err);
+    }
+
+    // 删除定时器
+    err = esp_timer_delete(timer_handle_);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG_GYROSCOPE, "删除定时器失败: 0x%x", err);
+    }
+
+    timer_handle_ = nullptr;
+    ESP_LOGI(TAG_GYROSCOPE, "定时器已删除");
+}
+
+/**
+ * @brief 静态定时器回调函数
+ * @param arg 传入的Gyroscope实例指针
+ */
+void Gyroscope::TimerCallback(void* arg)
+{
+    Gyroscope* gyroscope = static_cast(arg);
+    if (gyroscope) {
+        gyroscope->TimerInterruptHandler();
+    }
+}
+
+/**
+ * @brief 定时器中断处理函数
+ * 每50ms调用一次,可以在这里执行周期性任务
+ */
+void Gyroscope::TimerInterruptHandler()
+{
+    // 在这里添加定时器中断处理逻辑
+    // 例如:读取传感器数据、检测动作、发送状态等
+    AccelerationData accel_data_ = {0};
+    
+    esp_err_t err = GetAcceleration(&accel_data_);
+    if (err == ESP_OK) {
+        // 根据实际安装方式重新定义姿态判断
+        // 平放状态:Y轴接近±1g(因为Y轴垂直于桌面),X和Z轴接近0
+        bool is_flat = (fabs(accel_data_.y) > 0.85 && fabs(accel_data_.y) < 1.15) && 
+                       (fabs(accel_data_.x) < 0.15 && fabs(accel_data_.z) < 0.15);
+        
+        // 手持状态:Y轴接近0,X和Z轴中至少有一个有明显值
+        bool is_held = (fabs(accel_data_.y) < 0.7) && 
+                       (fabs(accel_data_.x) > 0.15 || fabs(accel_data_.z) > 0.15);
+        
+        // 计算合成加速度(总加速度大小)
+        float total_accel = sqrt(accel_data_.x * accel_data_.x + 
+                                accel_data_.y * accel_data_.y + 
+                                accel_data_.z * accel_data_.z);
+        
+        // 计算与上次合成加速度的差值(加速度变化量)
+        float total_accel_diff = fabs(total_accel - total_accel_last_);
+        
+        // 计算Y轴加速度变化
+        float y_diff = accel_data_.y - accel_data_y_last_;
+        
+        // 检测是否处于平放稳定状态
+        if(is_flat) {
+            stable_count_++;
+            if(stable_count_ >= 8) {  // 连续8次检测到平放状态(400ms),减少误判
+                stable_count_ = 8;    // 防止溢出
+                if(!is_stable_) {
+                    ESP_LOGI(TAG_GYROSCOPE, "定时器: 检测到稳定平放状态 (x:%.2f, y:%.2f, z:%.2f, total:%.2f)", 
+                             accel_data_.x, accel_data_.y, accel_data_.z, total_accel);
+                    is_stable_ = true;
+                    is_lifted_ = false;    // 重置拿起状态
+                    putdown_count_ = 0;    // 重置放置计数器
+                    lift_count_ = 0;       // 重置拿起计数器
+                    
+                    // 调用放置回调
+                    if (on_putdown_callback_) {
+                        on_putdown_callback_();
+                    }
+                }
+            }
+        } 
+        else {
+            stable_count_ = 0;  // 不在范围内则重置稳定计数器
+            
+            // 如果之前是稳定状态,检测是否有拿起动作
+            if(is_stable_) {
+                // 检测拿起动作的多种特征:
+                // 1. Y轴从接近1g变为接近0g(位置变化)
+                // 2. 合成加速度有显著变化(表示有加速度)
+                bool y_change_indicates_lift = fabs(y_diff) > 0.25;
+                bool total_accel_change_indicates_lift = total_accel_diff > 0.3; // 检测加速度突变
+                
+                if(y_change_indicates_lift || total_accel_change_indicates_lift) {
+                    lift_count_++;
+                    if(lift_count_ >= 1) {  // 降低拿起检测阈值,提高灵敏度
+                        ESP_LOGI(TAG_GYROSCOPE, "定时器: 检测到拿起动作 (x:%.2f, y:%.2f, z:%.2f, total:%.2f, y_diff:%.2f, accel_diff:%.2f)", 
+                                 accel_data_.x, accel_data_.y, accel_data_.z, total_accel, y_diff, total_accel_diff);
+                        is_stable_ = false;  // 重置状态
+                        is_lifted_ = true;   // 设置拿起状态
+                        lift_count_ = 0;
+                        stable_count_ = 0;
+                        
+                        // 调用拿起回调
+                        if (on_pickup_callback_) {
+                            on_pickup_callback_();
+                        }
+                    }
+                } else {
+                    lift_count_ = 0;  // 变化不符合预期,重置拿起计数器
+                }
+            }
+            // 如果之前是被拿起状态,检测是否有放置动作
+            else if(is_lifted_) {
+                // 检测从手持到平放的变化 - Y轴从接近0g变为接近1g
+                bool y_change_indicates_putdown = (y_diff > 0.25 && y_diff < 0.80);
+                
+                if(y_change_indicates_putdown) {
+                    putdown_count_++;
+                    if(putdown_count_ >= 3) {  // 连续3次检测到缓慢变化
+                        ESP_LOGI(TAG_GYROSCOPE, "定时器: 检测到缓慢放置动作 (x:%.2f, y:%.2f, z:%.2f, total:%.2f, y_diff:%.2f)", 
+                                 accel_data_.x, accel_data_.y, accel_data_.z, total_accel, y_diff);
+                        is_lifted_ = false;  // 重置拿起状态
+                        putdown_count_ = 0;
+                        
+                        // 调用放置回调
+                        if (on_putdown_callback_) {
+                            on_putdown_callback_();
+                        }
+                    }
+                } else {
+                    putdown_count_ = 0;  // 变化不符合预期,重置放置计数器
+                }
+            }
+            
+            // 检测倾斜动作 - 仅当手持时才触发倾斜
+            if (is_held && (fabs(accel_data_.x) > 0.3f || fabs(accel_data_.z) > 0.3f)) {
+                // 检测到倾斜,调用倾斜回调
+                if (on_tilt_callback_) {
+                    on_tilt_callback_();
+                }
+            }
+        }
+        // 保存当前值作为下一次的上一次值
+        accel_data_y_last_ = accel_data_.y;
+        total_accel_last_ = total_accel;
+    }
+}
+/**
+ * @brief 注册摇晃检测回调函数
+ * 
+ * @param callback 当检测到摇晃时调用的回调函数
+ */
+void Gyroscope::OnShake(std::function callback)
+{
+    on_shake_callback_ = callback;
+}
+
+/**
+ * @brief 注册拿起检测回调函数
+ * 
+ * @param callback 当检测到设备被拿起时调用的回调函数
+ */
+void Gyroscope::OnPickUp(std::function callback)
+{
+    on_pickup_callback_ = callback;
+}
+
+/**
+ * @brief 注册放置检测回调函数
+ * 
+ * @param callback 当检测到设备被放置时调用的回调函数
+ */
+void Gyroscope::OnPutDown(std::function callback)
+{
+    on_putdown_callback_ = callback;
+}
+
+/**
+ * @brief 注册倾斜检测回调函数
+ * 
+ * @param callback 当检测到设备倾斜时调用的回调函数
+ */
+void Gyroscope::OnTilt(std::function callback)
+{
+    on_tilt_callback_ = callback;
+}
+
+/**
+ * @brief 静态中断处理函数
+ * 
+ * @param arg 传入的Gyroscope实例指针
+ */
+void IRAM_ATTR Gyroscope::GpioIsrHandler(void* arg)
+{
+    Gyroscope* gyroscope = static_cast(arg);
+    if (gyroscope) {
+        gyroscope->interrupt_flag_ = true;
+    }
+}
+
+/**
+ * @brief 向陀螺仪寄存器写入数据
+ * 
+ * @param reg 寄存器地址
+ * @param data 要写入的数据
+ * @return esp_err_t ESP_OK表示成功
+ */
+esp_err_t Gyroscope::WriteRegister(uint8_t reg, uint8_t data)
+{
+    if (bus_handle_ == nullptr) {
+        ESP_LOGE(TAG_GYROSCOPE, "I2C总线未初始化");
+        return ESP_FAIL;
+    }
+    
+    return i2c_bus_write_bytes(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1, ®, 1, &data, 1);
+}
+
+/**
+ * @brief 从陀螺仪寄存器读取数据
+ * 
+ * @param reg 寄存器地址
+ * @param data 读取到的数据指针
+ * @return esp_err_t ESP_OK表示成功
+ */
+esp_err_t Gyroscope::ReadRegister(uint8_t reg, uint8_t* data)
+{
+    if (bus_handle_ == nullptr || data == nullptr) {
+        ESP_LOGE(TAG_GYROSCOPE, "参数错误或I2C总线未初始化");
+        return ESP_FAIL;
+    }
+    
+    return i2c_bus_read_bytes(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1, ®, 1, data, 1);
+}
+
+/**
+ * @brief 批量读取陀螺仪寄存器数据
+ * 
+ * @param reg 起始寄存器地址
+ * @param data 读取到的数据指针
+ * @param length 要读取的字节数
+ * @return esp_err_t ESP_OK表示成功
+ */
+esp_err_t Gyroscope::ReadRegisters(uint8_t reg, uint8_t* data, size_t length)
+{
+    if (bus_handle_ == nullptr || data == nullptr) {
+        ESP_LOGE(TAG_GYROSCOPE, "参数错误或I2C总线未初始化");
+        return ESP_FAIL;
+    }
+    
+    return i2c_bus_read_bytes(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1, ®, 1, data, length);
+}
+
+/**
+ * @brief 初始化陀螺仪中断GPIO
+ * 
+ * @param gpio_num 要初始化的GPIO引脚号
+ * @return esp_err_t ESP_OK表示成功
+ */
+esp_err_t Gyroscope::InterruptGpioInit(gpio_num_t gpio_num)
+{
+    gpio_config_t io_conf = {};
+    io_conf.intr_type = GPIO_INTR_POSEDGE;  // 上升沿触发
+    io_conf.pin_bit_mask = (1ULL<x = raw_x * ACCEL_SENSITIVITY_2G / 1000.0f;
+    data->y = raw_y * ACCEL_SENSITIVITY_2G / 1000.0f;
+    data->z = raw_z * ACCEL_SENSITIVITY_2G / 1000.0f;
+
+    return ESP_OK;
+}
+
+/**
+ * @brief 陀螺仪读取任务
+ * Y轴立起   Z轴躺下
+ * 该任务会周期性读取陀螺仪数据并处理中断
+ */
+void IRAM_ATTR Gyroscope::GyroReadTask(void* pvParameters)
+{
+    Gyroscope* gyroscope = static_cast(pvParameters);
+    uint32_t interrupt_count = 0;
+    while (1) {
+        if (gyroscope->interrupt_flag_) {
+            interrupt_count++;
+            gyroscope->ClearInterruptFlags();
+            gyroscope->interrupt_flag_ = false;
+            
+            // 调用用户注册的回调函数
+            if (gyroscope->on_shake_callback_) {
+                gyroscope->on_shake_callback_();
+            }
+            
+            ESP_LOGI(TAG_GYROSCOPE, "累计中断次数: %lu", interrupt_count);
+            if(interrupt_count >= 2){
+                interrupt_count = 0;
+                ESP_LOGI(TAG_GYROSCOPE, "检测到摇晃>>>>>>>>>>");
+            }
+        }
+        vTaskDelay(pdMS_TO_TICKS(50)); // 50ms检查一次,更快的响应
+    }
+}
diff --git a/main/05_executors/gyroscope/gyroscope.h b/main/05_executors/gyroscope/gyroscope.h
new file mode 100644
index 0000000..36e67f8
--- /dev/null
+++ b/main/05_executors/gyroscope/gyroscope.h
@@ -0,0 +1,214 @@
+#ifndef GYROSCOPE_H
+#define GYROSCOPE_H
+
+#include 
+#include 
+#include 
+#include 
+#include "i2c_bus.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/event_groups.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "esp_err.h"
+#include "config.h"
+#include "io_expansion_board.h"
+#include 
+#include "esp_timer.h"
+
+// 加速度数据结构体
+typedef struct {
+    float x;  // X轴加速度 (g)
+    float y;  // Y轴加速度 (g)
+    float z;  // Z轴加速度 (g)
+} AccelerationData;
+
+// 一阶滤波系数
+#define WEIGHTFACTOR 0.93f
+
+/* 陀螺仪寄存器定义 */
+#define CTRL1_XL        0x10    // 加速度计控制寄存器1
+#define CTRL2_G         0x11    // 陀螺仪控制寄存器2  
+#define CTRL3_C         0x12    // 控制寄存器3
+#define CTRL4_C         0x13    // 控制寄存器4
+#define CTRL5_C         0x14    // 控制寄存器5
+#define CTRL6_C         0x15    // 控制寄存器6
+#define CTRL7_G         0x16    // 陀螺仪控制寄存器7
+#define CTRL8_XL        0x17    // 加速度计控制寄存器8
+#define CTRL9_XL        0x18    // 加速度计控制寄存器9
+#define CTRL10_C        0x19    // 控制寄存器10
+#define INT1_CTRL       0x0D    // 中断1控制寄存器
+#define WAKE_UP_DUR     0x5B    // 唤醒持续时间寄存器
+#define WAKE_UP_THS     0x5C    // 唤醒阈值寄存器
+#define TAP_CFG         0x58    // 敲击配置寄存器
+#define TAP_THS_6D      0x59    // 6D方向阈值寄存器
+#define INT_DUR2        0x5A    // 中断持续时间寄存器
+#define MD1_CFG         0x5E    // 中断1配置寄存器
+#define MD2_CFG         0x5F    // 中断2配置寄存器
+#define FUNC_SRC1       0x53    // 功能源寄存器1
+#define WAKE_UP_SRC     0x1B    // 唤醒源寄存器
+
+#define ACCEL_X_L 0x28  // OUTX_L_XL
+#define ACCEL_X_H 0x29  // OUTX_H_XL
+#define ACCEL_Y_L 0x2A  // OUTY_L_XL
+#define ACCEL_Y_H 0x2B  // OUTY_H_XL
+#define ACCEL_Z_L 0x2C  // OUTZ_L_XL
+#define ACCEL_Z_H 0x2D  // OUTZ_H_XL
+
+#define ACCEL_SENSITIVITY_2G 0.061f // 2g 灵敏度 (g/LSB)
+
+#define I2C_MASTER_TIMEOUT_MS         1000            // I2C主设备超时时间(毫秒)
+
+/**
+ * @class Gyroscope
+ * @brief 陀螺仪驱动类,封装芯片操作
+ */
+#define TAG_GYROSCOPE "Gyroscope"
+class Gyroscope
+{
+public:
+    /**
+     * @brief 构造函数
+     */
+    Gyroscope();
+
+    /**
+     * @brief 析构函数
+     */
+    ~Gyroscope();
+
+    /**
+     * @brief 初始化中断引脚
+     * @param gpio_num 中断引脚编号
+     * @return esp_err_t 初始化结果
+     */
+    esp_err_t InterruptGpioInit(gpio_num_t gpio_num);
+
+    /**
+     * @brief 创建陀螺仪读取任务
+     */
+    void CreateGyroReadTask();
+
+    /**
+     * @brief 初始化陀螺仪
+     * @return esp_err_t 初始化结果
+     */
+    esp_err_t Init(i2c_bus_handle_t bus_handle);
+
+    /**
+     * @brief 清除中断标志
+     * @return esp_err_t 清除结果
+     */
+    esp_err_t ClearInterruptFlags();
+
+
+    /**
+     * @brief 获取当前加速度数据
+     * @param data 指向AccelerationData结构体的指针,用于存储读取到的加速度数据
+     * @return esp_err_t 获取结果
+     */
+    esp_err_t GetAcceleration(AccelerationData* data);
+
+    /**
+     * @brief 创建500ms周期定时器
+     * @return esp_err_t 创建结果
+     */
+    esp_err_t CreateTimer();
+
+    /**
+     * @brief 停止并删除定时器
+     */
+    void DeleteTimer();
+
+    /**
+     * @brief 注册摇晃检测回调函数
+     * @param callback 当检测到摇晃时调用的回调函数
+     */
+    void OnShake(std::function callback);
+
+    /**
+     * @brief 注册拿起检测回调函数
+     * @param callback 当检测到设备被拿起时调用的回调函数
+     */
+    void OnPickUp(std::function callback);
+
+    /**
+     * @brief 注册放置检测回调函数
+     * @param callback 当检测到设备被放置时调用的回调函数
+     */
+    void OnPutDown(std::function callback);
+
+    /**
+     * @brief 注册倾斜检测回调函数
+     * @param callback 当检测到设备倾斜时调用的回调函数
+     */
+    void OnTilt(std::function callback);
+
+    i2c_bus_handle_t bus_handle_ = nullptr;    // I2C总线句柄
+    volatile uint8_t interrupt_count_ = 0;     // 中断计数
+    volatile bool interrupt_flag_ = false;     // 中断标志位)(判断是否需要处理)
+
+private:
+    static void GpioIsrHandler(void* arg);    // 中断处理函数
+    static void GyroReadTask(void* pvParameters);
+    static void TimerCallback(void* arg);    // 定时器回调函数
+    
+    void TimerInterruptHandler();  // 定时器中断处理函数
+    
+    esp_err_t WriteRegister(uint8_t reg, uint8_t data);
+    esp_err_t ReadRegister(uint8_t reg, uint8_t* data);
+    esp_err_t ReadRegisters(uint8_t reg, uint8_t* data, size_t length);
+
+    /**
+     * @brief 读取原始加速度数据
+     * @param x 指向X轴加速度存储的指针
+     * @param y 指向Y轴加速度存储的指针
+     * @param z 指向Z轴加速度存储的指针
+     * @return esp_err_t 读取结果
+     */
+    esp_err_t ReadRawAcceleration(int16_t* x, int16_t* y, int16_t* z);
+
+    std::function on_shake_callback_;  // 摇晃回调函数
+    std::function on_pickup_callback_; // 拿起回调函数
+    std::function on_putdown_callback_; // 放置回调函数
+    std::function on_tilt_callback_;   // 倾斜回调函数
+    
+    esp_timer_handle_t timer_handle_ = nullptr;  // 定时器句柄
+
+    /**
+     * @brief 分配静态任务所需的内存
+     * @return bool 分配是否成功
+     */
+    bool AllocateStaticTaskMemory();
+    
+    /**
+     * @brief 释放静态任务分配的内存
+     */
+    void FreeStaticTaskMemory();
+
+    TaskHandle_t xGyroscopeTaskHandle_ = nullptr;
+    StackType_t* pGyroscopeTaskStackBuffer_ = nullptr;    // 任务栈指针(PSRAM)
+    StaticTask_t* pxGyroscopeTaskBuffer_ = nullptr;       // 任务控制块指针(内部RAM)
+
+    // 滤波相关成员变量
+    int16_t last_filtered_x_ = 0;     // 上一次滤波后的X轴值
+    int16_t last_filtered_y_ = 0;     // 上一次滤波后的Y轴值
+    int16_t last_filtered_z_ = 0;     // 上一次滤波后的Z轴值
+    bool is_first_sample_ = true;     // 是否为第一次采样标志
+
+    // 状态检测相关成员变量
+    float accel_data_y_last_ = 0.0f;  // 保存上一次Y轴数据
+    float total_accel_last_ = 1.0f;   // 保存上一次合成加速度值,初始值为1g(平放时的典型值)
+    uint8_t stable_count_ = 0;        // 稳定状态计数器
+    uint8_t lift_count_ = 0;          // 拿起动作计数器
+    uint8_t putdown_count_ = 0;       // 放置动作计数器
+    bool is_stable_ = false;          // 是否处于稳定平放状态
+    bool is_lifted_ = false;          // 是否处于被拿起状态
+};
+
+#endif // GYROSCOPE_H
diff --git a/main/05_executors/gyroscope/module.cmake b/main/05_executors/gyroscope/module.cmake
new file mode 100644
index 0000000..ca0f8aa
--- /dev/null
+++ b/main/05_executors/gyroscope/module.cmake
@@ -0,0 +1,16 @@
+# main/05_executors/gyroscope/module.cmake
+
+
+# 判断 menuconfig 中的开关
+if(NOT CONFIG_ENABLE_EXEC_GYROSCOPE AND NOT EARLY_EXPANSION)
+    message(STATUS "  [Skip] gyroscope module disabled by menuconfig.")
+    return()
+endif()
+
+list(APPEND MODULE_SRCS
+    "05_executors/gyroscope/gyroscope.cc"
+)
+
+list(APPEND MODULE_INCLUDE_DIRS
+    "05_executors/gyroscope"
+)
\ No newline at end of file
diff --git a/main/05_executors/millimeter_wave_radar/millimeter_wave_radar.cc b/main/05_executors/millimeter_wave_radar/millimeter_wave_radar.cc
new file mode 100644
index 0000000..689f4bc
--- /dev/null
+++ b/main/05_executors/millimeter_wave_radar/millimeter_wave_radar.cc
@@ -0,0 +1,202 @@
+#include "millimeter_wave_radar.h"
+#include 
+#include 
+#include 
+#include 
+
+static const char *TAG = "MillimeterWaveRadar";
+
+bool MillimeterWaveRadar::Init() {
+    uart_config_t uart_config = {
+        .baud_rate = MillimeterWaveRadar::BAUD_RATE,
+        .data_bits = UART_DATA_8_BITS,
+        .parity = UART_PARITY_DISABLE,
+        .stop_bits = UART_STOP_BITS_1,
+        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
+        .source_clk = UART_SCLK_DEFAULT,
+    };
+
+    ESP_ERROR_CHECK(uart_param_config(UART_NUM, &uart_config));
+    ESP_ERROR_CHECK(uart_set_pin(UART_NUM, TX_PIN, RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
+    ESP_ERROR_CHECK(uart_driver_install(UART_NUM, 256, 0, 0, NULL, 0));
+
+    // 清空缓冲区
+    uart_flush(UART_NUM);
+    return true;
+}
+
+uint8_t MillimeterWaveRadar::CalculateChecksum(uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4) {
+    return d1 ^ d2 ^ d3 ^ d4;
+}
+
+// 通过查看最高位是0还是1来判断是否是写命令。但是查询感应模式时最高位不是1(5A 11 00 00 00 11 FE),输入的是0x11,所以仅对此条不适用。
+bool MillimeterWaveRadar::IsWriteCommand(uint8_t cmd) {
+    if (cmd == 0x11) {
+        return false;
+    }
+    return (cmd & 0x80) == 0x00; // 写命令高位为0
+}
+
+bool MillimeterWaveRadar::SendFrame(const uint8_t *frame, size_t len) {
+    int written = uart_write_bytes(UART_NUM, frame, len);
+    uart_wait_tx_done(UART_NUM, pdMS_TO_TICKS(10));
+    return written == (int)len;
+}
+
+MillimeterWaveRadar::Result MillimeterWaveRadar::ReceiveFrame(uint8_t *buffer, size_t maxSize, size_t &receivedLen) {
+    TickType_t start = xTaskGetTickCount();
+    size_t total = 0;
+    while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(TIMEOUT_MS)) {
+        size_t available;
+        uart_get_buffered_data_len(UART_NUM, &available);
+        if (available >= 7) {
+            int read = uart_read_bytes(UART_NUM, buffer, 7, pdMS_TO_TICKS(10));
+            if (read == 7) {
+                receivedLen = 7;
+                // 校验帧头尾
+                if (buffer[0] != 0x5A || buffer[6] != 0xFE) {
+                    ESP_LOGW(TAG, "Invalid frame header/tail");
+                    return Result::CHECKSUM_ERROR;
+                }
+                // 校验 checksum
+                uint8_t expected = CalculateChecksum(buffer[1], buffer[2], buffer[3], buffer[4]);
+                if (expected != buffer[5]) {
+                    ESP_LOGW(TAG, "Checksum mismatch");
+                    return Result::CHECKSUM_ERROR;
+                }
+                return Result::OK;
+            }
+        }
+        vTaskDelay(pdMS_TO_TICKS(1));
+    }
+    return Result::TIMEOUT;
+}
+
+MillimeterWaveRadar::Result MillimeterWaveRadar::SetParameter(uint8_t paramId, uint32_t value) {
+    if (!IsWriteCommand(paramId)) {
+        return Result::INVALID_PARAM;
+    }
+
+    uint8_t frame[7];
+    frame[0] = 0x5A;
+    frame[1] = paramId;
+
+    switch (paramId) {
+        case SET_RADAR_DISTANCE_THRESHOLD:
+            if (value < 100 || value > 65000) return Result::INVALID_PARAM;
+            frame[2] = 0x00;
+            frame[3] = (value >> 8) & 0xFF;
+            frame[4] = value & 0xFF;
+            ESP_LOGI(TAG, "Setting distance threshold to %d", static_cast(value));
+            break;
+        case SET_RADAR_DELAY_TIME:
+            if (value > 0xFFFFFF) return Result::INVALID_PARAM;
+            frame[2] = (value >> 16) & 0xFF;
+            frame[3] = (value >> 8) & 0xFF;
+            frame[4] = value & 0xFF;
+            ESP_LOGI(TAG, "Setting delay time to %d", static_cast(value));
+            break;
+        case SET_RADAR_LOCKOUT_TIME:
+            if (value > 0xFFFFFF) return Result::INVALID_PARAM;
+            frame[2] = (value >> 16) & 0xFF;
+            frame[3] = (value >> 8) & 0xFF;
+            frame[4] = value & 0xFF;
+            ESP_LOGI(TAG, "Setting lockout time to %d", static_cast(value));
+            break;
+        case SET_RADAR_LIGHT_SENSOR_ENABLE:
+        case SET_RADAR_OUTPUT_LEVEL:
+        case SET_RADAR_POWER_MODE:
+        case SET_RADAR_TRIGGER_MODE:
+        case SET_RADAR_TX_POWER_LEVEL:
+        case SET_RADAR_PWM_ENABLE:
+        case SET_RADAR_PULSE_WIDTH:
+        case SET_RADAR_SENSING_MODE:
+        case SET_RADAR_SENSING_RESULT:
+            if (value > 0xFF) return Result::INVALID_PARAM;
+            frame[2] = 0x00;
+            frame[3] = 0x00;
+            frame[4] = value & 0xFF;
+            break;
+        case SET_RADAR_LIGHT_THRESHOLD:
+            if (value > 0xFF) return Result::INVALID_PARAM;
+            frame[2] = 0x00;
+            frame[3] = 0x00;
+            frame[4] = value & 0xFF;
+            break;
+        case SET_RADAR_PWM_DUTY:
+            if (value > 3500) return Result::INVALID_PARAM;
+            frame[2] = 0x00;
+            frame[3] = (value >> 8) & 0xFF;
+            frame[4] = value & 0xFF;
+            break;
+        default:
+            return Result::INVALID_PARAM;
+    }
+
+    frame[5] = CalculateChecksum(frame[1], frame[2], frame[3], frame[4]);
+    frame[6] = 0xFE;
+
+    if (!SendFrame(frame, 7)) {
+        return Result::UART_ERROR;
+    }
+
+    uint8_t reply[7];
+    size_t len;
+    Result res = ReceiveFrame(reply, sizeof(reply), len);
+    ESP_LOGW(TAG, "Received raw reply frame: %02X %02X %02X %02X %02X %02X %02X",
+            reply[0], reply[1], reply[2], reply[3], reply[4], reply[5], reply[6]);
+    if (res != Result::OK) return res;
+
+    // 发送保存指令
+    uint8_t saveFrame[7] = {0x5A, 0x20, 0x00, 0x00, 0x01, 0x21, 0xFE};
+    SendFrame(saveFrame, 7);
+    // 等待保存回复(协议注释1:约100ms)
+    vTaskDelay(pdMS_TO_TICKS(110)); // 稍微多等一点
+    uart_flush(UART_NUM); // 清除可能的残留
+
+    return Result::OK;
+}
+
+void MillimeterWaveRadar::OnRadarDetect(RadarDetectCallback callback) {
+    ESP_LOGI(TAG, "Registering radar detection callback");
+    radar_detect_callback_ = callback;
+}
+
+void MillimeterWaveRadar::TriggerRadarDetectCallback() {
+    ESP_LOGI(TAG, "Triggering radar detection callback");
+    if (radar_detect_callback_) {
+        radar_detect_callback_();
+    }
+}
+
+
+
+MillimeterWaveRadar::Result MillimeterWaveRadar::QueryParameter(uint8_t paramId, uint32_t &outputValue) {
+    if (IsWriteCommand(paramId)) {
+        ESP_LOGE(TAG, "Attempted to query with a write command ID: 0x%02X", paramId);
+        return Result::INVALID_PARAM;
+    }
+
+    uint8_t frame[7] = {0x5A, paramId, 0x00, 0x00, 0x00, paramId, 0xFE};
+    ESP_LOGI(TAG, "Sending query frame for param 0x%02X: %02X %02X %02X %02X %02X %02X %02X",
+             paramId, frame[0], frame[1], frame[2], frame[3], frame[4], frame[5], frame[6]);
+
+    if (!SendFrame(frame, 7)) {
+        ESP_LOGE(TAG, "UART send failed");
+        return Result::UART_ERROR;
+    }
+
+    uint8_t reply[7];
+    size_t len;
+    Result res = ReceiveFrame(reply, sizeof(reply), len);
+    if (res != Result::OK) {
+        ESP_LOGW(TAG, "Failed to receive reply for param 0x%02X, error code: %d", paramId, static_cast(res));
+        return res;
+    }
+
+    // 打印原始回复帧(新增功能)
+    ESP_LOGW(TAG, "Received raw reply frame: %02X %02X %02X %02X %02X %02X %02X",
+             reply[0], reply[1], reply[2], reply[3], reply[4], reply[5], reply[6]);
+
+    return Result::OK;
+}
\ No newline at end of file
diff --git a/main/05_executors/millimeter_wave_radar/millimeter_wave_radar.h b/main/05_executors/millimeter_wave_radar/millimeter_wave_radar.h
new file mode 100644
index 0000000..7fd47e5
--- /dev/null
+++ b/main/05_executors/millimeter_wave_radar/millimeter_wave_radar.h
@@ -0,0 +1,82 @@
+#pragma once
+
+#include 
+#include 
+#include 
+
+// 参数名称宏定义(对应协议中的命令)
+#define SET_RADAR_DISTANCE_THRESHOLD      0x01  // 设置感应距离门限值。Data3、Data4 为感应距离门限值,取值范围为 100 ~ 65000【值越大,感应距离越近】
+#define SET_RADAR_DELAY_TIME              0x02  // 设置输出延时时间。取值范围为 0X00~ 0XFFFFFF
+#define SET_RADAR_LIGHT_SENSOR_ENABLE     0x03  // 开关光感。Data4 为 0x01 时开启光感,为 0x00 时关闭光感。
+#define SET_RADAR_LOCKOUT_TIME            0x04  // 设置封锁时间。取值范围为 0X00~ 0XFFFFFF
+#define SET_RADAR_OUTPUT_LEVEL            0x05  // 设置有效电平。Data4 为 0x01 时高电平有效,为 0x00 时低电平有效
+#define SET_RADAR_POWER_MODE              0x06  // 设置功耗模式。Data4 为 0x00 时超低功耗模式(50/60uA),为 0x01 时常规功耗模式(13mA 档位)
+#define SET_RADAR_SENSING_RESULT          0x07  // 设置触发状态。Data4 为 0x00 时触发状态为未触发感应,为 0x01 时触发状态为已触发感应。
+#define SET_RADAR_TRIGGER_MODE            0x0A  // 设置触发模式。Data4 为 0x00 时触发模式为连续触发,为 0x01 时触发模式为单次触发。
+#define SET_RADAR_TX_POWER_LEVEL          0x0B  // 设置发射功率档位。Data4 取值范围为 0~ 7,总共 8 档发射功率可调,值越大,功率越小,=7 时最小,相当于关闭发射功率。发射功率档位值越小,实际发射功率越大,距离越远,抗干扰性越好。
+#define SET_RADAR_LIGHT_THRESHOLD         0x0C  // 设置光感门限值。取值范围为 0X00~ 0XFFFFFF。
+#define SET_RADAR_PWM_ENABLE              0x0D  // 开关 PWM 功能
+#define SET_RADAR_PWM_DUTY                0x0E  // 设置 PWM 占空比
+#define SET_RADAR_PULSE_WIDTH             0x0F  // 设置供电脉冲宽度
+#define SET_RADAR_SENSING_MODE            0x10  // 选择感应模式。Data4 为 0x00 时为移动感应模式,为 0x01 时为手扫感应模式。
+
+// 参数名称宏定义(对应协议中的命令)
+#define QUERY_RADAR_DISTANCE_THRESHOLD      0x81  // 查询感应距离门限值
+#define QUERY_RADAR_DELAY_TIME              0x82  // 查询输出延时时间
+#define QUERY_RADAR_LIGHT_SENSOR_ENABLE     0x83  // 查询开关光感
+#define QUERY_RADAR_LOCKOUT_TIME            0x84  // 查询封锁时间
+#define QUERY_RADAR_OUTPUT_LEVEL            0x85  // 查询有效电平
+#define QUERY_RADAR_POWER_MODE              0x86  // 查询功耗模式
+#define QUERY_RADAR_SENSING_RESULT          0x87  // 查询触发状态
+#define QUERY_RADAR_TRIGGER_MODE            0x8A  // 查询触发模式
+#define QUERY_RADAR_TX_POWER_LEVEL          0x8B  // 查询发射功率档位
+#define QUERY_RADAR_LIGHT_THRESHOLD         0x8C  // 查询光感门限值
+#define QUERY_RADAR_PWM_ENABLE              0x8D  // 查询开关 PWM 功能
+#define QUERY_RADAR_PWM_DUTY                0x8E  // 查询 PWM 占空比
+#define QUERY_RADAR_PULSE_WIDTH             0x8F  // 查询供电脉冲宽度
+#define QUERY_RADAR_SENSING_MODE            0x11  // 查询感应模式
+
+class MillimeterWaveRadar {
+public:
+    // 雷达检测回调函数类型定义
+    typedef std::function RadarDetectCallback;
+    enum class Result {
+        OK,
+        TIMEOUT,
+        CHECKSUM_ERROR,
+        INVALID_PARAM,
+        UART_ERROR
+    };
+
+    // 初始化 UART(使用 UART1, TX=GPIO39, RX=GPIO40)
+    bool Init();
+
+    // 设置参数(自动保存)
+    Result SetParameter(uint8_t paramId, uint32_t value);
+
+    // 查询参数(返回值通过 outputValue 返回)
+    Result QueryParameter(uint8_t paramId, uint32_t &outputValue);
+
+    Result QueryRawResponse(uint8_t paramId);
+    
+    // 注册雷达检测回调函数
+    void OnRadarDetect(RadarDetectCallback callback);
+    
+    // 触发雷达检测回调函数(供IO扩展板调用)
+    void TriggerRadarDetectCallback();
+
+private:
+    static constexpr uart_port_t UART_NUM = UART_NUM_1;
+    static constexpr int TX_PIN = 39;
+    static constexpr int RX_PIN = 40;
+    static constexpr uint32_t BAUD_RATE = 9600;
+    static constexpr uint32_t TIMEOUT_MS = 100;
+    
+    // 雷达检测回调函数
+    RadarDetectCallback radar_detect_callback_ = nullptr;
+
+    bool SendFrame(const uint8_t *frame, size_t len);
+    Result ReceiveFrame(uint8_t *buffer, size_t maxSize, size_t &receivedLen);
+    uint8_t CalculateChecksum(uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4);
+    bool IsWriteCommand(uint8_t cmd);
+};
\ No newline at end of file
diff --git a/main/05_executors/millimeter_wave_radar/module.cmake b/main/05_executors/millimeter_wave_radar/module.cmake
new file mode 100644
index 0000000..6007d55
--- /dev/null
+++ b/main/05_executors/millimeter_wave_radar/module.cmake
@@ -0,0 +1,16 @@
+# main/05_executors/millimeter_wave_radar/module.cmake
+
+
+# 判断 menuconfig 中的开关
+if(NOT CONFIG_ENABLE_EXEC_MILLIMETER_WAVE_RADAR AND NOT EARLY_EXPANSION)
+    message(STATUS "  [Skip] millimeter_wave_radar module disabled by menuconfig.")
+    return()
+endif()
+
+list(APPEND MODULE_SRCS
+    "05_executors/millimeter_wave_radar/millimeter_wave_radar.cc"
+)
+
+list(APPEND MODULE_INCLUDE_DIRS
+    "05_executors/millimeter_wave_radar"
+)
\ No newline at end of file
diff --git a/main/05_executors/photo_interrupter/module.cmake b/main/05_executors/photo_interrupter/module.cmake
new file mode 100644
index 0000000..7cc56bf
--- /dev/null
+++ b/main/05_executors/photo_interrupter/module.cmake
@@ -0,0 +1,16 @@
+# main/05_executors/photo_interrupter/module.cmake
+
+
+# 判断 menuconfig 中的开关
+if(NOT CONFIG_ENABLE_EXEC_PHOTO_INTERRUPTER AND NOT EARLY_EXPANSION)
+    message(STATUS "  [Skip] photo_interrupter module disabled by menuconfig.")
+    return()
+endif()
+
+list(APPEND MODULE_SRCS
+    "05_executors/photo_interrupter/photo_interrupter.cc"
+)
+
+list(APPEND MODULE_INCLUDE_DIRS
+    "05_executors/photo_interrupter"
+)
diff --git a/main/05_executors/photo_interrupter/photo_interrupter.cc b/main/05_executors/photo_interrupter/photo_interrupter.cc
new file mode 100644
index 0000000..2a0eff3
--- /dev/null
+++ b/main/05_executors/photo_interrupter/photo_interrupter.cc
@@ -0,0 +1,129 @@
+/**
+ * @file photo_interrupter.cc
+ * @brief 光电限位开关类实现文件
+ * 
+ * 该类实现了光电限位开关的完整功能,包括初始化、中断处理、
+ * 回调函数管理等。支持起始位置和结束位置两个限位开关的检测。
+ */
+
+#include "photo_interrupter.h"
+#include 
+
+#define TAG "PhotoInterrupter"  ///< 日志标签,用于ESP-IDF日志系统
+
+/**
+ * @brief 构造函数
+ * 
+ * 初始化PhotoInterrupter对象,设置默认状态
+ * 目前构造函数为空,所有初始化操作在Init()方法中完成
+ */
+PhotoInterrupter::PhotoInterrupter()
+{
+    
+}
+
+/**
+ * @brief 析构函数
+ * 
+ * 清理资源,释放分配的内存
+ * 目前析构函数为空,没有需要特殊清理的资源
+ */
+PhotoInterrupter::~PhotoInterrupter()
+{
+
+}
+
+/**
+ * @brief 初始化限位开关
+ * 
+ * 执行限位开关的初始化操作,包括:
+ * 1. 输出初始化日志
+ * 2. 设置默认的起始限位开关回调函数
+ * 3. 设置默认的结束限位开关回调函数
+ * 
+ * 默认回调函数仅输出触发日志,用户可以通过OnStartTrigger()和OnEndTrigger()
+ * 方法覆盖这些默认回调函数
+ */
+void PhotoInterrupter::Init()
+{
+    ESP_LOGI(TAG, "限位开关初始化");
+    
+    // 设置默认回调函数 - 起始限位开关触发时输出日志
+    OnStartTrigger([]() {
+        ESP_LOGI(TAG, "起始限位开关触发 - 默认回调");
+    });
+    
+    // 设置默认回调函数 - 结束限位开关触发时输出日志
+    OnEndTrigger([]() {
+        ESP_LOGI(TAG, "结束限位开关触发 - 默认回调");
+    });
+}
+
+/**
+ * @brief 处理限位开关中断
+ * 
+ * 当限位开关被触发时调用的中断处理函数
+ * 目前仅输出中断触发日志,可以根据需要扩展更多处理逻辑
+ */
+void PhotoInterrupter::Interrupt()
+{
+    ESP_LOGI(TAG, "限位开关中断触发");
+}
+
+/**
+ * @brief 设置起始限位开关触发回调函数
+ * @param callback 回调函数对象,当起始限位开关被触发时执行
+ * 
+ * 允许用户自定义起始限位开关被触发时的处理逻辑。
+ * 该函数会保存传入的回调函数,并输出注册日志。
+ */
+void PhotoInterrupter::OnStartTrigger(std::function callback)
+{
+    on_start_trigger_ = callback;
+    ESP_LOGI(TAG, "注册起始限位开关回调函数");
+}
+
+/**
+ * @brief 设置结束限位开关触发回调函数
+ * @param callback 回调函数对象,当结束限位开关被触发时执行
+ * 
+ * 允许用户自定义结束限位开关被触发时的处理逻辑。
+ * 该函数会保存传入的回调函数,并输出注册日志。
+ */
+void PhotoInterrupter::OnEndTrigger(std::function callback)
+{
+    on_end_trigger_ = callback;
+    ESP_LOGI(TAG, "注册结束限位开关回调函数");
+}
+
+/**
+ * @brief 触发起始限位开关回调
+ * 
+ * 当检测到起始限位开关被触发时,执行注册的回调函数。
+ * 如果回调函数已设置(不为nullptr),则执行回调并输出触发日志。
+ * 
+ * 该函数通常由IO扩展板在检测到起始限位开关中断时调用。
+ */
+void PhotoInterrupter::TriggerStartCallback()
+{
+    if (on_start_trigger_) {
+        ESP_LOGI(TAG, "触发起始限位开关回调");
+        on_start_trigger_();
+    }
+}
+
+/**
+ * @brief 触发结束限位开关回调
+ * 
+ * 当检测到结束限位开关被触发时,执行注册的回调函数。
+ * 如果回调函数已设置(不为nullptr),则执行回调并输出触发日志。
+ * 
+ * 该函数通常由IO扩展板在检测到结束限位开关中断时调用。
+ */
+void PhotoInterrupter::TriggerEndCallback()
+{
+    if (on_end_trigger_) {
+        ESP_LOGI(TAG, "触发结束限位开关回调");
+        on_end_trigger_();
+    }
+}
\ No newline at end of file
diff --git a/main/05_executors/photo_interrupter/photo_interrupter.h b/main/05_executors/photo_interrupter/photo_interrupter.h
new file mode 100644
index 0000000..032f5ac
--- /dev/null
+++ b/main/05_executors/photo_interrupter/photo_interrupter.h
@@ -0,0 +1,87 @@
+/**
+ * @file photo_interrupter.h
+ * @brief 光电限位开关类头文件
+ * 
+ * 该类用于处理光电限位开关的触发事件,支持起始位置和结束位置的检测。
+ * 通过回调函数机制,当限位开关被触发时执行相应的处理逻辑。
+ */
+
+#ifndef PHOTO_INTERRUPTER_H
+#define PHOTO_INTERRUPTER_H
+
+#include "io_expansion_board.h"
+#include 
+
+/**
+ * @class PhotoInterrupter
+ * @brief 光电限位开关类
+ * 
+ * 提供限位开关的初始化、中断处理和回调函数管理功能。
+ * 支持起始位置和结束位置两个限位开关的检测。
+ */
+class PhotoInterrupter {
+public:
+    /**
+     * @brief 构造函数
+     * 
+     * 初始化PhotoInterrupter对象,设置默认状态
+     */
+    PhotoInterrupter();
+    
+    /**
+     * @brief 析构函数
+     * 
+     * 清理资源,释放分配的内存
+     */
+    ~PhotoInterrupter();
+    
+    /**
+     * @brief 初始化限位开关
+     * 
+     * 执行限位开关的初始化操作,包括设置默认回调函数
+     */
+    void Init();
+    
+    /**
+     * @brief 处理限位开关中断
+     * 
+     * 当限位开关被触发时调用的中断处理函数
+     */
+    void Interrupt();
+    
+    /**
+     * @brief 设置起始限位开关触发回调函数
+     * @param callback 回调函数对象,当起始限位开关被触发时执行
+     * 
+     * 允许用户自定义起始限位开关被触发时的处理逻辑
+     */
+    void OnStartTrigger(std::function callback);
+    
+    /**
+     * @brief 设置结束限位开关触发回调函数
+     * @param callback 回调函数对象,当结束限位开关被触发时执行
+     * 
+     * 允许用户自定义结束限位开关被触发时的处理逻辑
+     */
+    void OnEndTrigger(std::function callback);
+    
+    /**
+     * @brief 触发起始限位开关回调
+     * 
+     * 当检测到起始限位开关被触发时,执行注册的回调函数
+     */
+    void TriggerStartCallback();
+    
+    /**
+     * @brief 触发结束限位开关回调
+     * 
+     * 当检测到结束限位开关被触发时,执行注册的回调函数
+     */
+    void TriggerEndCallback();
+
+private:
+    std::function on_start_trigger_;  ///< 起始限位开关回调函数
+    std::function on_end_trigger_;      ///< 结束限位开关回调函数
+};
+
+#endif // PHOTO_INTERRUPTER_H
\ No newline at end of file
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
new file mode 100644
index 0000000..2b92ae0
--- /dev/null
+++ b/main/CMakeLists.txt
@@ -0,0 +1,150 @@
+# 获取当前选择的 demo 配置
+if(CONFIG_SWEEKAR_DEMO_1)
+    set(ACTIVE_DEMO "sweekar_demo1")
+elseif(CONFIG_SWEEKAR_DEMO_2)
+    set(ACTIVE_DEMO "sweekar_demo2")
+elseif(CONFIG_SWEEKAR_DEMO_3)
+    set(ACTIVE_DEMO "sweekar_demo3")
+elseif(CONFIG_SWEEKAR_DEMO_4)
+    set(ACTIVE_DEMO "sweekar_demo4")
+elseif(CONFIG_SWEEKAR_DEMO_5)
+    set(ACTIVE_DEMO "sweekar_demo5")
+elseif(CONFIG_SWEEKAR_DEMO_6)
+    set(ACTIVE_DEMO "sweekar_demo6")
+elseif(CONFIG_SWEEKAR_DEMO_7)
+    set(ACTIVE_DEMO "sweekar_demo7")
+endif()
+
+# 初始化全局变量,用于收集各模块的信息
+set(MODULE_SRCS)
+set(MODULE_INCLUDE_DIRS)
+set(MODULE_REQUIRES)
+set(MODULE_PRIV_REQUIRES)
+set(MODULE_EMBED_TXTFILES)
+
+if(NOT DEFINED CONFIG_SWEEKAR_DEMO_SELECTION)
+    set(EARLY_EXPANSION TRUE)
+    message(STATUS "Early expansion pass: loading all module requirements")
+else()
+    set(EARLY_EXPANSION FALSE)
+endif()
+
+# ===================================================================
+# 执行 Kconfig 自动组装脚本 (在配置阶段自动生成 Kconfig.modules)
+# ===================================================================
+execute_process(
+    COMMAND python3 ${CMAKE_CURRENT_LIST_DIR}/generate_kconfig_modules.py
+    WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+    RESULT_VARIABLE generate_kconfig_result
+)
+if(NOT generate_kconfig_result EQUAL 0)
+    message(FATAL_ERROR "Failed to generate Kconfig.modules")
+endif()
+
+# ==================== 模块注册区 ====================
+# 定义需要扫描的架构层级目录
+set(SUBSYSTEM_DIRS 
+    "04_hal"
+    "05_executors"
+    "05_service"
+    "06_behaviors"
+    "tests"
+)
+
+# 扫描并加载所有启用的子模块(依赖各个模块中的 module.cmake)
+foreach(dir ${SUBSYSTEM_DIRS})
+    file(GLOB MODULE_FILES "${CMAKE_CURRENT_LIST_DIR}/${dir}/*/module.cmake")
+    foreach(mod_file ${MODULE_FILES})
+        include(${mod_file})
+    endforeach()
+endforeach()
+
+# sweekar_demos 模块 (单独加载)
+# include(${CMAKE_CURRENT_LIST_DIR}/sweekar_demos/module.cmake)
+
+# ===================================================================
+
+if(MODULE_REQUIRES)
+    list(REMOVE_DUPLICATES MODULE_REQUIRES)
+endif()
+if(MODULE_PRIV_REQUIRES)
+    list(REMOVE_DUPLICATES MODULE_PRIV_REQUIRES)
+endif()
+
+message(STATUS "==== DEBUG ====")
+message(STATUS "MODULE_REQUIRES: ${MODULE_REQUIRES}")
+message(STATUS "MODULE_SRCS: ${MODULE_SRCS}")
+message(STATUS "===============")
+
+idf_component_register(
+    SRCS 
+        "main.cc" 
+        # "tests/test.cc"
+        # "tests/korvo_port/korvo_port_runner.cc"
+        # "tests/korvo_port/ai_agent.c"
+        # "tests/korvo_port/audio_proc.c"
+        # "tests/korvo_port/rtc_proc.c"
+        # "../managed_components/espressif__zlib/zlib/contrib/minizip/unzip.c"
+        # "../managed_components/espressif__zlib/zlib/contrib/minizip/ioapi.c"
+        ${MODULE_SRCS}
+    INCLUDE_DIRS 
+        "." 
+        # "../managed_components/espressif__zlib/zlib/contrib/minizip"
+        # "05_executors/touch_sensor"
+        # "05_executors/aw_touch_sensor"
+        ${MODULE_INCLUDE_DIRS}
+
+    REQUIRES
+        # lvgl
+        # esp_timer  
+        # driver
+        # esp_driver_i2c
+        # esp_driver_i2s
+        # esp_event
+        # nvs_flash
+        # spi_flash
+        # esp_driver_gpio
+        # spiffs
+        # vfs
+        # esp_http_server
+        # log
+        # fatfs
+        # bt
+        # mbedtls
+        # audio_pipeline
+        # audio_hal
+        # audio_board
+        # esp_peripherals
+        # audio_stream
+        # audio_sal
+        # esp-adf-libs
+        # espressif__zlib
+        ${MODULE_REQUIRES}
+    PRIV_REQUIRES
+        # esp-qcloud
+        ${MODULE_PRIV_REQUIRES}
+    EMBED_TXTFILES
+        ${MODULE_EMBED_TXTFILES}
+)
+# 添加 C++ 标准库支持
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+# 自动创建SPIFFS分区镜像
+# 这会在构建时自动生成audio.bin并在烧录时一并烧录
+# spiffs_create_partition_image(audio ../spiffs FLASH_IN_PROJECT)
+
+# 添加编译选项来忽略字符串常量转换警告
+target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-write-strings)
+target_compile_options(${COMPONENT_LIB} PRIVATE -DUSE_FILE32API)
+
+
+set(LANG_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/assets/lang_config.h")
+
+# 根据 boards 目录内部模块自动匹配当前选择的板卡
+include(${CMAKE_CURRENT_LIST_DIR}/02_physical/boards/module.cmake)
+
+if (CONFIG_VOLC_RTC_MODE)
+    set(COMPONENT_SRCS ${COMPONENT_SRCS} RtcBotUtils.c)
+endif()
+target_compile_definitions(${COMPONENT_LIB} PRIVATE IOAPI_NO_64)
diff --git a/main/Kconfig.modules b/main/Kconfig.modules
new file mode 100644
index 0000000..b1822dd
--- /dev/null
+++ b/main/Kconfig.modules
@@ -0,0 +1,52 @@
+menu "Sweekar Subsystems Configuration"
+
+    menu "04 Hal Modules"
+        config ENABLE_HAL_AUDIO_CODEC
+            bool "Enable Audio Codec"
+            default y
+            help
+                Enable the audio_codec module in 04_hal.
+        config ENABLE_HAL_BASE_BOARD_HAL
+            bool "Enable Base Board Hal"
+            default y
+            help
+                Enable the base_board_hal module in 04_hal.
+        config ENABLE_HAL_STEPPER_DRIVER
+            bool "Enable Stepper Driver"
+            default y
+            help
+                Enable the stepper_driver module in 04_hal.
+    endmenu
+
+    menu "05 Executors Modules"
+        config ENABLE_EXEC_ADC_BATTERY_MONITOR
+            bool "Enable Adc Battery Monitor"
+            default y
+            help
+                Enable the adc_battery_monitor module in 05_executors.
+        config ENABLE_EXEC_BASE_BOARD_CONTROL
+            bool "Enable Base Board Control"
+            default y
+            help
+                Enable the base_board_control module in 05_executors.
+        config ENABLE_EXEC_GYROSCOPE
+            bool "Enable Gyroscope"
+            default y
+            help
+                Enable the gyroscope module in 05_executors.
+        config ENABLE_EXEC_MILLIMETER_WAVE_RADAR
+            bool "Enable Millimeter Wave Radar"
+            default y
+            help
+                Enable the millimeter_wave_radar module in 05_executors.
+        config ENABLE_EXEC_PHOTO_INTERRUPTER
+            bool "Enable Photo Interrupter"
+            default y
+            help
+                Enable the photo_interrupter module in 05_executors.
+    endmenu
+
+    menu "tests  Modules"
+    endmenu
+
+endmenu
diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild
new file mode 100644
index 0000000..e21b00a
--- /dev/null
+++ b/main/Kconfig.projbuild
@@ -0,0 +1,544 @@
+menu "Sweekar Application Configuration"
+
+    # ==============================================================
+    # 模块化配置自动扫描引入点
+    # 这里会自动加载 main/Kconfig.modules 文件
+    # ==============================================================
+    rsource "Kconfig.modules"
+
+    choice BOARD_VERSION_SELECTION
+        prompt "Select Board Version"
+        default BOARD_VERSION_V1_1_11
+        help
+            Select the hardware board version to use.
+    
+    config BOARD_VERSION_V1_1_11
+        bool "Board v1.1.11"
+        help
+            Use board version v1.1.11
+    
+    config BOARD_VERSION_V1_1_12
+        bool "Board v1.1.12"
+        help
+            Use board version v1.1.12
+    
+    config BOARD_VERSION_V1_1_13
+        bool "Board v1.1.13"
+        help
+            Use board version v1.1.13
+    
+    config BOARD_VERSION_V1_1_14
+        bool "Board v1.1.14"
+        help
+            Use board version v1.1.14
+
+    config BOARD_VERSION_V1_1_16
+        bool "Board v1.1.16"
+        help
+            Use board version v1.1.16
+
+    config BOARD_VERSION_V1_1_17
+        bool "Board v1.1.17"
+        help
+            Use board version v1.1.17
+
+    config BOARD_VERSION_V1_1_18
+        bool "Board v1.1.18"
+        help
+            Use board version v1.1.18
+    
+    endchoice
+    
+    choice STEPPER_DRIVER_IMPL
+        prompt "Stepper Driver Implementation"
+        default STEPPER_DRIVER_DRV8428
+        help
+            Select the stepper motor driver chip.
+
+    config STEPPER_DRIVER_DRV8428
+        bool "TI DRV8428"
+        help
+            Use TI DRV8428 stepper motor driver.
+
+    config STEPPER_DRIVER_AW8646
+        bool "Awinic AW8646"
+        help
+            Use Awinic AW8646 stepper motor driver.
+
+    endchoice
+
+    choice LINEAR_MOTOR_TYPE
+        prompt "Linear Motor Type"
+        default LINEAR_MOTOR_LD0832
+        help
+            Select the linear motor type.
+
+    config LINEAR_MOTOR_LD0832
+        bool "LD0832 (1.8V, 235Hz, 21 ohm)"
+        help
+            Use LD0832 linear motor.
+
+    config LINEAR_MOTOR_LD0625
+        bool "LD0625 (0.7V, 260Hz, 8 ohm)"
+        help
+            Use LD0625 linear motor.
+
+    endchoice
+
+    choice AUDIO_DECODER_SUPPORT
+        prompt "Audio Decoder"
+        default AUDIO_SUPPORT_OPUS_DECODER
+    
+    config AUDIO_SUPPORT_G711A_DECODER
+        bool "AUDIUO-G711-DECODER"
+    
+    config AUDIO_SUPPORT_OPUS_DECODER
+        bool "AUDIO-OPUS-DECODER"
+    
+    config AUDIO_SUPPORT_AAC_DECODER
+        bool "AUDIO-AAC-DECODER"
+    
+    endchoice
+    
+    choice AUDIO_CONVERSATION_MODE_SUPPORT
+        prompt "Conversion Mode"
+        default CONTINUOUS_CONVERSATION_MODE
+    
+    config LANGUAGE_WAKEUP_MODE
+        select USE_WAKENET
+        select SR_WN_WN9_HILEXIN
+        bool "LANGUAGE-WAKEUP-MODE"
+    
+    config CONTINUOUS_CONVERSATION_MODE
+        bool "CONTINUOUS-CONVERSATION-MODE"
+    
+    endchoice
+    
+    choice RTC_MODE_CHOICE
+        prompt "rtc mode choice"
+        default COZE_REQUEST
+        help
+            Select rtc request mode
+    
+        config COZE_REQUEST
+            bool "enable coze request"
+    
+        config RTC_TOKEN_REQUEST
+            bool "enable rtc token request"
+    endchoice
+
+    choice RTC_BACKEND_PROVIDER
+        prompt "RTC backend provider"
+        default RTC_BACKEND_VOLC
+        help
+            Select the RTC SDK backend used by the AI RTC service.
+
+        config RTC_BACKEND_VOLC
+            bool "VolcEngine RTC (current default)"
+
+        config RTC_BACKEND_AGORA
+            bool "Agora RTC (migration target)"
+    endchoice
+
+    menu "Agora RTC Configuration"
+        depends on RTC_BACKEND_AGORA
+
+        config AGORA_SDK_ENABLED
+            bool "Agora SDK integrated"
+            default n
+            help
+                Enable this option after adding Agora RTC SDK headers/libs.
+
+        config AGORA_APP_ID
+            string "Agora App ID"
+            default ""
+
+        config AGORA_TOKEN
+            string "Agora RTC Token"
+            default ""
+
+        config AGORA_CHANNEL
+            string "Agora Channel Name"
+            default "default"
+
+        config AGORA_UID
+            int "Agora Local UID"
+            default 0
+    endmenu
+
+    choice TOUCH_SENSOR_IMPL
+        prompt "Touch Sensor Implementation"
+        default TOUCH_SENSOR_IMPL_ESP
+
+    config TOUCH_SENSOR_IMPL_ESP
+        bool "ESP32 Touch Pad"
+        help
+            Use ESP32 internal touch sensor (via touch_pad).
+
+    config TOUCH_SENSOR_IMPL_AW
+        bool "Awinic Touch Sensor"
+        help
+            Use Awinic AW933xx touch sensor.
+    
+    endchoice
+
+    choice BASE_BOARD_COMM_INTERFACE
+        prompt "Base Board Communication Interface"
+        default BASE_BOARD_COMM_UART
+        help
+            Select the communication interface for the base board.
+
+        config BASE_BOARD_COMM_UART
+            bool "UART (Legacy)"
+            help
+                Use UART for base board communication.
+
+        config BASE_BOARD_COMM_I2C
+            bool "I2C (v1.1.16+)"
+            help
+                Use I2C for base board communication.
+    endchoice
+    
+    
+    config COZE_URL
+        string "COZE-URL"
+        default "http://115.190.92.216:8899/startvoicechat"
+        depends on COZE_REQUEST
+    
+        config COZE_AUTHORIZATION
+            string "COZE-AUTHORIZATION"
+            default "af78e3067582ac8c04ba20174410bd1"
+            depends on COZE_REQUEST
+        
+        config COZE_BOTID
+            string "COZE-BOTID"
+            default "ep-20241104163951-sdmjc"
+            depends on COZE_REQUEST
+    
+    
+    config RTC_TOKEN
+        depends on RTC_TOKEN_REQUEST
+        config APPID
+            string "appid"
+            depends on RTC_TOKEN_REQUEST
+        
+        config ROOMID
+            string "roomid"
+            depends on RTC_TOKEN_REQUEST
+        
+        config UID
+            string "userid"
+            depends on RTC_TOKEN_REQUEST
+    
+        config TOKEN
+            string "token"
+            depends on RTC_TOKEN_REQUEST
+    
+    config ENABLE_RECORDER_DEBUG
+        bool "enable recorder debug save to sdcard"
+        default "n"
+        help
+            Save the data processed by AEC to the SD card. The saved file name is "rec.pcm", and by default, 30 seconds' worth of data will be saved.
+    
+    config ENABLE_OTA_UPDATE
+        bool "Enable OTA Update"
+        default y
+        help
+            Enable or disable OTA
+    
+    choice OTA_UPDATE_STRATEGY
+        prompt "OTA Update Strategy"
+        default OTA_MODE_NOTIFY
+        depends on ENABLE_OTA_UPDATE
+        help
+            Select the OTA update strategy
+    
+        config OTA_MODE_AUTO
+            bool "Auto Update (Immediate)"
+            help
+                Automatically download and install updates immediately
+    
+        config OTA_MODE_NOTIFY
+            bool "Notify Update (Wait for Confirmation)"
+            help
+                Wait for user confirmation before starting the OTA update process.
+    endchoice
+    
+    endmenu
+
+menu "QCloud COS Download Configuration"
+
+    config QCLOUD_COS_QUEUE_SIZE
+        int "COS download queue size"
+        default 20
+        range 1 100
+        help
+            Number of pending COS download messages that can be buffered.
+
+    config QCLOUD_COS_WORKER_COUNT
+        int "COS worker thread count"
+        default 1
+        range 1 4
+        help
+            Number of worker threads for COS download processing.
+
+    config QCLOUD_COS_WORKER_STACK_SIZE
+        int "COS worker stack size (bytes)"
+        default 16384
+        range 4096 65536
+        help
+            Stack size in bytes for each COS worker thread.
+
+    config QCLOUD_COS_HTTP_BUFFER_SIZE
+        int "COS HTTP download buffer size (bytes)"
+        default 32768
+        range 4096 131072
+        help
+            Buffer size used by HTTP read and esp_http_client internal buffer.
+
+    config QCLOUD_COS_ZIP_UNZIP_BUFFER_SIZE
+        int "COS ZIP unzip read buffer size (bytes)"
+        default 32768
+        range 4096 131072
+        help
+            Buffer size used when reading compressed data from ZIP entries.
+
+    config QCLOUD_COS_SD_WRITE_BUFFER_SIZE
+        int "COS SD write buffer size (bytes)"
+        default 32768
+        range 4096 131072
+        help
+            stdio write buffer size for HTTP download and ZIP extraction output.
+
+endmenu
+    
+    
+    menu "WiFi Configuration"
+        config ENABLE_HARDCODED_WIFI
+            bool "Enable Hardcoded WiFi Credentials"
+            default n
+            help
+                If enabled, the device will first attempt to connect to the specified WiFi network.
+                If disabled or connection fails, it will fall back to SmartConfig/QCloud provisioning.
+
+        config HARDCODED_WIFI_SSID
+            string "WiFi SSID"
+            depends on ENABLE_HARDCODED_WIFI
+            default ""
+            help
+                The SSID of the WiFi network to connect to.
+                Leave empty to fallback to SmartConfig/QCloud provisioning.
+
+        config HARDCODED_WIFI_PASSWORD
+            string "WiFi Password"
+            depends on ENABLE_HARDCODED_WIFI
+            default ""
+            help
+                The password of the WiFi network to connect to.
+    endmenu
+
+    # Sweekar Demo Selection
+    menu "Sweekar Demo Selection"
+    
+        choice SWEEKAR_DEMO_SELECTION
+            prompt "Select Active Demo"
+            default SWEEKAR_DEMO_3
+            help
+                Select which demo to build and run. Only one demo can be active at a time.
+    
+            config SWEEKAR_DEMO_2
+                bool "Demo 2"
+                
+            config SWEEKAR_DEMO_3
+                bool "Demo 3 - Basic Pet Game"
+                
+            config SWEEKAR_DEMO_5
+                bool "Demo 5"
+                
+            config SWEEKAR_DEMO_6  
+                bool "Demo 6 - Layered Architecture"
+                
+            config SWEEKAR_DEMO_7
+                bool "Demo 7 - Microkernel Architecture"
+                
+        endchoice
+    
+        config ACTIVE_DEMO_NAME
+            string
+            default "sweekar_demo2" if SWEEKAR_DEMO_2
+            default "sweekar_demo3" if SWEEKAR_DEMO_3
+            default "sweekar_demo5" if SWEEKAR_DEMO_5
+            default "sweekar_demo6" if SWEEKAR_DEMO_6
+            default "sweekar_demo7" if SWEEKAR_DEMO_7
+            
+        config SWEEKAR_DEMO6_HATCHING5_TVC
+            bool "Use TVC version for Hatching 5"
+            depends on SWEEKAR_DEMO_6
+            default n
+            help
+                If enabled, plays EGG_EMORAISING_HATCHING5_TVC instead of EGG_EMORAISING_HATCHING5_NORMAL during the final hatching stage.
+    
+    endmenu
+    
+    menu "ESP QCloud Example Configuration"
+        menu "Light development board selection "
+            choice LIGHTBULB_DEMO_DRIVER_SELECT
+                    bool "Demo select"
+                    default LIGHTBULB_DEMO_DRIVER_SELECT_WS2812 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32H2
+                    default LIGHTBULB_DEMO_DRIVER_SELECT_PWM
+                    help
+                        Select the driver type you want to demonstrate
+    
+                    config LIGHTBULB_DEMO_DRIVER_SELECT_SM2135E
+                        bool "Demo SM2135E"
+                    config LIGHTBULB_DEMO_DRIVER_SELECT_WS2812
+                        bool "Demo WS2812"
+                    config LIGHTBULB_DEMO_DRIVER_SELECT_PWM
+                        bool "Demo PWM"
+            endchoice
+    
+            config WS2812_LED_GPIO
+                int "WS2812 LED GPIO"
+                default 8 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32H2
+                default 18 if IDF_TARGET_ESP32S2
+                default 48 if IDF_TARGET_ESP32S3
+                default 4 if IDF_TARGET_ESP32C2
+                default 18
+                depends on LIGHTBULB_DEMO_DRIVER_SELECT_WS2812
+                help
+                    Set the WS2812 RGB LED GPIO.
+    
+            config WS2812_LED_NUM
+                int "WS2812 LED NUM"
+                default 1
+                depends on LIGHTBULB_DEMO_DRIVER_SELECT_WS2812
+                help
+                    Set the WS2812 LED NUM.
+    
+            config PWM_FREQ_HZ
+                int "PWM Frequency (hz)"
+                default 4000
+                range 2000 5000
+                depends on LIGHTBULB_DEMO_DRIVER_SELECT_PWM
+                help
+                    Set the PWM Frequency (hz).
+    
+            config PWM_RED_GPIO
+                int "PWM Red GPIO"
+                default 10 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S2
+                default 15 if IDF_TARGET_ESP32S3
+                default 0 if IDF_TARGET_ESP32C2
+                default 23 if IDF_TARGET_ESP32H2
+                default 25
+                depends on LIGHTBULB_DEMO_DRIVER_SELECT_PWM
+                help
+                    Set the PWM Red LED GPIO.
+    
+            config PWM_GREEN_GPIO
+                int "PWM Green GPIO"
+                default 6 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S2
+                default 16 if IDF_TARGET_ESP32S3
+                default 1 if IDF_TARGET_ESP32C2
+                default 24 if IDF_TARGET_ESP32H2
+                default 26
+                depends on LIGHTBULB_DEMO_DRIVER_SELECT_PWM
+                help
+                    Set the PWM Green LED GPIO.
+    
+            config PWM_BLUE_GPIO
+                int "PWM Blue GPIO"
+                default 7 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S2
+                default 17 if IDF_TARGET_ESP32S3
+                default 8 if IDF_TARGET_ESP32C2
+                default 25 if IDF_TARGET_ESP32H2
+                default 27
+                depends on LIGHTBULB_DEMO_DRIVER_SELECT_PWM
+                help
+                    Set the PWM Blue LED GPIO.
+    
+            config SM2135E_IIC_CLK_GPIO
+                int "SM2135E IIC CLK GPIO"
+                default 4
+                depends on LIGHTBULB_DEMO_DRIVER_SELECT_SM2135E
+                help
+                    Set the SM2135E CLK GPIO.
+    
+            config SM2135E_IIC_SDA_GPIO
+                int "SM2135E IIC SDA GPIO"
+                default 5
+                depends on LIGHTBULB_DEMO_DRIVER_SELECT_SM2135E
+                help
+                    Set the SM2135E SDA GPIO.
+    
+    
+    
+    
+    
+    
+    
+        endmenu
+    menu "Light provisioning network selection"
+            config LIGHT_PROVISIONING_SMARTCONFIG
+                bool "Enable SmartConfig's smart network configuration method"
+                default n
+                help
+                    Enable SmartConfig's smart network configuration method
+            
+            config LIGHT_PROVISIONING_SOFTAPCONFIG
+                bool "Enable SoftAP's network configuration method"
+                default y
+                help
+                    "Enable SoftAP's network configuration method"
+    
+            config LIGHT_PROVISIONING_BLECONFIG
+                depends on QCLOUD_ENABLE_BLECONFIG
+                bool "Enable BLE's network configuration method"
+                default y
+                help
+                    "Enable BLE's network configuration method"
+    
+            config LIGHT_PROVISIONING_SOFTAPCONFIG_SSID
+                depends on LIGHT_PROVISIONING_SOFTAPCONFIG
+                string "SoftAP ssid"
+                default "tcloud_XXX"
+                help
+                    SSID (network name) for the phone to connect to.
+    
+            config LIGHT_PROVISIONING_BLECONFIG_NAME
+                depends on LIGHT_PROVISIONING_BLECONFIG
+                string "BLE name"
+                default "Qcloud"
+                help
+                    BLE for the phone to connect to.
+        endmenu
+    
+        config LIGHT_REBOOT_UNBROKEN_COUNT_RESET
+            int "More than this number of continuous uninterrupted restarts triggers a reset of the device"
+            range 3 15
+            default 5
+            help
+                Devices without buttons trigger a device reset through continuous restart.
+    
+        config LIGHT_DEBUG
+            bool "The device will be in debug mode"
+            default n
+            help
+                Debug mode device performance is only used during development.
+    
+                
+    
+        choice QCLOUD_WIFI_CONFIG_METHOD
+            prompt "WiFi Provisioning Method"
+            default QCLOUD_WIFI_SMARTCONFIG
+            help
+                Select how the device should connect to WiFi.
+    
+            config QCLOUD_WIFI_PROVISIONING
+                bool "WeChat Mini-Program (connectWiFi)"
+                
+            config QCLOUD_WIFI_SMARTCONFIG
+                bool "ESP-Touch / SmartConfig (connectWiFi_smartconfig)"
+        endchoice
+    
+    endmenu
+    
diff --git a/main/MODULE_DEVELOPMENT_GUIDE.md b/main/MODULE_DEVELOPMENT_GUIDE.md
new file mode 100644
index 0000000..3293538
--- /dev/null
+++ b/main/MODULE_DEVELOPMENT_GUIDE.md
@@ -0,0 +1,124 @@
+# Sweekar-ESP32 模块化开发与构建系统指南
+
+为了支持多人无冲突协作,并保持系统代码的高内聚、低耦合,Sweekar-ESP32 的 CMake 构建系统采用 **“透明化脚手架 (Transparent Scaffolding) + Kconfig 自动组装”** 架构。
+
+在这套架构下,开发者在添加新的底层硬件驱动、业务服务或测试代码时,**完全不需要修改任何顶层文件(包括 `main/CMakeLists.txt` 和 `main/Kconfig.projbuild`)**,构建系统会自动帮你生成必要的模板文件,而后续的修改则完全交由你掌控,没有任何“黑魔法”。
+
+以下是添加新模块的标准流程和机制说明。
+
+---
+
+## 1. 确定模块归属的目录分类
+系统顶层会自动扫描以下目录下的子文件夹:
+- `04_hal/` : 硬件抽象层代码(如 Codec 驱动、马达驱动等)
+- `05_executors/` : 执行器组件(如 AudioPlayer, Display, 传感器读取等)
+- `05_service/` : 后台服务组件(如 AI RTC、QCloud、WiFi 连接等)
+- `06_behaviors/` : 行为逻辑组件
+- `tests/` : 各种测试模块(如麦克风测试、扬声器测试等)
+- `sweekar_demos/` : 各种组装好的 Demo 入口
+
+*假设我们要添加一个专门测试麦克风的模块,名为 `test_mic`,它显然应该归属于 `tests/` 目录。*
+
+## 2. 新建模块与文件 (自动化部分)
+在对应的分类下新建文件夹,并将你的源码和头文件放进去:
+```bash
+mkdir -p main/tests/test_mic
+touch main/tests/test_mic/test_mic.cc
+touch main/tests/test_mic/test_mic.h
+```
+
+**【核心自动化机制】**
+此时,你**不需要**手动去写 CMake 文件。你只需要在终端执行一次:
+```bash
+idf.py reconfigure
+```
+(或者 `idf.py build` 如果这是你第一次编译该工程)。
+
+构建系统中的 Python 脚本 (`generate_kconfig_modules.py`) 会在配置阶段自动扫描目录。当它发现 `tests/test_mic` 目录下有源码但**没有** `module.cmake` 时,它会**自动为你生成一个 `module.cmake` 脚手架文件**。
+
+自动生成的文件内容类似于:
+```cmake
+# main/tests/test_mic/module.cmake
+# 自动生成的模块脚手架,可直接手工修改。
+# 如果后续添加了新文件,可以手工在此处添加,或者删除本文件让脚本重新生成。
+
+if(NOT CONFIG_ENABLE_TEST_TEST_MIC AND NOT EARLY_EXPANSION)
+    message(STATUS "  [Skip] test_mic module disabled by menuconfig.")
+    return()
+endif()
+
+list(APPEND MODULE_SRCS
+    "tests/test_mic/test_mic.cc"
+)
+
+list(APPEND MODULE_INCLUDE_DIRS
+    "tests/test_mic"
+)
+
+# 需要公开依赖时,在这里手工补充。例如:
+# list(APPEND MODULE_REQUIRES
+#     esp_timer
+#     driver
+# )
+```
+
+## 3. 后续维护与修改 (手工部分)
+
+**“透明化”原则**:一旦 `module.cmake` 被生成,Python 脚本就**再也不会覆盖或修改它**。它现在完全属于你。
+
+### 3.1 当你新增/删除源文件时
+你有两种选择:
+1. **手动修改(推荐)**:直接打开 `module.cmake`,在 `list(APPEND MODULE_SRCS ...)` 中手动添加或删除文件路径。所见即所得,非常直观。
+2. **重新生成(偷懒大法)**:如果你一口气加了十几个文件,不想手写路径,你可以**直接删除**这个 `module.cmake` 文件,然后运行 `idf.py reconfigure`,脚本会重新帮你扫描并生成一份包含所有最新文件的脚手架。
+
+### 3.2 当你需要依赖其他库时
+直接在 `module.cmake` 底部,取消注释并填入你需要的 ESP-IDF 组件名(如 `esp_adc`, `audio_pipeline` 等):
+```cmake
+list(APPEND MODULE_REQUIRES
+    audio_pipeline
+    driver
+)
+```
+
+## 4. 编写模块内部的 `Kconfig` (可选)
+系统会自动为你的模块生成一个默认的配置开关(例如 `CONFIG_ENABLE_TEST_TEST_MIC`)。
+- `tests/` 目录下的默认开关为关闭(`default n`)。
+- 其他目录默认开启(`default y`)。
+
+如果你需要为你的模块定义更复杂的配置选项(比如定义默认开启、依赖其他模块、或者包含子菜单),你可以在模块目录(`main/tests/test_mic/`)下建立一个名为 `Kconfig` 的文件:
+
+```kconfig
+# main/tests/test_mic/Kconfig
+config ENABLE_TEST_MIC
+    bool "Enable Microphone Test Module"
+    default n
+    help
+        Enable this to compile the microphone testing routines.
+```
+> 系统如果扫描到模块自带 `Kconfig`,就会使用你写的,而不再自动生成默认开关。
+
+## 5. 编译与配置
+1. 运行 `idf.py menuconfig`。
+2. 导航到 `Sweekar Subsystems Configuration` -> 对应的目录(如 `Tests Modules`)。
+3. 找到你刚刚添加的 `Enable test_mic`(或你自己定义的开关名字),按空格键勾选 `[*]`。
+4. 保存退出后,运行 `idf.py build` 即可!
+
+---
+
+## ⚠️ 常见问题与注意事项
+
+### Q: 为什么我新建了一个文件夹或者删除了 `module.cmake`,运行 `idf.py build` 没有反应?
+这是 CMake 的缓存机制导致的。如果你只是增删了目录或文件,但没有修改任何现有的 `CMakeLists.txt` 内容,CMake 会跳过配置阶段直接去编译,导致 Python 扫描脚本没有运行。
+**解决办法**:遇到这种情况,请明确告诉 IDF 重新配置:
+```bash
+idf.py reconfigure
+```
+然后再运行 `idf.py build`。
+
+### Q: 为什么要加 `NOT EARLY_EXPANSION`?
+ESP-IDF 的构建系统分为两步:
+1. **依赖解析阶段 (Early Expansion)**:此时 CMake 快速扫描所有组件收集 `REQUIRES`,但此时 `menuconfig` 的配置尚未加载,所有的 `CONFIG_xxx` 都是空值!
+2. **实际构建阶段 (Build Pass)**:此时配置加载完毕,开始真实编译。
+
+如果在 `module.cmake` 顶部仅仅写 `if(NOT CONFIG_ENABLE_XXX) return()`,会导致在依赖解析阶段该模块就被错误地跳过了,从而丢失其依赖声明,引发“找不到头文件”的编译灾难。
+加入 `AND NOT EARLY_EXPANSION` 后,能保证所有启用的组件依赖都被正确收集到构建树中,实现完美解耦。
diff --git a/main/generate_kconfig_modules.py b/main/generate_kconfig_modules.py
new file mode 100644
index 0000000..59cfa21
--- /dev/null
+++ b/main/generate_kconfig_modules.py
@@ -0,0 +1,247 @@
+import os
+import re
+
+# The directories to scan for Kconfig files
+SUBSYSTEM_DIRS = ["04_hal", "05_executors", "05_service", "06_behaviors", "tests"]
+TEMPLATE_SCAN_DIRS = SUBSYSTEM_DIRS + ["sweekar_demos"]
+BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+OUTPUT_FILE = os.path.join(BASE_DIR, "Kconfig.modules")
+
+SOURCE_EXTENSIONS = (".c", ".cc", ".cpp")
+HEADER_EXTENSIONS = (".h", ".hpp")
+SKIP_DIR_NAMES = {"build", "__pycache__"}
+
+
+def iter_child_dirs(parent_dir):
+    if not os.path.exists(parent_dir):
+        return []
+    return sorted(
+        [
+            name
+            for name in os.listdir(parent_dir)
+            if os.path.isdir(os.path.join(parent_dir, name)) and not name.startswith(".")
+        ]
+    )
+
+
+def compute_default_config_name(subsystem_dir, module_name):
+    if subsystem_dir == "tests":
+        prefix = "TEST"
+    else:
+        prefix = subsystem_dir.split("_")[1].upper()
+        if prefix == "EXECUTORS":
+            prefix = "EXEC"
+        elif prefix == "BEHAVIORS":
+            prefix = "BEHAV"
+        elif prefix == "SERVICE":
+            prefix = "SVC"
+    return f"CONFIG_ENABLE_{prefix}_{module_name.upper()}"
+
+
+def contains_module_files(module_dir):
+    for _, _, files in os.walk(module_dir):
+        for filename in files:
+            if filename.endswith(SOURCE_EXTENSIONS) or filename.endswith(HEADER_EXTENSIONS):
+                return True
+    return False
+
+
+def collect_existing_module_cmake_files():
+    module_files = []
+    for root, _, files in os.walk(BASE_DIR):
+        if "module.cmake" in files:
+            module_files.append(os.path.join(root, "module.cmake"))
+    return sorted(module_files)
+
+
+def collect_module_files(module_dir):
+    srcs = []
+    include_dirs = {"."}
+
+    for root, dirs, files in os.walk(module_dir):
+        dirs[:] = [
+            d for d in dirs
+            if d not in SKIP_DIR_NAMES and not d.startswith(".")
+        ]
+
+        rel_root = os.path.relpath(root, module_dir).replace(os.sep, "/")
+        rel_root = "." if rel_root == "." else rel_root
+
+        has_header = False
+        for filename in files:
+            if filename.endswith(SOURCE_EXTENSIONS):
+                rel_path = os.path.normpath(os.path.join(rel_root, filename)).replace(os.sep, "/")
+                if rel_path.startswith("./"):
+                    rel_path = rel_path[2:]
+                srcs.append(rel_path)
+            elif filename.endswith(HEADER_EXTENSIONS):
+                has_header = True
+
+        if has_header:
+            include_dirs.add(rel_root)
+
+    srcs = sorted(set(srcs))
+    include_dirs = sorted(set(include_dirs))
+    return srcs, include_dirs
+
+
+def is_already_aggregated(rel_module_dir, existing_module_files):
+    rel_module_prefix = f'"{rel_module_dir}/'
+    for module_file in existing_module_files:
+        try:
+            with open(module_file, "r", encoding="utf-8") as f:
+                content = f.read()
+        except OSError:
+            continue
+
+        if rel_module_prefix in content:
+            return True
+    return False
+
+
+def render_module_template(subsystem_dir, module_name, module_dir):
+    srcs, include_dirs = collect_module_files(module_dir)
+    rel_module_dir = os.path.relpath(module_dir, BASE_DIR).replace(os.sep, "/")
+    
+    lines = [
+        f"# main/{subsystem_dir}/{module_name}/module.cmake",
+        "# 自动生成的模块脚手架,可直接手工修改。",
+        "# 如果后续添加了新文件,可以手工在此处添加,或者删除本文件让脚本重新生成。",
+        "",
+    ]
+
+    if subsystem_dir != "sweekar_demos":
+        config_name = compute_default_config_name(subsystem_dir, module_name)
+        lines.extend(
+            [
+                f"if(NOT {config_name} AND NOT EARLY_EXPANSION)",
+                f'    message(STATUS "  [Skip] {module_name} module disabled by menuconfig.")',
+                "    return()",
+                "endif()",
+                "",
+            ]
+        )
+
+    lines.append("list(APPEND MODULE_SRCS")
+    for src in srcs:
+        lines.append(f'    "{rel_module_dir}/{src}"')
+    lines.append(")")
+    lines.append("")
+
+    lines.append("list(APPEND MODULE_INCLUDE_DIRS")
+    for inc in include_dirs:
+        if inc == ".":
+            lines.append(f'    "{rel_module_dir}"')
+        else:
+            lines.append(f'    "{rel_module_dir}/{inc}"')
+    lines.append(")")
+    lines.append("")
+
+    lines.extend(
+        [
+            "# 需要公开依赖时,在这里手工补充。例如:",
+            "# list(APPEND MODULE_REQUIRES",
+            "#     esp_timer",
+            "#     driver",
+            "# )",
+            "",
+            "# 需要私有依赖时,在这里手工补充。例如:",
+            "# list(APPEND MODULE_PRIV_REQUIRES",
+            "#     nvs_flash",
+            "# )",
+            "",
+        ]
+    )
+    return "\n".join(lines)
+
+
+def ensure_module_templates():
+    created_files = []
+    existing_module_files = collect_existing_module_cmake_files()
+
+    for subsystem_dir in TEMPLATE_SCAN_DIRS:
+        dir_path = os.path.join(BASE_DIR, subsystem_dir)
+        if not os.path.exists(dir_path):
+            continue
+
+        for module_name in iter_child_dirs(dir_path):
+            if subsystem_dir == "sweekar_demos" and not module_name.startswith("sweekar_demo"):
+                continue
+
+            module_dir = os.path.join(dir_path, module_name)
+            module_cmake = os.path.join(module_dir, "module.cmake")
+            if os.path.exists(module_cmake):
+                continue
+
+            if not contains_module_files(module_dir):
+                continue
+
+            rel_module_dir = os.path.relpath(module_dir, BASE_DIR).replace(os.sep, "/")
+            if subsystem_dir != "sweekar_demos" and is_already_aggregated(rel_module_dir, existing_module_files):
+                continue
+
+            template_content = render_module_template(subsystem_dir, module_name, module_dir)
+            with open(module_cmake, "w", encoding="utf-8") as f:
+                f.write(template_content)
+            created_files.append(module_cmake)
+
+    return created_files
+
+def generate_kconfig_modules():
+    created_templates = ensure_module_templates()
+    kconfig_content = 'menu "Sweekar Subsystems Configuration"\n\n'
+
+    for d in SUBSYSTEM_DIRS:
+        dir_path = os.path.join(BASE_DIR, d)
+        if not os.path.exists(dir_path):
+            continue
+
+        # Create a pretty menu name from the directory name
+        # e.g., "05_executors" -> "05 Executors Modules"
+        parts = d.split('_')
+        menu_name = parts[0] + " " + " ".join([p.capitalize() for p in parts[1:]]) + " Modules"
+        
+        kconfig_content += f'    menu "{menu_name}"\n'
+
+        # Sort subdirectories to ensure consistent ordering
+        subdirs = iter_child_dirs(dir_path)
+        
+        for module_name in subdirs:
+            module_dir = os.path.join(dir_path, module_name)
+            kconfig_file = os.path.join(module_dir, "Kconfig")
+            
+            if os.path.exists(kconfig_file):
+                # If the module has its own Kconfig, just source it
+                # Make sure the source path is relative to the project root or uses proper env vars
+                # Since Kconfig.projbuild is processed relative to project root usually
+                rel_path = os.path.join("main", d, module_name, "Kconfig")
+                kconfig_content += f'        source "{rel_path}"\n'
+            else:
+                # If no Kconfig exists, generate a default toggle for it
+                config_name = compute_default_config_name(d, module_name)
+                pretty_name = " ".join([word.capitalize() for word in module_name.split('_')])
+                
+                # Default to 'n' for tests, 'y' for everything else
+                default_val = 'n' if d == 'tests' else 'y'
+
+                kconfig_content += f'''        config {config_name.replace("CONFIG_", "")}
+            bool "Enable {pretty_name}"
+            default {default_val}
+            help
+                Enable the {module_name} module in {d}.
+'''
+        kconfig_content += '    endmenu\n\n'
+    
+    kconfig_content += 'endmenu\n'
+
+    with open(OUTPUT_FILE, 'w') as f:
+        f.write(kconfig_content)
+    
+    print(f"Generated {OUTPUT_FILE} successfully.")
+    if created_templates:
+        print("Generated module.cmake templates:")
+        for path in created_templates:
+            print(f"  - {path}")
+
+if __name__ == "__main__":
+    generate_kconfig_modules()
\ No newline at end of file
diff --git a/main/idf_component.yml b/main/idf_component.yml
new file mode 100644
index 0000000..8768341
--- /dev/null
+++ b/main/idf_component.yml
@@ -0,0 +1,19 @@
+## IDF Component Manager Manifest File
+dependencies:
+  ## Required IDF version
+  idf:
+    version: '>=5.0.0'
+
+  # lvgl/lvgl: ^8.*
+  # 添加button组件依赖
+  # espressif/button: ~4.1.3
+
+  # 78/esp-wifi-connect: ~2.4.3
+
+  espressif/adc_battery_estimation: ^0.2.0
+
+  # lightbulb_driver: ^0.0.9
+  # espressif/touch_slider_sensor: ^0.2.0
+
+  # espressif/touch_button_sensor: ^0.2.0
+  
diff --git a/main/main.cc b/main/main.cc
new file mode 100644
index 0000000..c9d988f
--- /dev/null
+++ b/main/main.cc
@@ -0,0 +1,5 @@
+
+
+extern "C" void app_main() {
+
+}
\ No newline at end of file