エイアイ・ラボ・ジャパン TAB5 / CAMERA M5Stack Tab5 · ESP32-P4 · MIPI-CSI Arduino-ESP32 3.3.12 camera only

sample program / for arduino ide

Tab5 の内蔵カメラを、Arduino で動かす。

素の Arduino では素直に動いてくれない M5Stack Tab5 のカメラを、 映像が出るところまで確実に立ち上げるための1本です。 初期化の順序、黒画面の直し方、色化けの直し方、暗い場所で画面をライトにする使い方まで。 実機で確かめた設定と、つまずいた理由をそのまま書いてあります。

  • Arduino-ESP32 3.3.12
  • M5Stack Tab5
  • M5Unified
  • ESP_Video(コア同梱)
  • 1280×720 / RGB565
  • シリアル操作
MIPI-CSI · SC202CS · RGB565 1280×720
LIGHT L | SWAP | 26.0 fps | exp 1000

fps 実測 ms 1フレームの表示時間 LIGHT L 左半分が照明(白)exp 露出時間

ページを開くと、実機と同じ起動カラーバー(白→赤→緑→青→CAM INIT OK)が流れます。

spec / できること

「映る」までを、確実に

本体に組み込む前の切り分けを目的にしています。カメラだけを取り出して「どこまで動くか」を確かめられる形にしました。

view

カメラ映像の表示

1280×720 の映像を5インチ画面いっぱいへ。c 生 / s バイト入替 / g 明暗伸長 の3モード。既定は色化けの直る s です。

light

画面をライト代わりに

l キーで画面が真っ白に。5インチ・バックライト最大点灯の光を照明として使います。ライト中もカメラは止まりません。

half light

左半分を白く、右半分に映像

起動直後から、左半分が白(照明)/右半分がカメラ映像。暗い場所で白い面を照明や証明写真の背景にしながら、被写体を確認できます。t で全面映像、r で左右反転。

exposure

露出とゲインを手で動かす

e/E で露出時間、-/+ でゲイン。自動露出がハンチングして明るさが脈打つときの、追い込みの足がかりです。

計測を画面に出します。 実測 fps、1フレームの表示時間、いまの露出時間とゲインを下のバーに1行で表示。 「動いているか」「重すぎないか」が数字で分かるので、切り分けが速くなります。

trace / 初期化の順序

この順番に意味があります

コードもこの順で読めるように並べてあります。順序を入れ替えると動きません。とくに【1】と【4】は外せません。

  1. 【1】 XCLK 24MHz 必ず M5.begin() より先に設定します。ESP32-P4 の LEDC は全タイマがクロック源を共有するため、後から設定すると M5GFX のバックライト用と衝突して24MHzが出せません。
  2. 【2】 M5Unified 開始
    バックライト救済
    画面を横(1280×720)にし、backlightFix() で GPIO22 を素の出力として HIGH に固定します。M5GFX の調光が失敗して黒画面になるのを防ぎます。
  3. 【3】 カメラ給電
    IOエキスパンダ 0x43
    E1.P6 = CAM_RST を解放します。これをやらないとカメラは SCCB に応答しません(0x36 が出てきません)。0x01 に 0xFF は禁止。
  4. 【4】 ESP_Video 初期化
    (dont_init_ldo)
    SCCB は SCL=G32 / SDA=G31。csi.begin(cam_config, true) の true が必須です。MIPI PHY 用 LDO は画面と共用で、M5GFX が取得済みだからです。
  5. 【5】 撮影開始 cap.begin(name, 3) → setFormat(RGB565) → startCapture()。バッファは3枚。表示中に1枚取られても余裕を持たせます。
  6. 【6】 フレーム取得 captureBuffer() で RGB565 1280×720 を借用します。変数が消えると自動でドライバに返る(RAII)ので、長く握ると次のフレームが来ません。
  7. 【7】 画面表示 16ラインずつ内蔵RAMのバッファ(g_lbuf)へコピーしてから pushImage()。PSRAMから直接DMAすると黒画面になることがあります。
  8. 【8】 ライトモード
    露出・ゲイン
    画面を真っ白にして照明にします。ライト中もカメラは動き続けます。露出とゲインは setSensorExposureTime() / setSensorGain() で手動調整(実験的)。

build / コンパイル・実行に必要な注意点

外すと動かない、8つのポイント

実機で1つずつ確かめた項目です。症状と原因が対応するように書きました。

Tab5 内蔵カメラ / Arduino IDE
注意点外すとどうなるか対処
XCLK を M5.begin() より先に設定 LEDC のタイマ衝突で24MHzが出ず、カメラが応答しない xclkSetup() を setup の最初に置く。ログが 24000000 Hz なら成功
csi.begin(cam_config, true)=dont_init_ldo LDO の取り合いで初期化失敗(画面が先に取得している) 第2引数を必ず true にする
IOエキスパンダの 0x01 に 0xFF を書かない LCD_RST / TP_RST まで戻り、画面が真っ黒になる camPowerOn() の値(0x0D/0x0B/0x05/0x07/0x03)を変えない
GPIO22(バックライト)を直High に M5GFX のLEDC調光が失敗し、画面が真っ黒のまま backlightFix() を呼ぶ。setBrightness() だけでは直りません
表示は16ラインずつ内蔵RAMを経由する PSRAMから直接DMAしようとすると黒画面になることがある g_lbuf[1280*16] にコピーしてから pushImage()
フレームバッファを長く握らない 次のフレームが来ず、fps が落ちる/止まる 重い処理の前に、必要な分だけコピーして手放す
表示はバイト入替をする(s) 赤と青が入れ替わって見える(色化け) 表示は入替、解析は入替なしが原則。用途で別系統と覚える
このサンプルでは M5.update()・タッチを使わない 内蔵I2C(G31/G32)とカメラSCCBが同じピンで clear bus failed が多発。fps も 6→1.7 に低下(実測) モード切替はシリアル入力で行う。タッチが要るなら 250ms 間隔に間引く
色化けの正体。 カメラが返す RGB565 は標準の並び(赤が上位ビット)です。画面に出すときはバイトを入れ替えると赤青反転が直ります(s キー)。 逆に、輝度を計算して解析する用途では入れ替えてはいけません。ここを混同すると「どんなデコーダでも読めない画像」になります。

setup / ライブラリとファイルの置き方

ESP_Video の入れ方だけ、少し手がかかります

Arduino-ESP32 コア 3.3.11 以降には ESP_Video が同梱されていますが、環境によってはコア内の libraries\ESP_Video が見当たりません。その場合は配布しているZIPを次の形に展開してください。

# Windows の例
C:\Users\<ユーザー名>\Documents\Arduino\libraries\ESP_Video\src\ESP_Video.h
                                                     ↑ この形になるように

# NG: 1階層深くなっている
...\libraries\ESP_Video\ESP_Video\src\ESP_Video.h

展開後は Arduino IDE を再起動してください。スケッチ冒頭のマクロ定義(CONFIG_ESP_VIDEO_ENABLE_MIPI_CSI_VIDEO_DEVICE など)は消さないでください。

スケッチの置き方 — フォルダ名と .ino 名は必ず一致させます。

Arduino/
└─ Tab5_Camera_Basic_20261106/
   ├─ Tab5_Camera_Basic_20261106.ino   ← これを開く
   └─ README.md

ino と M5Unified だけでビルドできます。コマンドラインなら次の1行。

arduino-cli compile -b esp32:esp32:m5stack_tab5 Tab5_Camera_Basic_20261106
書き込みが Write timeout で失敗するときは、クラッシュ再起動ループでUSBが掴めなくなっています。 シリアルモニタを閉じる → リセットを約2秒長押し(内部の緑LEDが高速点滅=ダウンロードモード)→ 書き込み → もう一度リセット、の順で復帰します。USBケーブルはデータ通信対応のものをお使いください。

keys / 操作

シリアルモニタに1文字

Arduino IDE のシリアルモニタを 115200bps で開き、1文字送るだけで切り替わります。

キー動作使いどころ
cCOLOR(生)そのままの映像
sCOLOR バイト入替色化け(赤青反転)が直る。既定はこれ
gGRAY(明暗を伸ばす)暗い・コントラストが弱いとき
t半分照明 ON/OFF既定はON(左半分が白/右半分が映像)。OFFで全面映像
l全面ライト ON/OFF画面全体を白くして照明にする(従来のライト)
r白い側を左右反転カメラの位置に合わせて、照らしたい側へ(1=左/0=右)
e / E露出時間を 1段下げる / 上げる自動露出がハンチングするとき
- / +ゲインを 1段下げる / 上げる暗いとき(ノイズと引き換え)
0露出・ゲインを初期値へ元に戻す
hヘルプ—

画面のバーに、いまの状態が1行で出ます。半分照明のときは映像側の下端、全面表示のときは画面の下端です。

半分照明: SWAP | 26.1 fps | exp 1000
全面表示: COLOR swap | 26.1 fps | 16 ms | exp 1000 | gain 0
         表示モード  実測fps   表示時間  露出時間   ゲイン

* が付いているときは「手で動かした(手動)」の印です。

exposure / 明るさが脈打つとき

自動露出を、手で押さえに行く

本体に組み込んだ版では、映像が白っぽく、明るさが脈打つ現象が残っています。 カメラ側の AE(自動露出)が行ったり来たりしている疑いが濃いのですが、 ESP_Video の公開 API には AE を止める手段が見当たりません。 そこで、露出時間とゲインを直接投げる道具を入れておきました。

// ESP_Video.h にある V4L2 拡張コントロール
cap.setSensorExposureTime(int32_t);   // V4L2_CID_EXPOSURE_ABSOLUTE
cap.setSensorGain(int32_t);           // V4L2_CID_GAIN
cap.setSensorExposure(int32_t);       // V4L2_CID_EXPOSURE
cap.setSensorAETargetLevel(int32_t);  // V4L2_CID_CAMERA_AE_LEVEL
本スケッチが投げる値(出発点。単位はドライバ実装依存)
段露出時間ゲイン
初期値10000
下限1000
上限2000064
正直な注意点。 返り値は「ioctl が通ったか」であって、映像が変わったかではありません。ログに OK が出ても暗さが変わらないことがあります。 その場合はドライバの AE が優先されています。値の単位(マイクロ秒相当か、行数相当か)も実装依存です。
したがって 「固定露出版」はこの版では未完成です。実機で e/E を押しながら、g モードの見え方と fps を見て決めてください。

files / ダウンロード

一式をどうぞ

まずはZIPを落として展開するのが早いです(中のフォルダ名と ino 名が一致しているので、そのまま Arduino で開けます)。md5 4813f2e3b7ed3c4e6d78e0c9ad03683a body/ にあります。

  • Tab5_Camera_Basic_20261106.zip 一式(スケッチ + README) download 16,854 bytes  ·  md5 fa3f59e0323400b802252652238f0086
  • Tab5_Camera_Basic_20261106.ino スケッチ本体(映像表示 + モード + ライト + 露出/ゲイン) download 29,606 bytes  ·  md5 a9a184aac1528c701e3ba55cb7dd3ddc
  • README.md 解説書(初期化の順序 / 罠8点 / 露出 / 既知の制限) download 13,861 bytes  ·  md5 71f2193b83bcfda6084ef0533835dac1
  • ESP_Video_for_3.3.12.zip ESP_Video ライブラリ(コアに見当たらないとき用) download 15,685 bytes  ·  md5 6c1c757ca3cc5087c1585a78d05116cb
# ビルド確認(この版を作ったときの実測)
Arduino-ESP32 コア 3.3.12 / esp32:esp32:m5stack_tab5
Flash   1,075,612 bytes (16%)
RAM        70,052 bytes (21%)
warning 0 / error 0

notes / 正直な記載

確認できたこと・これからのこと

お知らせ。 現状ではI2Cと画面描画の性能に影響するため、本ライブラリとしては、二次元コードの読み取りサンプル部分を抹消しました。
ビルド
3.3.12 / warning 0
実機表示
以前の版で確認済み
この版の実機
確認済み・26fps
露出固定
未完成(実験的)

内蔵カメラの映像表示、IOエキスパンダ経由の給電、ESP_Video の初期化手順は、 実機(Tab5)で動作を確認済みです。本ライブラリは、その確認できた処理に 露出・ゲイン操作と fps 表示を足したものです。2026.11.06 に実機で書き込み・起動・カメラ初期化まで確認しました。左半分が白・右半分が映像の状態で 26.0 fps / I2Cエラー0 / AEエラー0。全面表示(1280×720)では 6〜7 fps なので、律速は表示転送です。 差異があればお知らせください。

既知の制限

  • 解像度は 1280×720 固定。SC202CS は 1600×900 / 1600×1200 も持っていますが未対応です。
  • 露出・ゲインの固定は未完成(戻り値が OK でも AE が優先される場合がある)。
  • バックライトの PWM調光は未実装(LEDC が XCLK と競合するため)。常時最大点灯です。
  • タッチ操作は使いません(内蔵I2C がカメラSCCB とピンを共有するため)。操作はシリアル1文字。