// // Created by kindring on 2025/12/26. // #include "esp_log.h" #include "app_io.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #define TAG "app_io" static QueueHandle_t g_io_evt_queue = NULL; static void io_task(void* arg) { uint32_t io_num; while (true) { if(xQueueReceive(g_io_evt_queue, &io_num, portMAX_DELAY)) { // 消抖处理 vTaskDelay(50 / portTICK_PERIOD_MS); if(gpio_get_level(io_num) == 0) { // 确认仍然是低电平 ESP_LOGI(TAG, "GPIO%"PRIu32" interrupt, button pressed", io_num); next_audio_mode(); } } } } static void IRAM_ATTR gpio_isr_handler(void* arg) { const uint32_t gpio_num = (uint32_t) arg; xQueueSendFromISR(g_io_evt_queue, &gpio_num, NULL); } /** * 切换系统状态灯 * @param on * @return */ esp_err_t set_led_io(const bool on) { const esp_err_t err = gpio_set_level(IO_LED, on); if (err != ESP_OK) { ESP_LOGE(TAG, "Set system to %d failed: %s", on, esp_err_to_name(err)); return err; } return ESP_OK; } esp_err_t init_led_io() { // system state led const gpio_config_t led_io_conf = { .pin_bit_mask = (1ULL << IO_LED), // GPIO15 .mode = GPIO_MODE_OUTPUT, // 输出模式 .pull_up_en = GPIO_PULLUP_DISABLE, // 禁用上拉 .pull_down_en = GPIO_PULLDOWN_DISABLE, // 禁用下拉 .intr_type = GPIO_INTR_DISABLE // 禁用中断 }; // 配置GPIO const esp_err_t err = gpio_config(&led_io_conf); if (err != ESP_OK) { ESP_LOGE(TAG, "system led config failed: %s", esp_err_to_name(err)); return err; } return set_led_io(0); } esp_err_t init_btn_io() { // 配置GPIO2为输入模式,用于低电平中断 const gpio_config_t btn_conf = { .pin_bit_mask = (1ULL << IO_BTN), .mode = GPIO_MODE_INPUT, .pull_up_en = GPIO_PULLUP_ENABLE, // 启用上拉,按钮按下时拉低 .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_NEGEDGE // 下降沿触发(按下按钮) }; const esp_err_t err = gpio_config(&btn_conf); if (err != ESP_OK) { ESP_LOGE(TAG, "BTN config failed: %s", esp_err_to_name(err)); return err; } // 注册中断服务 gpio_isr_handler_add(IO_BTN, gpio_isr_handler, (void*) IO_BTN); return ESP_OK; } // 更新输出引脚状态 esp_err_t update_output_mode(const audio_mode_t mode) { esp_err_t err = ESP_OK; // 根据音频模式设置GPIO19输出状态 switch(mode) { case AUDIO_MODE_NORMAL: err = gpio_set_level(IO_OUTPUT_SW, 0); // 低电平 break; case AUDIO_MODE_BASS_BOOST: err = gpio_set_level(IO_OUTPUT_SW, 1); // 高电平 break; default: err = gpio_set_level(IO_OUTPUT_SW, 0); break; } ESP_LOGD(TAG, "GPIO19 set to: %d", gpio_get_level(IO_OUTPUT_SW)); return err; } // 初始化输出引脚 esp_err_t init_output_io() { // 配置GPIO2为输入模式,用于低电平中断 const gpio_config_t output_conf = { .pin_bit_mask = (1ULL << IO_OUTPUT_SW), .mode = GPIO_MODE_OUTPUT, .pull_up_en = GPIO_PULLUP_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE }; const esp_err_t err = gpio_config(&output_conf); if (err != ESP_OK) { ESP_LOGE(TAG, "OUTPUT config failed: %s", esp_err_to_name(err)); return err; } return ESP_OK; } // 启用或者关闭功放 esp_err_t enable_amp(const bool on) { // 低有效, 高无效, 需要将电平反转 const int io_level = !on; const esp_err_t err = gpio_set_level(IO_AMP_EN, io_level ); if (err != ESP_OK) { ESP_LOGE(TAG, "%s apm failed: %s", on? "ENABLE" : "DISABLE", esp_err_to_name(err)); return err; } return ESP_OK; } esp_err_t init_amp_io() { // 配置GPIO32为输出模式并拉低电平 const gpio_config_t io_conf = { .pin_bit_mask = (1ULL << IO_AMP_EN), // GPIO32 .mode = GPIO_MODE_OUTPUT, // 输出模式 .pull_up_en = GPIO_PULLUP_DISABLE, // 禁用上拉 .pull_down_en = GPIO_PULLDOWN_DISABLE, // 禁用下拉 .intr_type = GPIO_INTR_DISABLE // 禁用中断 }; // 配置GPIO const esp_err_t err = gpio_config(&io_conf); if (err != ESP_OK) { ESP_LOGE(TAG, "IO_AMP_EN config failed: %s", esp_err_to_name(err)); return err; } return enable_amp(false); } // 初始化io引脚配置 int init_io() { // 安装GPIO ISR服务 esp_err_t err = gpio_install_isr_service(0); g_io_evt_queue = xQueueCreate(10, sizeof(uint32_t)); xTaskCreate(io_task, "io_task", 2048, NULL, 10, NULL); init_amp_io(); init_output_io(); init_led_io(); init_btn_io(); return 0; }