M5Stick-Cに画像を表示する

M5Stick-Cに画像を表示する方法を簡潔に、デモコードと共に紹介します。今回紹介する方法は2つ。①ヘッダファイルに変換して読み込む②SPIFFS領域に直接画像を送り込んで読み込み表示する です。

動いている様子

今回は2パターンの画像表示方法を紹介します。

参考にしたサイト

方法①-画像をコードに変換して描画

  1. Lang-shipさんの画像コード変換サイトにて、好きな画像を変換する。※M5stick-Cの解像度は80×160なので、それ以下の大きさに加工しておく

  2. 出力データをメモ帳などに貼り付け、拡張子を”.h”にして保存

  3. 以下の.inoファイルと同じフォルダに画像ファイル(.h)を移動。ここではlogo.hという画像ファイル名にしました。

#include <M5StickC.h>               // M5StickCの読み込み
// イメージデータ
#include "logo.h"                   // 画像データの読み込み
 
void setup() {
  M5.begin();
  M5.Axp.ScreenBreath(10);          
  M5.Lcd.setRotation(3);            
  M5.Lcd.setSwapBytes(false);       
}
 
void loop() {
  M5.Lcd.startWrite();
  M5.Lcd.pushImage(0, 0, imgWidth, imgHeight, img);
  // 描画終了
  M5.Lcd.endWrite();
  // Wait
  delay(1000);
}
  1. M5stick-Cに書き込んで完成!

これだけで冒頭で紹介したような画像表示ができます。ただ、このままでは画像を.hファイルに変換しないといけなく若干面倒です。

方法②-画像ファイルとしてSPIFFSにアップロードして描画

M5Stick-Cを駆動しているESP32にはSPIFFS領域と呼ばれるファイル領域が用意されています。フラッシュの一部をUSBメモリみたいに使用できるイメージです。
ここに画像ファイルのままアップロードして、表示する方法を紹介します。

  1. 画像ファイルをビットマップ形式(.bmp)で保存。24ビットで保存しましょう。

  2. 以下のコードを用意して、.ino形式で保存しフォルダを作成

    #include "FS.h"
    #include "SPIFFS.h"
    #include "M5StickC.h"
    #include "M5Display.h"
    //ここから参考にしたM5stackの関数群
    uint16_t read16(fs::File &f) {
      uint16_t result;
      ((uint8_t *)&result)[0] = f.read(); // LSB
      ((uint8_t *)&result)[1] = f.read(); // MSB
      return result;
    }
    
    uint32_t read32(fs::File &f) {
      uint32_t result;
      ((uint8_t *)&result)[0] = f.read(); // LSB
      ((uint8_t *)&result)[1] = f.read();
      ((uint8_t *)&result)[2] = f.read();
      ((uint8_t *)&result)[3] = f.read(); // MSB
      return result;
    }
    void drawBmpFile(fs::FS &fs, const char *path, uint16_t x, uint16_t y) {
      if ((x >= 160) || (y >= 80)) return;
    
      // Open requested file on SD card
      File bmpFS = fs.open(path, "r");
    
      if (!bmpFS) {
        Serial.print("File not found");
        return;
      }
    
      uint32_t seekOffset;
      uint16_t w, h, row, col;
      uint8_t  r, g, b;
    
      uint32_t startTime = millis();
    
      if (read16(bmpFS) == 0x4D42) {
        read32(bmpFS);
        read32(bmpFS);
        seekOffset = read32(bmpFS);
        read32(bmpFS);
        w = read32(bmpFS);
        h = read32(bmpFS);
    
        if ((read16(bmpFS) == 1) && (read16(bmpFS) == 24) && (read32(bmpFS) == 0)) {
          y += h - 1;
    
          M5.Lcd.setSwapBytes(true);
          bmpFS.seek(seekOffset);
    
          uint16_t padding = (4 - ((w * 3) & 3)) & 3;
          uint8_t lineBuffer[w * 3 + padding];
    
          for (row = 0; row < h; row++) {
            bmpFS.read(lineBuffer, sizeof(lineBuffer));
            uint8_t*  bptr = lineBuffer;
            uint16_t* tptr = (uint16_t*)lineBuffer;
            // Convert 24 to 16 bit colours
            for (col = 0; col < w; col++) {
              b = *bptr++;
              g = *bptr++;
              r = *bptr++;
              *tptr++ = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
            }
    
            // Push the pixel row to screen, pushImage will crop the line if needed
            // y is decremented as the BMP image is drawn bottom up
            M5.Lcd.pushImage(x, y--, w, 1, (uint16_t*)lineBuffer);
          }
          Serial.print("Loaded in "); Serial.print(millis() - startTime);
          Serial.println(" ms");
        }
        else Serial.println("BMP format not recognized.");
      }
      bmpFS.close();
    }
    
    //参考にした関数終わり
    void setup(){
        M5.begin();
        M5.Axp.ScreenBreath(12);          // 7-12で明るさ設定
        M5.Lcd.setRotation(3);            // 0-3で画面の向き  
        if(!SPIFFS.begin(true)){
            Serial.println("SPIFFS Mount Failed");
            return;
        }
        drawBmpFile(SPIFFS, "/logo.bmp", 0, 0);
    }
    
    void loop(){
      delay(1);
    }
    

    M5Stick-Cのライブラリにはファイルシステム(SDやSPIFFS)から画像を読み込んで表示する関数がありません(M5stackにはあります)。そこでM5stackのdrawBitmapFileを参考にして、drawBitmapFile関数を実装してみました。この関数部分を抜くと以下のコードだけになります。

    #include "FS.h"
    #include "SPIFFS.h"
    #include "M5StickC.h"
    #include "M5Display.h"
    void setup(){
        M5.begin();
        M5.Axp.ScreenBreath(12);          // 7-12で明るさ設定
        M5.Lcd.setRotation(3);            // 0-3で画面の向き  
        if(!SPIFFS.begin(true)){
            Serial.println("SPIFFS Mount Failed");
            return;
        }
        drawBmpFile(SPIFFS, "/logo.bmp", 0, 0);
    }
    
    void loop(){
      delay(1);
    }
    
  3. 作ったスケッチのフォルダ内にdataという名前のフォルダを作り、その中に先程の.bmpファイルを入れます。※このフォルダ内が丸ごとM5Stick-Cにアップロードされます。

  4. mgo-tecさんのSPIFFS uploaderの導入方法に従いSPIFFS uploaderを入れる

  5. ESP32 Sketch Data Uploadを選択してM5Stick-Cにデータをアップロードする。

  6. 通常通りスケッチを書き込む

  7. 完成!

手順が多いように見えますが、画像をそのまま使えるので結果として楽じゃないかなと思います。(.hファイルだと書き込みが1回で済むのは楽)

まとめ

2つの方法を紹介しました。

  1. ヘッダファイルに変換して読み込む
  2. 画像をそのままSPIFFS領域にアップロードして読み込む

好みに合わせて使ってみて下さい!

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です