ESP32-WROOM-32 で ILI9341 に SDから読みだした PNG画像を連続描画【マルチコア使用】

戦略

描画とSDからの読み出しを別々のコアでやることで並列に動作させてできるだけアイドルを減らす。

画像の前半を読んだらセマフォを開放。前半の描画を行っている間に次の後半の描画部分を読みだす。 描画のほうが早いので読み出しの速度分のFPSがでるはず。

コード

#include "FS.h"
#include "SD.h"
#include "SPI.h"
#include "TFT_eSPI.h"

TFT_eSPI tft = TFT_eSPI();       // Invoke custom library
SPIClass sd_HSPI(HSPI);
#define HSPI_SCK  14
#define HSPI_MISO 35
#define HSPI_MOSI 13
#define HSPI_SS   15
#define SDSPEED   16000000
boolean sdHasError;

SemaphoreHandle_t xSemaphore1;
SemaphoreHandle_t xSemaphore2;
SemaphoreHandle_t xSemaphore3;

static uint8_t data1[120 * 320];
static uint8_t data2[120 * 320];

void testOriginalData() {
  xSemaphoreTake(xSemaphore1, portMAX_DELAY);
  tft.pushImage(0,   0, 320, 120, data1);
  xSemaphoreGive(xSemaphore1);
  
  xSemaphoreTake(xSemaphore2, portMAX_DELAY);
  tft.pushImage(0, 120, 320, 120, data2);
  xSemaphoreGive(xSemaphore2);
}

bool readFile(fs::FS &fs, const char * path){
  if(sdHasError) {
    return false;
  }

  File file = fs.open(path);
  if(!file){
      Serial.println("Failed to open file for reading");
      return false;
  }

  xSemaphoreTake(xSemaphore1, portMAX_DELAY);
  xSemaphoreGive(xSemaphore3);
  file.read(data1, 120 * 320);
  xSemaphoreGive(xSemaphore1);
  
  xSemaphoreTake(xSemaphore2, portMAX_DELAY);
  file.read(data2, 120 * 320);
  xSemaphoreTake(xSemaphore3, portMAX_DELAY);
  xSemaphoreGive(xSemaphore2);

  file.close();
  return true;
}

void task0(void* arg) {
  char buf[255];
  while(1) {
    for(int i = 1; i <= 100; i++) {
      sprintf(buf, "/output/%04d.dat", i);
      readFile(SD, buf);
      delay(1);
    }
  }
}

void setup()
{
// Setup the LCD
  tft.init();
  tft.setRotation(1);

  sd_HSPI.begin(HSPI_SCK, HSPI_MISO, HSPI_MOSI, HSPI_SS);

  Serial.begin(115200);
  delay(100);

  if(!SD.begin(HSPI_SS, sd_HSPI, 12000000L)){
      Serial.println("Card Mount Failed");
      sdHasError = true;
  } else {
    Serial.println("Card Mount Succeeded");
  }

  xSemaphore1 = xSemaphoreCreateMutex();
  xSemaphore2 = xSemaphoreCreateMutex();
  xSemaphore3 = xSemaphoreCreateBinary();

  xTaskCreatePinnedToCore(task0, "Task0", 4096, NULL, 1, NULL, 0);
  tft.fillScreen(TFT_BLACK);
}

void loop()
{
  xSemaphoreTake(xSemaphore3, portMAX_DELAY);
  xSemaphoreGive(xSemaphore3);

  if (sdHasError) {
    if(!SD.begin(HSPI_SS, sd_HSPI, SDSPEED)){
        Serial.println("Card Mount Failed");
        delay(1000);
        return;
    } else {
      Serial.println("Card Mount Succeeded");
      sdHasError = false;
    }
  }
  
  //randomSeed(1234); // This ensure test is repeatable with exact same draws each loop
  char buf[255];
  int x, x2;
  int y, y2;
  int r;
  
// Clear the screen and draw the frame
  static unsigned long old_time;
  old_time = millis();
  testOriginalData();
  Serial.print((float)1/(millis()-old_time)*1000);
  Serial.println(" fps");
}

結果

6.80 ~ 7.50 fps になった。