カメラから画像を取得してディスプレイ表示する方法を学ぶ

はじめに

 スマートフォンの普及にともなって、安価に入手できる小型のカメラが増えています。当コラムではカメラから取得したデータの表示・収集からAI分析までの開発チュートリアルを3部構成でお届けします。今回はVol.1として、RTOS「μC3/Compact」と「STM32L496G-Discovery」で、カメラからデータを取得しディスプレイに表示する方法をご紹介します。

今回の概要

 カメラから得られる画像データは応用範囲が広く存在します。例として『見守りカメラの作成(他のデバイスに画像データを転送し続ける)』『リアルタイムの異常検知(AIのアルゴリズムを組み込むこと)』『画像内の人数カウント』などが出来るようになります。

 本チュートリアルでは、以下の動画のようにカメラから取得したデータを、継続的にLCDに表示し続ける方法を紹介します。

 組み込み未経験者でも、本チュートリアルとコードを合わせて読んで頂き、PoCなどの際に別のカメラモジュールに差し替えて使ったり、別のST社のボードで使う際の参考にして頂けることを想定しています。また、文末に用語集を記述しましたので、こちらも参照ください。

必要なもの

ボードSTM32L496G-Discovery
カメラモジュールB-CAMS-OMV
IDEEWARM 8.50.6
SDKμC3/Compact for STM32L4, STM32CubeMX 6.1.2
開発PCWindows 10

 本チュートリアルでは、カメラとLCD,マイコンボードが必要になるため、これらが全て搭載されているマイコンボード「STM32L496G-Discovery(以後L496)」を使用します。

 μC3/Compact for STM32L4はhttps://www.eforce.co.jp/uc3-compact/から評価版をダウンロードすることができます。

処理の概要

1.カメラからDCMIを通じて画像データを取得
2.画像データをDMAでRAMに転送
3.DMA2DでFMC用に設定されたLCDのデータ送受信用の領域にコピー

 上記の処理を連続的に行い、カメラからキャプチャーしたデータをディスプレイに続けて表示することが可能になります。

 このチュートリアルのプログラムは、STM32CubeMXでDCMIやFMCなどのパラメータ設定、μC3のConfiguratorで割り込みや、タスクの設定や生成したソースコードを元にして作成します。

ハードウェアの接続

 LCDはL496付属のものを使用し、カメラはB-CAMS-OMVというSTマイクロエレクトロニクス社(以下STマイクロ社)の製品でOV5640というイメージセンサが載っているものを使います。

 L496にはカメラ用のコネクタが付属しており、B-CAMS-OMVとFFCケーブルで簡単に接続することができます。

設定の詳細

カメラ用DCMIの設定項目

 カメラは「画像データの左上の1ピクセル」から「右下の1ピクセル」まで1行ずつ順番にデータを転送していきます。1行分のデータ転送が終わるタイミングをHSYNC、1フレーム分のデータ転送が終わるタイミングをVSYNC、8bit分のピクセルのデータ転送が終わるタイミングをPIXSYNCで取りますので、これらのパラメータをSTM32CubeMXで設定する必要があります。

 加えて、SyncroモードはSTM32CubeMXから「External Synchro」か「Embedded Synchro」かを選択出来ますが、カメラからのHSYNCなどで同期タイミングを取りますので、External Synchroで設定します。

 L496に接続されているLCDは240×240ピクセルとなっており、出力としてQVGA(320×240)がカメラから送信されるように設定しているため、240×240でLCDに出力されるように画像データをCROPする設定が必要です。

 そのため、以下のコードをDCMIの初期化に加えて行います。なお、1pixel clockで8bitのデータ転送が行われるため、RGB565では1pixel分のデータ転送に2pixel clock必要になります。

  HAL_DCMI_ConfigCROP(&hdcmi,
                      40,                /* Crop in the middle of the VGA picture */
                      0,                 /* Same height (same number of lines: no need to crop vertically) */
                      (240 * 2) - 1,     /* 2 pixels clock needed to capture one pixel */
                      (240 * 1) - 1);    /* All 240 lines are captured */
  HAL_DCMI_EnableCROP(&hdcmi);

LCD用FSMCの設定項目

 メモリの場合は読み込み・書き込みをするメモリアドレスをアドレスバスで転送し、データを操作することになります。一方で、LCDを制御する場合は、L496の場合はレジスタの書き込み用メモリアドレスとデータの書き込み用メモリアドレスをLCD用にRAMに確保し、対応したアドレスやデータがLCDコントローラに転送されます。

 L496にはLCDコントローラを制御するために、必要なピンがあらかじめFSMCに接続されていますので、FSMCをそれに合わせて設定します。

 以下の図のようにFSMCを設定し、書き込むレジスタを0x6000’000, 送受信するデータを0x6008’0000に書き込むことで、FSMCがLCDに16bitパラレルのデータ線を通じてデータを送受信できるようになります。

カメラ関連の初期化

 B-CAMS-OMVのOV5640は画像データのアウトプットとして、10bitパラレルのDVP(Digital Video Port)とMIPI CSI-2を持ちます。STマイクロ社のボードでは、MIPI CSI-2でデータを送受信するために、STMIPID02などのMIPI CSI-2用のDe-Serializerが載っているSTM32MP1のボードなどが必要になりますので、本チュートリアルではDVPを出力として設定します。

 DVPから送信されてくるデータをL496のDCMIのデータレジスタに転送されるように、設定します。

// Disable MIPI
  {OV5640_MIPI_CONTROL00, 0x58},
//  DVP settings
  {OV5640_TIMING_DVPHO_HIGH, 0x01},
  {OV5640_TIMING_DVPHO_LOW, 0x40},
  {OV5640_TIMING_DVPVO_HIGH, 0x00},
  {OV5640_TIMING_DVPVO_LOW, 0xF0},

LCDの設定項目

 カメラから取得した画像の出力には、L496に元々付属している240×240ピクセルのLCDを使用します。262Kまでの色を表現できるため、RGB565で画像を出力します。

 st7789h2というLCDコントローラで制御するようになっており、16bitパラレルインタフェースで、データやコマンドの送受信のタイミングに必要なD/CX(Command/Data Select)ピン、Chip SelectなどのピンはFSMC(Flexible Static Memory Controller)を使った接続をするようになっています。

フレームの描画

 HAL_DCMI_Start_DMA関数を呼び出すことで、DCMIで取得したデータがDMAでRAMに転送が開始されます。

 毎フレーム画像を更新し続けるためには、転送完了時に呼び出されるDCMIのDCMI_DMAXferCpltというコールバック関数に再度LCDへの描画処理を入れて、毎回描画が終わるたびに次の描画がされる必要があります。

void BSP_CAMERA_FrameEventCallback(void)
{
  HAL_StatusTypeDef hal_status = HAL_OK;  										      
  /* Fully fill the LCD screen */
  LCD_ImagePreparation(0, 0, ST7789H2_LCD_PIXEL_WIDTH, ST7789H2_LCD_PIXEL_HEIGHT);
  /* Write data (through DMA2D) */
  hal_status = LCD_Write((uint32_t) (&pBuffer), (uint32_t)&(LCD_ADDR->REG), ST7789H2_LCD_PIXEL_WIDTH * ST7789H2_LCD_PIXEL_HEIGHT);
  UNUSED(hal_status);
}

まとめ

 カメラから取得した画像データをLCDに継続して表示をさせるためには「カメラから取得した画像をDMAでRAMに転送し、RAMからLCDに画像データをコピーする」という処理を繰り返し行う必要があります。

 カメラからの画像データ取得方法は、カメラモジュールによりインタフェースが異なりますが、STマイクロ社のボードの場合はDCMIを使うことで、毎回モジュール依存のRead/Writeの処理を書く必要がなくなります。カメラの初期化を書けばデータを連続的にDCMIで取得し、RAMに転送してくれます。

 得られた画像データをLCDに映すためには、LCDモジュール依存の処理も多く存在します。FSMCを用いることで、接続インタフェースやタイミングを意識することなく、0x6000’0000に設定対象レジスタを書き込み、データの送受信は0x6008’0000に書き込み/読み込みすることで可能です。

 LCDへのデータ転送には、DMA2D(画像データ転送に特化したDMA)を用いることで、LCDに転送するデータのフォーマットや送受信速度を意識することなく、カメラからLCDまでのデータ転送が実現されています。

用語集

STM32CubeMX
 使用するボードに合わせて初期化や、ドライバのコードを自動生成するSTマイクロ社のツールです。

DCMI
 DCMI (Digital Camera Interface) -カメラとのピンを接続し、カメラに合わせた初期設定をI2Cなどを通じて行うことにより、カメラからのデータ受信、VSYNC・HSYNC・PIXSYNCのようなタイミングのパラメータやDMAを用いたRAMへのデータ転送を担うインタフェースになります。

VSYNC, HSYNC, PIXSYNC
 カメラデータの取得のためには、いくつかタイミング・パラメータが必要になります。例えば180×180ピクセルの画像データを取得する場合は、180×180のデータをカメラから継続的に転送され続けるため、1フレームの転送が終わるタイミング「VSYNC」、1行分のデータ転送が終わるタイミング「HSYNC」、1byte分のデータ転送が終わるタイミング「PIXSYNC」などに対して割込みを設定することで、各フレームに対する処理などの記述が可能になります。

https://www.digi.com/resources/documentation/digidocs/90001945-13/reference/yocto/r_an_adding_custom_display.htmより引用

I2C
 プロセッサとカメラなどがお互いに通信を行う方法の1つ。カメラもI2Cでレジスタに設定値を書き込むことで、カメラデータの出力方法やリセットなどの制御ができます。

DMA
 CPUを介さないデータの転送方法。一般的にデータ転送などにはある程度の時間がかかるため、CPUをデータ転送に使ってしまうとその間他の処理が出来なくなってしまいます。DMAを使えば、データ転送中はCPUが他の処理を行うことが可能になります。

DMA2D
 グラフィックスに特化したDMAで、背景を透過させる処理やピクセルのフォーマットを変更できるなど、通常だと時間のかかる画像処理も行います。

FSMC
 FSMC(Flexible Static Memory Controller)はIntel8080を使ったパラレルインタフェースなどで外部メモリを制御できるコントローラとなっており、FSMCと書き込み・読み込みのタイミング設定に必要なGPIOピンとデータ・アドレス転送に必要なインタフェースを接続することで利用が可能になります。

参考文献

Discovery kit with STM32L496AG MCU
https://www.st.com/en/evaluation-tools/32l496gdiscovery.html

Using the Chrom-ART Accelerator™ to refresh an LCD-TFT display on STM32L496xx/L4A6xx/L4Rxxx/L4Sxxx microcontrollers
https://www.st.com/resource/en/application_note/dm00338361-using-the-chromart-accelerator-to-refresh-an-lcdtft-display-on-stm32l496xxl4a6xxl4rxxxl4sxxx-microcontrollers-stmicroelectronics.pdf

LCD-TFT display controller (LTDC) on STM32 MCUs
https://www.st.com/resource/en/application_note/dm00287603-lcdtft-display-controller-ltdc-on-stm32-mcus-stmicroelectronics.pdf

TFT LCD interfacing with the high-density STM32F10xxx FSMC
https://www.st.com/resource/en/application_note/cd00201397-tft-lcd-interfacing-with-the-highdensity-stm32f10xxx-fsmc-stmicroelectronics.pdf

Adding a custom display
https://www.digi.com/resources/documentation/digidocs/90001945-13/reference/yocto/r_an_adding_custom_display.htm