You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

启用INMP441麦克风i2s_set_pin后相机帧延迟过高问题

问题分析与解决方案

启用i2s_set_pin后相机帧率暴跌的核心原因是:I2S外设启动后与相机抢占了ESP32的中断、DMA或时钟资源——未启用引脚配置时,I2S驱动仅完成安装但未实际工作,不会占用系统资源;引脚配置完成后,I2S持续接收音频数据,与相机的帧捕获操作产生资源竞争。

以下是针对性的解决方案,按优先级排序:


1. 调整中断优先级,优先保障相机

将I2S的中断优先级调低,让相机的帧捕获中断优先被处理:

i2s_config_t i2s_config = {
  .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
  .sample_rate = SAMPLE_RATE,
  .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
  .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
  .communication_format = I2S_COMM_FORMAT_I2S,
  .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,  // 从LEVEL2改为LEVEL1,降低优先级
  .dma_buf_count = 2,
  .dma_buf_len = 128,
  .use_apll = false,
  .tx_desc_auto_clear = false,
  .fixed_mclk = 0
};

2. 优化I2S配置,减少资源占用

通过调整DMA参数和启用独立时钟,降低I2S对系统的干扰:

i2s_config_t i2s_config = {
  // 保留原有配置
  .dma_buf_count = 4,    // 增加缓冲数量,减少中断触发频率
  .dma_buf_len = 256,    // 增大缓冲长度,降低CPU调度次数
  .use_apll = true,      // 启用APLL独立时钟,避免与相机的XCLK时钟冲突
};

3. 启用相机双帧缓冲,提升捕获效率

将相机的帧缓冲数量改为2,让相机在处理当前帧的同时捕获下一帧,减少等待时间:

void setupCamera() {
    camera_config_t config;
    // ...其他配置不变
    config.fb_count = 2;  // 从1改为2
    // ...初始化相机
}

4. 用FreeRTOS分离任务,明确优先级

将相机捕获和音频读取放到独立的FreeRTOS任务中,给相机任务设置更高优先级:

void setup() {
    Serial.begin(115200);
    setupCamera();

    i2s_driver_install(I2S_NUM_1, &i2s_config, 0, NULL);
    i2s_set_pin(I2S_NUM_1, &i2s_mic_pins);

    // 相机任务绑定到核心0,优先级5(更高)
    xTaskCreatePinnedToCore(camera_task, "CameraTask", 4096, NULL, 5, NULL, 0);
    // 音频任务绑定到核心1,优先级3(更低)
    xTaskCreatePinnedToCore(audio_task, "AudioTask", 4096, NULL, 3, NULL, 1);
}

// 相机任务
void camera_task(void *param) {
    while(1) {
        camera_fb_t *fb = esp_camera_fb_get();
        if (!fb) {
            Serial.println("Camera capture failed");
            vTaskDelay(10 / portTICK_PERIOD_MS);
            continue;
        }

        Serial.println("Shot!!!");
        esp_camera_fb_return(fb);
        vTaskDelay(1 / portTICK_PERIOD_MS);
    }
}

// 音频读取任务
void audio_task(void *param) {
    int16_t audio_buf[256];
    size_t bytes_read;
    while(1) {
        i2s_read(I2S_NUM_1, audio_buf, sizeof(audio_buf), &bytes_read, portMAX_DELAY);
        // 在此处理音频数据(如写入缓冲区或传输)
    }
}

void loop() {
  // 空循环,任务由FreeRTOS调度
}

内容的提问来源于stack exchange,提问作者Ahmadreza Gholizade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 23:10:55