メイン・コンテンツまでスキップ

SPIディスプレイ・インタフェース

このシナリオでは、SPIシリアル・インタフェースとGRAMを搭載したディスプレイを使用する場合に、SPIとTouchGFX Generatorを設定する方法について説明します。

Note
このシナリオでは、動作するディスプレイ・ドライバはボードの立ち上げフェーズで開発されたものとします。 ドライバは、ピクセルをディスプレイに転送し、ディスプレイのメモリ書き込み位置を制御できる必要があります。 詳細については、ディスプレイのデータシートを参照してください。

設定

SPIの設定

他のディスプレイ・インタフェース(FMCなど)と比べて、SPIの帯域幅は低くなっています。 このため、SPIの設定を最高のボーレートに最適化して、帯域幅を最大化することが重要です。 STM32CubeMXカテゴリ・リストの[Connectivity]グループにある[SPI]を有効にします。 CPUの負荷を最小化するために、SPIへのDMAチャネルを設定することを推奨します。 SPIのボーを32MBit/sに制限している64MHzのマイクロコントローラの例を以下に示します。

FMCバンクの設定

ディスプレイと整合するようにクロック・パラメータを設定します。

TouchGFX Generator

SPIディスプレイ・インタフェースを使用する場合は、TouchGFX Generatorで「カスタム」ディスプレイ・インタフェースを選択する必要があります。 つまり、完全なHALは自動で生成できないので、ピクセルをフレームバッファ・メモリからディスプレイに手動で転送するための機能を、開発者が実装する必要があるのです。 これを実行するために必要なすべてのハンドルは、TouchGFX Generatorによって生成されます。

ディスプレイ・インタフェース - カスタム

DMAの設定

CPUの負荷を最小化するために、フレームバッファからSPI TXアドレスにピクセル・データを転送するためのDMAチャネルを設定できます。

ユーザ・コード

一般的に、GRAMを内蔵したディスプレイの場合、生成されたTouchGFX HALハンドルのTouchGFXHAL.cppにおける実装では、以下の手順を実行して、ピクセルをディスプレイに転送し、ディスプレイとTouchGFX Engineを同期する必要があります。

  1. 「VSYNC」(ティアリング効果(TE)信号と呼ばれることもあります)を待ち、TouchGFX Engineに信号を送ります。
  2. 再描画されるフレームバッファの領域に基づいて、この領域に対応するGRAM内の場所に、「ディスプレイ・カーソル」および「アクティブ・ウィンドウ」(更新されるディスプレイ領域)を移動します。
  3. 送られてくるピクセル・データをGRAMに書き込む準備を整えます。 フレームバッファ戦略と使用するディスプレイ・インタフェースに応じて、これはフレームバッファのポインタのスワッピング、TouchGFX Engineの信号伝達、または前の転送の完了を待つことであったりします。
  4. ピクセル・データを送信します。

使用するディスプレイとフレームバッファ戦略によって、上記の手順の実装方法は異なります。

サポートされるフレームバッファ戦略

  • シングル
  • ダブル
  • パーシャル - GRAMディスプレイ(推奨)
Further reading
TouchGFXのフレームバッファ戦略の概要については、「フレームバッファ戦略」の記事を参照してください。

他のディスプレイ・インタフェースと比べてSPIで達成される帯域幅は限られているので、パーシャル - GRAMディスプレイ戦略の使用を推奨します。 この戦略には使用するRAMの量が非常に少ない(一般的にSPIはRAMの限られた単純なシステムで使用される)という利点があり、更新されたピクセルのみをディスプレイへ転送することで、使用可能な帯域幅の利用を最適化します。 ただし、ティアリングのリスクがあります。

SPIによるシングル・バッファを使用すると、長時間のレンダリングによって起こるティアリングが回避されます。 ただし、SPIは帯域幅が小さいので、ディスプレイへのピクセルの転送が、ディスプレイ・スキャンラインによるGRAMバッファの読み出しより一般的に低速になります。 このため、ティアリングを防ぐために、TE信号の立ち下がりエッジ(ディスプレイがアクティブ領域に入った時点)で転送を開始することが重要です。 このためのコードは以下のようになります。

TouchGFXHAL.cpp
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == LCD_TE_Pin)
{
// VSync has occurred, increment TouchGFX engine vsync counter
HAL::getInstance()->vSync();
// VSync has occurred, signal TouchGFX engine
OSWrappers::signalVSync();
GPIO::clear(GPIO::VSYNC_FREQ);

if (refreshRequested)
{
refreshRequested = false;
nextSendToDisplayLine = refreshMinLine;
maxSendToDisplayLine = refreshMaxLine;
sendNextFrameBufferBlockToDisplay();
}
}
}
Note
ディスプレイ転送の帯域幅がディスプレイ・スキャンラインよりも低速である場合、ティアリングを防ぐために、TE信号の立ち下がりエッジで転送を開始する必要があります。

SPIによるダブル・バッファを使用すると、長時間のレンダリングによって起こるティアリングが回避されます。 ただし、各フレームでディスプレイに過剰なピクセルが転送された場合、GRAMバッファを読み出すスキャンラインが転送されている領域と衝突し、低速な転送帯域幅によるティアリングが発生します。 この問題は、フレームバッファ全体ではなく、更新されたピクセル領域のみを転送することで軽減できます。 関数TouchGFXHAL::flushFrameBufferを使用して、各フレーム内の更新された領域を計算し、最小限の転送領域を定めることができます。

シングル

現在のところ、TouchGFX Board Supportには、SPIを使用したシングル・バッファに関するリファレンス実装が含まれていません。 このセットアップは「FMCシングル・バッファ」のセットアップと似ていますが、FMCではなくSPIのドライバ機能を使用します。

ダブル

現在のところ、TouchGFX Board Supportには、SPIを使用したダブル・バッファに関するリファレンス実装が含まれていません。 このセットアップは「FMCダブル・バッファ」のセットアップと似ていますが、FMCではなくSPIのドライバ機能を使用します。

パーシャル - GRAMディスプレイ

TouchGFX Board Setup NUCLEO-G071RB + GFX01M2には、SPIを使用したパーシャル - GRAMディスプレイのリファレンス実装が含まれています。 このセットアップは「FMCパーシャル・バッファ」のセットアップと似ていますが、FMCではなくSPIのドライバ機能を使用します。