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を有効にした後、以下のパラメータを設定する必要があります。
- 接続するディスプレイの仕様に合わせたLTDCの設定(GPIOとタイミング)
- 目的とするTouchGFXアプリケーションの仕様に合わせたLTDCの設定
TouchGFX Generatorは、STM32CubeMXから各種設定を読み出し、[Dependencies]セクションに警告、推奨事項、またはエラーのリストを表示することができます。 下の画像は、STM32CubeMXでLTDCを初めて有効化するときに現れる依存関係のリストを示しています。
Note
パラメータとレイヤの設定
LTDCブロックで以下のパラメータを設定する必要があります。
依存関係 | 説明 |
---|---|
レイヤ数 | TouchGFXには、単一レイヤのみ使用可能です。 |
ウィンドウ位置 | デフォルトでは、LTDCレイヤのウィンドウの水平位置および垂直位置は0です。 ウィンドウの水平停止位置と垂直停止位置は、ディスプレイの寸法と同じに設定する必要があります。 |
アルファ定数は0です | デフォルトでは、LTDCレイヤのアルファ定数は0です。 アプリケーションでグローバル・アルファを常時使用しないかぎり、この値は0より大きく、可能ならば255としてください。 |
次の図は、警告を解消するようにLTDCを設定し、TouchGFX Generatorのインタフェースに[Dependencies]グループが表示されなくなった状態を示しています
Note
TouchGFXドライバ / VSYNC信号
ディスプレイ・インタフェースとして[Parallel RGB (LTDC)]を選択すると、開発者はLTDC Application Tick Driverにアクセスできるようになります。これにより、LTDC割り込みを使用してTouchGFX Engineのメイン・ループを駆動します。 これは、LTDCを使用する場合にTouchGFX Engineのメイン・ループを駆動するための推奨される方法です。
Note
次のコードは、ディスプレイの準備ができたときに、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
Caution
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
このオプションは、RGB888フレームバッファ・フォーマットとGPU2D(NeoChrome)を使用してレンダリングを加速させている、制限のある一部の特定のプラットフォーム上でのみ推奨されます。
GPU2D(NeoChrome)を使用してレンダリングを加速させる一部のマイクロコントローラは、24ビットRGB888フレームバッファへの書き込みをサポートしていません。 この場合は、GFXMMUを使用して、32ビットARGB8888フォーマットから物理フレームバッファ・ブロックのRGB888フォーマットに読み出し/書き込みされるデータを「パッキング」します。
Further reading
これを可能にするには、ARGB8888フレームバッファ・フォーマットを使用するようにLTDCのピクセル・フォーマットをセットアップし、GFXMMU(GFXMMU_VIRTUAL_BUFFERX_BASE)の仮想バッファの1つをフレームバッファ・アドレスとして使用するようにする必要があります。 GFXMMUで設定したものと同じGFXMMUバッファ・アドレスを使用することが重要です。 以下に示すように、12バイトの「ブロック・サイズ」を使用するようにGFXMMUを設定し、バッファの「パッキング」を有効にします。
これらのオプションはTouchGFX GeneratorのUIに反映されます。
リンカ・スクリプト内で物理的な24ビット・フレームバッファのメモリ領域を正しいサイズ(ピクセルあたり3バイト)で定義し、この領域の開始アドレスを使用してGFXMMUの物理バッファ・アドレスを設定する必要があります。
Note
サポートされるフレームバッファ戦略
- シングル
- ダブル
- パーシャル - LTDC駆動ディスプレイ
Further reading
シングル
シングル・フレームバッファ戦略で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();
}
}
リファレンス実装
TouchGFX Board Setup STM32H7S78 DKパーシャル・フレームバッファには、リファレンス実装が含まれています。