01.M5Tab5でjpgの一部を自動送り表示
01.M5Tab5でjpgの一部を自動送り表示
M5Stack Tab5をスイッチサイエンスで購入しました。
https://www.switch-science.com/collections/m5stack/products/10378
電池は別売りなので、アマゾンで購入。NP-F550互換バッテリー2900mAhが2個とUSB充電器のセットで3399円でした。
A4程度の大きさの本をスキャンしてpdfにした手持ちがたくさんあったのでそれをM5Stack Tab5で見れるようにします。今回は初期セットから1頁分を順番に表示するまでです。
スケッチ概要
PCでpdfをjpgに変換し、短辺2432pxのjpgとします。それをTab5横置き(1280x720px)で部分表示させます。左上1タイル目 → 右上1タイル目 → 左2タイル目 → ・・・・・ → 右上6タイル目 の順に
1頁12タイル(横2x縦6タイル)を0.5秒ごとに自動送りで表示させます。(今回はここまで)
表示の重なりは、タイルの左右は128px、上下は100px以上としました。
製品仕様
スイッチサイエンス製品紹介
https://www.switch-science.com/collections/m5stack/products/10378本家製品紹介の一部
https://docs.m5stack.com/en/core/Tab5電源に関する注意
電源を切ったり、バッテリーを交換したりする前に、まずシャットダウンを実行。電源が直接切断されている場合は、5秒待ってから再度電源を入れます。そうしないと、異常電圧によりIMUセンサーが正しく初期化されない事があります。
電源on/off
USBケーブル or バッテリーで駆動時、電源ボタンを1回押すと、電源がoffになっている時にonになります。onの時は、2回押してoffします。
ダウンロードモード
USBケーブルを接続するか、バッテリーに電力を供給した状態で、内部の緑LEDが点滅し始めるまで、リセットボタンを押します(2秒)。離すと、ダウンロードモードに入ります。
初回起動方法
https://docs.m5stack.com/ja/arduino/m5tab5/program1.準備
1-1.済1-2.ボードマネージャーをインストール
ボードマネージャー > M5Stack by M5Stack 3.2.2(最新)をインストール
Arduino-IDE 2.3.6 > ツール > ボード > M5Stack > M5Tab5 を選択
1-3.ライブラリのインストール (すべてをインストール)
M5Unified by M5Stack 0.2.7(最新)
M5GFX by M5Stack 0.2.9(最新)
2.ダウンロードモード
USBケーブル接続時に、下面左端のリセットボタンを2秒長押し、内部の緑LEDが点滅したら放します。3. ポートの選択
Arduino-IDE > ツール > ポート > COM□を選択4.スケッチで動作確認
Arduino-IDE > ファイル > スケッチ例 > (カスタムライブラリのスケッチ例) M5GFX > Basic > BarGraph を書込み実行 > バーグラフを表示 > 動作確認終了スケッチについて
元のpdfはA4程度以下の横書きとします。本の字より大きな表示をします。・jpg1枚をPSRAMのキャンバスに展開し、マイナスのオフセットで一部をpushSpriteします。
・画面表示は全画面にしないと、数倍表示が遅くなってしまったので部分表示は止めました。
・最初にSDから読込むのが一番時間がかかります。
1.準備
1-1.pdf→jpgにオンライン変換(無料)https://www.ilovepdf.com/ja/pdf_to_jpg
* jpgは、pngより容量が小さいです。
1-2.フリーソフトIrfanView 4.62にて
横2432pxに一括変換。今回縦は3653pxになりました。
1-3.SDに保存
SDのルートに保存。今回は"09.jpg"としました。
2.overlap
横は128px固定で,縦は100px以上とします。横
pdfからjpgにする時、jpg横2432pxにします。横は2タイルとするので、重なりは、1280x2-2432=128pxになります。
縦 (overlapH)
最低100px(overlapHmin)とし、jpgの縦px(imgH)により変わります。
重なりを引いたタイル縦pxは、
lcdH - overlapHmin = 720 - 100 = 620px以下
となります。タイルの縦数は、重なりが1少ないので
(imgH - lcdH) / 620 + 1 = (3653-720)/620+1 = 5.73以上 = 6タイル
で、その時、重なりを引いたタイル縦pxは、
(imgH - lcdH) / (6 - 1) = (3653-720)/5 = 586.6 ≒ 587px
よって、
overlapH = lcdH - 587 = 720-587 = 133px
ただし、一番下の重なりを引いたタイル縦pxは、
3653-587x5-133=585px
になります。
2.表示位置
今回のjpg位置でのタイル座標は以下になります。(0,000)┌─┐(x1,000) (x2,000)┌─┐(x3,000)
(0,y01)└─┘(x1,y01) (x2,y01)└─┘(x3,y01)
(0,y02)┌─┐(x1,y02) (x2,y02)┌─┐(x3,y02)
(0,y03)└─┘(x1,y03) (x2,y03)└─┘(x3,y03)
(0,y04)┌─┐(x1,y04) (x2,y04)┌─┐(x3,y04)
(0,y05)└─┘(x1,y05) (x2,y05)└─┘(x3,y05)
(0,y06)┌─┐(x1,y06) (x2,y06)┌─┐(x3,y06)
(0,y07)└─┘(x1,y07) (x2,y07)└─┘(x3,y07)
(0,y08)┌─┐(x1,y08) (x2,y08)┌─┐(x3,y08)
(0,y09)└─┘(x1,y09) (x2,y09)└─┘(x3,y09)
(0,y10)┌─┐(x1,y10) (x2,y10)┌─┐(x3,y10)
(0,y11)└─┘(x1,y11) (x2,y11)└─┘(x3,y11)
x1=1280,x2=1152,x3=2432
y01=720,y02=587,y03=y02+720,y04=1174,y05=y04+720,y06=1761,
y07=y06+720,y08=2348,y09=y08+720,y10=2933,y11=y10+720=3653
単純計算ではy10=2935ですが、縦720px以下となるため、
下に余白ができ前回の表示が見えてしまうので、
2933(=3653-720)にして全画面表示とします。
スケッチ
// jpg1枚をPSRAMのキャンバスに展開し、
// マイナスのオフセットで一部をpushSprite
#include <SD.h> // SDを使用 SDの方が上に書く
#include <M5Unified.h> // M5統合ライブラリ
#define SD_SPI_CS_PIN 42 // SD CS pin
#define SD_SPI_SCK_PIN 43 // SD SCK pin
#define SD_SPI_MOSI_PIN 44 // SD MOSI pin
#define SD_SPI_MISO_PIN 39 // SD MISO pin
static const char* imgF = "/09.jpg"; // 読込file
static const int imgW = 2432; // jpg横(=38x64) tileW*2(=2560)以下
// 横重なりは、lcdW x 2 - imgW = 1280x2-2432 = 128px
static const int imgH = 3653; // jpg縦 1.41倍程度 スキャン切抜きにより異なる
static const int lcdW = 1280; // 表示横 画面横いっぱい
static const int lcdH = 720; // 表示縦 全画面表示で無いと数倍遅い。一番下のタイル表示は我慢
static const int overlapHmin = 100; // 縦重なり
int overlapH;
M5Canvas canvas(&M5.Display); // canvasをM5.Displayに描画
void setup() {
M5.begin(); // M5の初期化
SPI.begin(SD_SPI_SCK_PIN, SD_SPI_MISO_PIN, SD_SPI_MOSI_PIN, SD_SPI_CS_PIN); // SPIの初期化
M5.Display.setRotation(3); // 画面回転 (0-3,4-7)
M5.Display.fillScreen(TFT_DARKGREEN); // 全画面を深緑 起動確認のため
M5.Display.setBrightness(100); // 明るさ (0暗-255明)
M5.Display.clear(); // 画面クリア
M5.Display.setFont(&fonts::lgfxJapanGothic_40); // 固定幅ゴシック 8,12,16,20,24,28,32,36,40
if (!SD.begin(SD_SPI_CS_PIN, SPI, 25000000)) {
// SDの初期化に失敗時 or SDが存在しない時(CSpin,SPI通信,SPI25MHz)
M5.Display.print("\n SD cardが見つかりません"); // 画面表示
for (;;) delay(1000); // 永久ループ
}
M5.Display.println("\n SD cardを検出\n"); // 画面表示
canvas.setPsram(true); // キャンバスはPSRAMを使用
canvas.setColorDepth(16); // 色の深さ(1,2,4,8,16,24,32)
if (!canvas.createSprite(imgW, imgH)) { // 1頁丸ごとキャンバスが作れなければ
// 2400×3604×RGB565≈16.5MB程度を確保。PSRAM断片化で失敗したら再起動や初期確保
M5.Display.println(" キャンバス枠作成 失敗"); // 画面表示
for (;;) delay(1000); // 永久ループ
}
//M5.Display.println("キャンバス枠作成 成功\n"); // 画面表示
M5.Display.println(" jpgをキャンバスに描画中\n"); // 画面表示
if (!canvas.drawJpgFile(SD, imgF, 0, 0)) { // キャンバスにjpgを描画できなければ
M5.Display.println(" jpgをキャンバスに描画 失敗"); // 画面表示
for (;;) delay(1000); // 永久ループ
}
overlapH = ((imgH * 1.0 - lcdH) / (lcdH - overlapHmin) + 1 + 0.999);
overlapH = ((imgH * 1.0 - lcdH) / (overlapH - 1) + 0.5);
overlapH = lcdH - overlapH; // 縦のoverlap(px)
M5.Display.printf(" overlapH= %3dpx\n\n", overlapH); // overlapHを表示
M5.Display.println(" 表示 開始"); // 画面表示
delay(1000); // 1秒待つ
}
void loop() {
bool viewEnd = 0; // 表示する
for (int32_t offY = 0; offY > -imgH; offY -= lcdH - overlapH) { // 最後はbreakで抜ける
if (lcdH > imgH + offY) { // 一番下のブロック(表示が余る)なら
offY = -(imgH - lcdH); // 全画面表示するよう重なりを増やす
viewEnd = 1; // 表示終了フラグ
}
canvas.startWrite(); // バッファを効率的に使用開始
//M5.Display.fillScreen(TFT_BLACK);// 全画面黒 ちらつくのでやめ
canvas.pushSprite(0, offY); // 左キャンバスをプッシュ(左上基準点)
canvas.endWrite(); // バッファを効率的に使用終了
delay(500); // 0.5秒待つ
canvas.startWrite(); // バッファを効率的に使用開始
//M5.Display.fillScreen(TFT_BLACK); // 全画面黒 ちらつくのでやめ
canvas.pushSprite(-(imgW - lcdW), offY); // 右キャンバスをプッシュ(左上基準点)
canvas.endWrite(); // バッファを効率的に使用終了
delay(500); // 0.5秒待つ
if (viewEnd) break; // 表示終了
}
}
* flash memory(6.5Mbyte)のうち、スケッチが16%使用。RAM(327kbyte)のうち、global変数が7%使用、
local変数で301kbyte使用可能。(1000byte=1kbyteで計算)