M5Stack CoreS3の内蔵カメラとLCDをZephyr RTOSで動かしてみました。
CoreS3には、GC0308(DVPカメラ)とILI9342C(LCD)が搭載されています。
今回は、Zephyr RTOS上でカメラ映像を内蔵LCDへリアルタイム描画(約13.4 FPS)するシステムを構築したメモです。
外部PSRAMを使わず、内蔵SRAMのみでDMAダブルバッファリングを実現した工夫も紹介します。
M5Stack CoreS3でカメラ & LCD表示!Zephyr RTOSで動かしてみた
M5Stack CoreS3の内蔵カメラとLCDをZephyr RTOSで動かしてみました。
CoreS3には、GC0308(DVPカメラ)とILI9342C(LCD)が搭載されています。
今回は、Zephyr RTOS上でカメラ映像を内蔵LCDへリアルタイム描画(約13.4 FPS)するシステムを構築したメモです。
外部PSRAMを使わず、内蔵SRAMのみでDMAダブルバッファリングを実現した工夫も紹介します。


プロジェクト・GitHubのリンク先
GitHubのリンク先は下記です

実際のデモ動画は下記です
CoreS3のハードウェア構成とインターフェース
M5Stack CoreS3は、ESP32-S3をコアとし、多彩な周辺デバイスがコンパクトに一体化されたデバイスです。
カメラモジュールにはGalaxyCore製のGC0308(0.3MP VGA CMOSセンサ)が採用されています。
ESP32-S3のDVP(Digital Video Port)周辺機能へ、8ビット並列データバスで直接結線されています。
ディスプレイには、2.0インチのカラーTFT液晶(ILI9342C、解像度320x240)がSPI接続されています。
ピンアサイン一覧
ESP32-S3と各ペリフェラルの主要な接続構成は以下の通りです。
| 機能区分 | 信号名 | 物理ピン / 制御元 | 役割・説明 |
|---|---|---|---|
| DVPデータバス | D0 ~ D7 | GPIO 39, 40, 41, 42, 15, 16, 48, 47 | 8ビット並列画像データ入力バス |
| DVP同期クロック | PCLK / VSYNC / HREF | GPIO 45 / 46 / 38 | 画素クロック、垂直同期、水平有効信号 |
| マスタークロック | MCLK | オンボード水晶発振器 (X2) | カメラ用20MHzマスタークロック(GPIO不要) |
| I2C制御バス | SCL / SDA | GPIO 11 / 12 | カメラレジスタ制御(7ビットアドレス: 0x21) |
| リセット制御 | RESET | AW9523B (P1_0) | I2C IOエクスパンダ経由のアクティブLowリセット |
| カメラ電源系統 | VDDCAM / AVDD / DVDD | AXP2101 (ALDO3, BLDO1, BLDO2) | PMIC制御による3.3V / 2.8V / 3.3V安定給電 |
| LCDディスプレイ | SPI / CS / DC / BL | SPI2 / AXP2101 (DLDO1) | 320x240 LCDパネル(バックライト給電含む) |
Zephyrでのデバイスツリー設定(.overlay)
Zephyr RTOSからカメラとLCDを制御するため、デバイスツリーオーバーレイを作成します。
ESP32-S3のLCD_CAMペリフェラルをDVPモードとして定義し、各ピンを割り当てます。
また、カメラの初期化に必要なAXP2101の電源レールを常時ONにし、LCDのSPI周波数を設定します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
/* m5stack_cores3_esp32s3_procpu.overlay */ #include <zephyr/dt-bindings/pinctrl/esp32s3-pinctrl.h> / { chosen { zephyr,camera = &lcd_cam_dvp; zephyr,display = &ili9342c; }; }; &pinctrl { lcd_cam_default: lcd_cam_default { group1 { pinmux = <LCD_CAM_V_SYNC_CAM_GPIO46>, <LCD_CAM_H_ENABLE_CAM_GPIO38>, <LCD_CAM_CAM_PCLK_GPIO45>, <LCD_CAM_DATA_IN0_GPIO39>, <LCD_CAM_DATA_IN1_GPIO40>, <LCD_CAM_DATA_IN2_GPIO41>, <LCD_CAM_DATA_IN3_GPIO42>, <LCD_CAM_DATA_IN4_GPIO15>, <LCD_CAM_DATA_IN5_GPIO16>, <LCD_CAM_DATA_IN6_GPIO48>, <LCD_CAM_DATA_IN7_GPIO47>; input-enable; bias-disable; }; }; }; &i2c0 { gc0308: gc0308@21 { compatible = "galaxycore,gc0308"; reg = <0x21>; status = "okay"; reset-gpios = <&aw9523b_gpio 8 GPIO_ACTIVE_LOW>; port { gc0308_ep_out: endpoint { remote-endpoint = <&dvp_ep_in>; }; }; }; }; /* 高速描画のためLCDのSPIクロックを40MHzに設定 */ &spi2 { clock-frequency = <40000000>; }; &ili9342c { mipi-max-frequency = <40000000>; }; |
画面の歪み・見切れを解決するクロップ設定
実装の初期段階では、画面右側に黒い帯が出たり、画像が斜めに歪む現象が発生しました。
原因を調査したところ、GC0308センサの出力解像度にありました。
センサの受光素子アレイ(648x488)から単純に1/2サブサンプリングを行うと、出力画素数は324x244(158,112バイト)になります。
これをLCDの解像度である320x240(153,600バイト)のDMAバッファにそのまま流し込むと、1行あたり4ピクセル分のズレが累積し、斜めの歪みや画面下部の見切れが発生してしまいます。
Hardware Crop Window(ハードウェア切り出し)による解決
ドライバ側でGC0308のPage 0レジスタ(0x46)を設定し、ハードウェアクロップ機能を有効化しました。
X0=0, Y0=0, Width=320, Height=240 を指定し、センサから送出される段階できっちり153,600バイトに成形します。
この調整により、画面全域に歪みのない映像が表示されるようになりました。
ゼロPSRAM・内蔵SRAMのみで実現するDMAダブルバッファ
カメラ映像をスムーズに描画するためには、バッファリング設計が非常に重要です。
シングルバッファでは、画面の途中で描画が更新されるテアリングや、色の反転(サイケデリックな色合い)が発生します。
CoreS3には外部PSRAMも搭載されていますが、今回はESP32-S3の内蔵SRAM(DRAM0)のみで完結させるアーキテクチャを採用しました。
* ビデオバッファプールの確保: 2面分のフレームバッファ(153.6KB × 2 = 307.2KB)を静的に確保。
* スタック領域の最適化: メインスタックを4KBに抑え、DRAM使用率を98.50%(393.1KB / 399.1KB)に最適化。
* Ping-Pong DMA転送: GDMAがバッファ0へカメラ映像をキャプチャしている間に、CPUとSPIコントローラがバッファ1のデータをLCDへ送信。
さらに、LCDのSPIクロックをデフォルトの20MHzから40MHzへ倍速化しました。
1フレームあたりのLCD転送時間を51msまで短縮でき、安定して約13.4 FPSの描画レートを達成しています。
シリアルブートログ取得の工夫(CONFIG_BOOT_DELAY)
ESP32-S3の内蔵USB-Serial/JTAGコントローラは、SoCがリセットされるとPC側で一度切断され、COMポートの再認識(列挙)が行われます。
そのため、PC側のターミナルソフトが再接続する前に、Zephyrの初期ブートログが流れて見落としてしまう問題がありました。
そこで、プロジェクト設定(prj.conf)に3秒のブート遅延を追加しました。
|
1 2 |
# prj.conf CONFIG_BOOT_DELAY=3000 |
この設定により、起動バナーの出力が3秒間待機されるため、Tera TermやMobaXtermなどのシリアルコンソールで確実に最初のブートログを取得できます。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
[00:00:03.013,000] <inf> video_gc0308: GC0308 camera sensor successfully detected! Chip ID: 0x9b [00:00:03.148,000] <inf> video_gc0308: GC0308 hardware configured for exact 320x240 (subsample + crop window) [00:00:03.148,000] <inf> video_gc0308: GC0308 initialized successfully (Default: 320x240 RGB565) *** Booting Zephyr OS build v4.4.0-12700-g8dafb9a897da (delayed boot 3000ms) *** [00:00:03.148,000] <inf> camera_display: ============================================== [00:00:03.148,000] <inf> camera_display: M5Stack CoreS3 Camera LCD Preview Viewer [00:00:03.148,000] <inf> camera_display: Zephyr OS Build: 4.4.99 [00:00:03.148,000] <inf> camera_display: ============================================== [00:00:03.148,000] <inf> camera_display: Display device ready: ili9342c@0 [00:00:03.512,000] <inf> camera_display: Camera device ready: lcd_cam_dvp [MAIN] Preview: 27 frames (~13.4 FPS) [deq=0ms, disp=51ms, enq=0ms] INT_RAW=0x0 G46=1 [MAIN] Preview: 27 frames (~13.1 FPS) [deq=47ms, disp=51ms, enq=1ms] INT_RAW=0x0 G46=1 |
ビルドと書き込み手順(West)
Zephyrの開発環境(west)を用いて、M5Stack CoreS3向けにビルドと書き込みを実行します。
仮想環境の有効化
PowerShellでZephyrの仮想環境を立ち上げます。
|
1 2 |
cd $env:USERPROFILE .\zephyrproject\.venv\Scripts\Activate.ps1 |
アプリケーションのビルド
ターゲットボードに m5stack_cores3/esp32s3/procpu を指定してビルドします。
|
1 |
west build -p auto -b m5stack_cores3/esp32s3/procpu src/camera_display -d src/camera_display/build |
CoreS3への書き込み
USB-CケーブルでCoreS3を接続し、ファームウェアを書き込みます。
|
1 |
west flash -d src/camera_display/build --esp-device COM9 --esp-baud-rate 921600 |
性能・リソース測定のまとめ
本システムの実機検証で得られた性能データは以下の通りです。
| 測定項目 | 実測値 | 解説・設計上のポイント |
|---|---|---|
| プレビュー解像度 | 320 x 240 | RGB565形式(1画素16ビット、1フレーム153,600バイト) |
| 安定フレームレート | ~13.4 FPS | フレーム落ちなし、DMAアンダーフローなし |
| LCD SPIクロック | 40 MHz | 全画面転送時間を51msに短縮 |
| カメラ画素クロック (PCLK) | ~10 MHz | フレーム間隔約98ms(生レート約10.2 FPS) |
| 内蔵DRAM使用量 | 393.1 KB / 399.1 KB | 98.50%(内蔵SRAMのみにぴったり収容) |
| 外部PSRAM使用量 | 0 KB | PSRAM依存なし、バス競合ゼロ |


実際のデモ動画は下記です。
まとめ
M5Stack CoreS3の内蔵DVPカメラ(GC0308)とLCD(ILI9342C)を、Zephyr RTOS上で動かす実装例を紹介しました。
センサ側のハードウェアクロップ設定によるアライメント調整や、内蔵SRAMのみを使ったDMAダブルバッファリングにより、滑らかなリアルタイム表示が実現できました。
ESP32-S3の内部リソースを極限まで引き出したRTOS制御として、非常に面白い構成となっています。
ソースコードもGitHubに公開していますので、ぜひ試してみてください!

コメント