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

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

このシナリオでは、 LCD-TFTパラレル・ディスプレイ・インタフェースを使用する場合に、STM32 LTDCディスプレイ・コントローラとTouchGFX Generatorを設定する方法について説明します。

TouchGFX Generatorでは完全なTouchGFX ALを生成できます。これは、フレームバッファ・メモリからディスプレイにピクセルを転送し、ディスプレイがTouchGFX Engineと同期するようにLTDCを設定するものです。

設定

STM32CubeMXカテゴリ・リストの[Multimedia]グループにある[LTDC]を有効にします。

LTDCを有効化すると、TouchGFX Generatorの[Display]セクションで[Parallel RGB (LTDC)]オプションを使用できるようになります。

STM32CubeMXでLTDCを有効にした後、以下のパラメータを設定する必要があります。

  1. 接続するディスプレイの仕様に合わせたLTDCの設定(GPIOとタイミング)
  2. 目的とするTouchGFXアプリケーションの仕様に合わせたLTDCの設定

TouchGFX Generatorは、STM32CubeMXから各種設定を読み出し、[Dependencies]セクションに警告、推奨事項、またはエラーのリストを表示することができます。 下の画像は、STM32CubeMXでLTDCを初めて有効化するときに現れる依存関係のリストを示しています。

Note
STM32CubeMXでLTDCを有効化するとすぐに、TouchGFX Generatorのインタフェースに、LTDCに関する推奨事項、警告、およびエラーが表示されます。

パラメータとレイヤの設定

LTDCブロックで以下のパラメータを設定する必要があります。

依存関係説明
レイヤ数TouchGFXには、単一レイヤのみ使用可能です。
ウィンドウ位置デフォルトでは、LTDCレイヤのウィンドウの水平位置および垂直位置は0です。 ウィンドウの水平停止位置と垂直停止位置は、ディスプレイの寸法と同じに設定する必要があります。
アルファ定数は0ですデフォルトでは、LTDCレイヤのアルファ定数は0です。 アプリケーションでグローバル・アルファを常時使用しないかぎり、この値は0より大きく、可能ならば255としてください。

次の図は、警告を解消するようにLTDCを設定し、TouchGFX Generatorのインタフェースに[Dependencies]グループが表示されなくなった状態を示しています

Note
LTDCが有効で[Display]セクションで[Parallel RGB (LTDC)]オプションが選択されている場合、TouchGFX GeneratorはLTDCの設定から高さの値を継承します。

TouchGFXドライバ / VSYNC信号

ディスプレイ・インタフェースとして[Parallel RGB (LTDC)]を選択すると、開発者はLTDC Application Tick Driverにアクセスできるようになります。これにより、LTDC割り込みを使用してTouchGFX Engineのメイン・ループを駆動します。 これは、LTDCを使用する場合にTouchGFX Engineのメイン・ループを駆動するための推奨される方法です。

Note
LTDCドライバでTouchGFXアプリケーションを自動的に駆動するには、LTDC NVIC設定またはグローバルNVIC設定で、LTDCのグローバル割り込みを有効化するとともに、ハンドラ・コードの生成も有効化する必要があります。

次のコードは、ディスプレイの準備ができたときに、TouchGFX Engineのメイン・ループに自動的に信号を送ってブロックを解除するように生成されたLTDC割り込みハンドラ(シングルまたはダブル・フレームバッファ戦略向け)を示しています。

TouchGFXGeneratedHAL.cpp
extern "C"
{
void HAL_LTDC_LineEventCallback(LTDC_HandleTypeDef* hltdc)
{
if (!HAL::getInstance())
{
return;
}

if (LTDC->LIPCR == lcd_int_active_line)
{
//entering active area
HAL_LTDC_ProgramLineEvent(hltdc, lcd_int_porch_line);
HAL::getInstance()->vSync();
OSWrappers::signalVSync();

// Swap frame buffers immediately instead of waiting for the task to be scheduled in.
// Note: task will also swap when it wakes up, but that operation is guarded and will not have
// any effect if already swapped.
HAL::getInstance()->swapFrameBuffers();
GPIO::set(GPIO::VSYNC_FREQ);
}
else
{
//exiting active area
HAL_LTDC_ProgramLineEvent(hltdc, lcd_int_active_line);

// Signal to the framework that display update has finished.
HAL::getInstance()->frontPorchEntered();
GPIO::clear(GPIO::VSYNC_FREQ);
}
}
}

LTDCフレームバッファ・アドレスの設定

生成されたTouchGFX HALが実行時にLTDCのレイヤ・カラーのフレームバッファ開始アドレスを自動的に設定するので、ユーザがLTDC設定で値を設定することはありません。

GFXMMUの設定

「パーシャル・バッファ - LTDC駆動ディスプレイ」フレームバッファ戦略を使用する場合は、GFXMMUを有効にして設定する必要があります。 GFXMMUを使用して、LTDCが読み出したフレームバッファ・アドレスを、物理メモリ内のパーシャル・フレームバッファ・ブロックのアドレスにマッピングします。

まず、[Multimedia]セクションの下でSTM32CubeMXのGFXMMUを有効にし、[Address Translation]を有効にします。 16ビットおよび32ビット・フレームバッファのピクセル・フォーマットでは、16バイトの「ブロック・サイズ」が推奨されます。 24ビット・フレームバッファのピクセル・フォーマットの場合、12バイトの「ブロック・サイズ」が必要です。

Note
一部のマイクロコントローラ(STM32U5G9など)では、「ラインあたりの16バイトのブロック数」のパラメータを「ブロック・サイズ」ではなく256または192のオプションで定義します。 これらはそれぞれ、16バイトまたは12バイトのブロック・サイズに対応します。
Caution
GFXMMUを使用してアドレスをマッピングする場合、フレームバッファのピクセル・フォーマットとブロック・サイズに応じて、使用するディスプレイの最大幅と最大高さに次のような制限があります。
  • 32ビット・フレームバッファのピクセル・フォーマット(12バイト/16バイト): 768x1024px / 1024x1024px
  • 16ビット・フレームバッファのピクセル・フォーマット(12バイト/16バイト): 1536x1024px / 2048x1024px
  • 24ビット・フレームバッファのピクセル・フォーマット(12バイト): 1024x1024px
  • TouchGFX Generatorは、GFXMMUの設定とLTDCレイヤの設定に基づいてアドレスをマッピングするアドレス・ルックアップ・テーブル(LUT)を自動的に生成します。

    GFXMMUを有効にした後、使用されるパーシャル・ブロック数(またはパーシャル・フレームバッファ・ブロックがディスプレイに収まる回数)をTouchGFX Generatorで設定できます。

    このパラメータは、フレームバッファ・ブロックに使用されるRAMの量に直接影響します。 ブロック数は2のべき乗(2、4、8など)にする必要があります。これにより、フレームバッファ・ブロックのサイズが、ディスプレイ・サイズ合計のそれぞれ1/2、1/4、1/8になります。

    フレームバッファの割り当て

    「パーシャル・バッファ - LTDC駆動ディスプレイ」フレームバッファ戦略を使用する場合、フレームバッファ割り当て戦略の意味合いが通常とは異なります。

    [by allocation]を選択した場合、TouchGFX Engineは物理的なパーシャル・フレームバッファ・ブロックに直接描画しますが、LTDCはGFXMMUのアドレスLUTを通して読み出します。

    [by address]を選択した場合は、GFXMMUの仮想バッファのいずれかのアドレスのみ指定可能で、TouchGFX Engineは物理的なフレームバッファ・ブロックに直接描画するのではなく、レンダリング時にGFXMMUの仮想バッファを通して描画します。

    Buffer Location - By allocation

    推奨されるフレームバッファ割り当て戦略は「by allocation」です。 この戦略では、TouchGFX Engineが物理的なパーシャル・フレームバッファ・ブロックに直接描画することができ、LTDCはGFXMMUのアドレスLUTを通して読み出します。

    Buffer Location - By address

    This option is only recommended on some specific platforms with limitations using RGB888 framebuffer format and GPU2D (NeoChrom) to accelerate rendering.

    Some MCU's using GPU2D (NeoChrom) to accelerate rendering do not support writing to a 24-bit RGB888 framebuffer. この場合は、GFXMMUを使用して、32ビットARGB8888フォーマットから物理フレームバッファ・ブロックのRGB888フォーマットに読み出し/書き込みされるデータを「パッキング」します。

    Further reading
    RGB888フレームバッファ・フォーマット使用の制限付きのマイクロコントローラについてはこの記事を参照

    これを可能にするには、ARGB8888フレームバッファ・フォーマットを使用するようにLTDCのピクセル・フォーマットをセットアップし、GFXMMU(GFXMMU_VIRTUAL_BUFFERX_BASE)の仮想バッファの1つをフレームバッファ・アドレスとして使用するようにする必要があります。 GFXMMUで設定したものと同じGFXMMUバッファ・アドレスを使用することが重要です。 以下に示すように、12バイトの「ブロック・サイズ」を使用するようにGFXMMUを設定し、バッファの「パッキング」を有効にします。

    これらのオプションはTouchGFX GeneratorのUIに反映されます。

    リンカ・スクリプト内で物理的な24ビット・フレームバッファのメモリ領域を正しいサイズ(ピクセルあたり3バイト)で定義し、この領域の開始アドレスを使用してGFXMMUの物理バッファ・アドレスを設定する必要があります。

    Note
    この設定でパフォーマンスが低下する可能性があります。TouchGFX Engineが物理的なフレームバッファ・ブロックに直接描画するのではなく、レンダリング時にGFXMMUの仮想バッファを通して描画するからです。

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

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

    シングル

    シングル・フレームバッファ戦略でLTDC駆動ディスプレイを使用すると、HALに以下のコードが生成され、TouchGFX Engineがディスプレイのリフレッシュ・サイクルに従ってレンダリング・プロセスを最適化できるようになります。

    TouchGFXGeneratedHAL.cpp
    uint16_t TouchGFXGeneratedHAL::getTFTCurrentLine()
    {
    // The CPSR register (bits 15:0) specify current line of TFT controller.
    uint16_t curr = (uint16_t)(LTDC->CPSR & LTDC_CPSR_CYPOS_Msk);
    uint16_t backPorchY = (uint16_t)(LTDC->BPCR & LTDC_BPCR_AVBP_Msk) + 1;

    // The semantics of the getTFTCurrentLine() function is to return a value
    // in the range of 0-totalheight. If we are still in back porch area, return 0.
    return (curr < backPorchY) ? 0 : (curr - backPorchY);
    }

    LTDC割り込みハンドラでは、LTDCフレームバッファのアドレスはスワップされないので、ディスプレイのリフレッシュ・サイクルが「アクティブ領域」を抜け出た時点(つまり、ディスプレイがフレームバッファの最後のラインを読み出した時点)で、TouchGFX Engineは現在のフレームのレンダリングを終了できます。

    リファレンス実装

    TouchGFX Board Setup STM32U5G9J Discovery Kit 2には、ダブル・フレームバッファ戦略のリファレンス実装が含まれています。 TouchGFX Generatorでこのフレームバッファ戦略をシングルに変更してコードを生成し、シングル・フレームバッファ戦略の使用例を確認します。

    ダブル

    ダブル・フレームバッファ戦略でLTDC駆動ディスプレイを使用すると、LTDC割り込みハンドラ内でLTDCフレームバッファのアドレスが別のフレームバッファにスワップされます。 これにより、TouchGFX EngineはLTDCフレームバッファ・アドレスのスワップ後すぐに次のフレームをレンダリングでき、この間にLTDCはもう一方のフレームバッファから現在のフレームを読み出します。

    リファレンス実装

    TouchGFX Board Setup STM32U5G9J Discovery Kit 2には、リファレンス実装が含まれています。

    パーシャル - LTDC駆動ディスプレイ

    パーシャル・フレームバッファ戦略でのLTDC駆動ディスプレイの使用は、シングル・フレームバッファ戦略の使用時とよく似ていますが、TouchGFX Engineはパーシャル・フレームバッファ・ブロックのみにレンダリングを行います。 同じフレームバッファ・ブロックがディスプレイの全部分のレンダリングに再利用されるので、レンダリング・プロセスを効率的に管理して、ティアリングや同期の失敗を防ぐことが重要です。 これを可能にするために、TouchGFX GeneratorはHALに以下のコードを生成して、ディスプレイの次の部分をレンダリングするタイミングをTouchGFX Engineに伝えるように、TouchGFX EngineがLTDCライン割り込みを設定できるようにします。

    TouchGFXGeneratedHAL.cpp
    void TouchGFXGeneratedHAL::waitForLTDCLines(uint16_t numberOfLines)
    {
    // The CPSR register (bits 15:0) specify current line of TFT controller.
    uint16_t curr = LTDC->CPSR & LTDC_CPSR_CYPOS_Msk;

    // The AWCR register (10:0) specify the accumulated active height.
    uint16_t max = (LTDC->AWCR & LTDC_AWCR_AAH_Msk) - 1;

    // Calculate the line at which to configure the interrupt.
    curr += numberOfLines;
    if (curr > max)
    {
    curr -= max;
    }

    // Configure line interrupt
    HAL_LTDC_ProgramLineEvent(&hltdc, curr);

    // Wait for VSync signal, which fires on the line interrupt that we just configured.
    OSWrappers::waitForVSync();
    }

    関数TouchGFXGeneratedHAL::waitForLTDCLines(uint16_t)は、TouchGFX Engineの描画ループから呼び出されます。 要求される具体的なライン数は、一連のパラメータによって決まります。 TouchGFX Generatorで設定される「パーシャル・ブロック数」に応じて、適切な一連のデフォルト値がこれらのパラメータに割り当てられます。

    同じフレームバッファ・ブロックがディスプレイの全部分のレンダリングに再利用されるので、通常はLTDCスキャンラインがアクティブ領域を抜け出たことを示すVSYNC信号が、TouchGFX Engineにディスプレイの次の部分のレンダリングを開始することを伝えるために使用されます。

    TouchGFXGeneratedHAL.cpp
    extern "C"
    {
    void HAL_LTDC_LineEventCallback(LTDC_HandleTypeDef* hltdc)
    {
    OSWrappers::signalVSync();
    }
    }

    リファレンス実装

    The TouchGFX Board Setup STM32H7S78 DK Emulated Framebuffer includes a reference implementation: