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

ESP32-S3播放音频时无法同步LCD显示屏的问题求助

ESP32-S3(SC01 Plus)AudioI2S与LVGL/LovyanGFX兼容问题解决

问题根源

你的问题核心是DMA通道资源冲突:ESP32-S3的AudioI2S库默认占用DMA通道0,而LovyanGFX的并行8位总线默认也会使用通道0。调用audio.setPinout()后,音频抢占了显示屏的DMA资源,导致屏幕无法正常刷新,最终冻结变黑,但音频不受影响。

解决方案步骤

  1. 指定LovyanGFX并行总线的DMA通道,避开AudioI2S使用的通道
  2. 调整任务优先级与核心绑定,确保LVGL任务拥有更高优先级,避免被音频任务抢占CPU
  3. 优化显示屏刷新回调,确保DMA操作的稳定性
  4. 调整初始化顺序,先完成音频初始化,再启动显示屏和LVGL

修改后的关键代码部分

1. 调整LovyanGFX总线配置,指定DMA通道

在LGFX类的总线配置块中添加DMA通道设置:

{
  auto cfg = _bus_instance.config();

  cfg.port = 0;
  cfg.freq_write = 40000000;
  cfg.pin_wr = 47;
  cfg.pin_rd = -1;
  cfg.pin_rs = 0;
  cfg.pin_d0 = 9;
  cfg.pin_d1 = 46;
  cfg.pin_d2 = 3;
  cfg.pin_d3 = 8;
  cfg.pin_d4 = 18;
  cfg.pin_d5 = 17;
  cfg.pin_d6 = 16;
  cfg.pin_d7 = 15;
  // 指定DMA通道1,避开AudioI2S默认的通道0
  cfg.dma_channel = 1; 
  _bus_instance.config(cfg);
  _panel_instance.setBus(&_bus_instance);
}

2. 正确启用音频任务并设置优先级

取消setup()中playSound任务的注释,确保LVGL任务优先级高于音频任务:

// 在setup()中替换原注释的任务创建代码
xTaskCreatePinnedToCore(
    playSound,
    "playSound",
    10240,
    NULL,
    1,  // 音频任务优先级设为1,低于LVGL的2
    NULL,
    0); // 绑定到核心0

3. 优化显示屏刷新回调

修改my_disp_flush函数,确保DMA传输完成后再标记刷新完成:

void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
  // 等待上一次DMA传输完成
  while (tft.isDMA()) delay(1);
  
  tft.pushImageDMA(area->x1, area->y1, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1, (lgfx::swap565_t *)&color_p->full);
  
  // 等待当前DMA传输完成再通知LVGL
  while (tft.isDMA()) delay(1);
  lv_disp_flush_ready(disp);
}

4. 调整初始化顺序

将音频初始化步骤移到显示屏和LVGL初始化之前,确保音频先占用DMA通道0:

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

  // 先初始化音频相关
  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);
  SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
  if (!SD.begin(SD_CS))
  {
    Serial.println("SD卡初始化失败!");
    while (true);
  }
  audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
  audio.setVolume(21);
  audio.connecttoFS(SD, "/Azahriah - 'FOUR MOODS' (OFFICIAL VISUALIZER).mp3");
  xTaskCreatePinnedToCore(playSound, "playSound", 10240, NULL, 1, NULL, 0);

  // 再初始化显示屏和LVGL
  tft.init();
  tft.initDMA();
  tft.startWrite();
  tft.setBrightness(255);

  lv_init();
  if (!disp_draw_buf)
  {
    Serial.println("LVGL显示缓冲区分配失败!");
  }
  else
  {
    lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, disp_draw_buf2, screenWidth * SCR);
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = screenWidth;
    disp_drv.ver_res = screenHeight;
    disp_drv.flush_cb = my_disp_flush;
    disp_drv.draw_buf = &draw_buf;
    lv_disp_drv_register(&disp_drv);

    static lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = my_touchpad_read;
    lv_indev_drv_register(&indev_drv);

    ui_init();
    Serial.println("初始化完成");
  }

  guiHandler();
}

验证要点

  • 确认DMA通道设置正确:LovyanGFX用通道1,AudioI2S默认用通道0
  • 任务优先级:LVGL任务优先级(2)高于音频任务(1),确保界面响应优先
  • 刷新回调中等待DMA完成,避免冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 21:44:55