启用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
相关产品推荐
相关产品推荐

