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

低コスト・ハードウェア上のTouchGFX

このセクションでは、RAMやFlashの搭載量が制限され、アクセラレーション機能がなく、外部FlashやディスプレイへのSPI接続が低速である低コスト・ハードウェア上でTouchGFXを使用する方法について説明します。

また、与えられたハードウェアで最適なアプリケーションを作成するための、いくつかアドバイスを提示したいと思います。

このセクションを通して、ハードウェア例として、X-Nucleo-GFX01M1拡張ボード付きSTM32G071 Nucleoボード向けのTouchGFXボード設定を使用します。 この拡張ボードには16ビット・ディスプレイとシリアルFlashが搭載されています。

X-Nucleo-GFX01M1拡張ボード付きのNucleo-G071RB

ハードウェアの概要

このキットのハードウェア構成は、STM32G071マイクロコントローラ、SPI NOR Flash、SPIディスプレイ、ジョイスティック・ボタンから成り立っています。

コンポーネント 
マイクロコントローラSTM32G071RB
マイクロコントローラ内蔵RAM32KB
マイクロコントローラ内蔵Flash128KB
ディスプレイDisplaytech DT022CTFT
ディスプレイ解像度240x320
ディスプレイ・フォーマット16ビットRGB565
ディスプレイ・コントローラILI9341V
ディスプレイ接続SPI
ディスプレイ接続速度32MHz
NOR FlashMacronix MX25L6433F
NOR Flashサイズ64Mbit
NOR Flash接続速度32MHz

ディスプレイはSPI1ペリフェラルに、FlashはSPI2ペリフェラルに接続されています。 これにより、マイクロコントローラはデータをディスプレイに転送中に、Flashからデータを読み込むことができます。

X-Nucleo-GFX01M1を接続したNucleo-G071RBの構成

GPIO割り当て

信号GPIOピン
ディスプレイCSPB5
ディスプレイDCXPB3
ディスプレイSCKPA5
ディスプレイMOSIPA7
ディスプレイTEPA0
Flash CSPB9
Flash SCKPB13
Flash MOSIPC3
Flash MISOPC2

上のテーブルは、Flashおよびディスプレイへの信号のGPIO割り当てを示しています。 これらの信号は、オシロスコープまたはロジック・アナライザを使用してモニタできます。 これはパフォーマンスに関する問題などのデバッグ時に非常に役立ちます。

プロジェクトの開始

STM32G071RB Nucleo評価キットのプロジェクトは、TouchGFX Designerで簡単に開始できます。 "Create New"ボタンをクリックして、STM32G071 Nucleoを検索します。 このボード設定は、X-Nucleo-GFX01M1ディスプレイ・シールド付きのNucleo-G071RBキット用に特に開発されたものです。

Nucleo-G071RBの新しいプロジェクト

TouchGFXボード設定は、NOR Flash、ディスプレイ、ボタンをサポートします。 ディスプレイは縦向きと横向きの両方のモードで使用できます。

ディスプレイの向きは、TouchGFX DesignerのConfig -> Displayセクションで変更できます。

ディスプレイの向きを縦または横に選択

X-Nucleo-GFX01M1シールドのディスプレイは、元々は縦向き(幅より高さの方が長い)ですが、横向きでも簡単に使用できます。

ディスプレイの更新

上に示したディスプレイの解像度は240x320ピクセルです。 合計で76,800ピクセル(153,600バイト)です。 マイクロコントローラとディスプレイ間の接続はSPI、32MHzです。 これにより、4MB/秒(2Mピクセル/秒)の転送が可能になります。

ディスプレイのリフレッシュ・レートは76.1Hzで、これにより1フレームあたり13.14msのフレーム時間となります。

ディスプレイからのティアリング効果信号

つまり、次のフレーム用のデータ転送にかけられる時間は、長くて13ms程度ということです。 この時間内で、200万ピクセル/秒 / 76 fps = 26,280ピクセル/フレーム(または、フル・スクリーンの34%)を転送できます。 実際には、プロトコル・オーバーヘッドのために、SPIバス上でこの転送速度を維持することはできないので、フレーム全体の約30%以上を送信することは期待できません。

アプリケーションの更新がこのピクセル量を超える場合、ハードウェアはフレーム時間内に転送を完了できません。 その結果、ディスプレイには更新全体が完了する前に、更新中のフレームが表示されることになります。 このため、古いフレームと新しいフレームが混じった状態で表示される場合があります。

この現象は、一部のアニメーションではユーザにとって目立つものではありませんが、特定のアプリケーションでは受け入れがたいものとなります。

このためSTでは、更新のレベルを30%未満に抑えることを推奨しています。 たとえば、 フレームの更新を少しずつ行う方法です。

このことから、一般的にはアイテムの移動よりも画面上でアイテムを展開する方がうまくいきます。

ディスプレイからのティアリング効果信号

星を右側に移動する場合は、その星によってカバーされているすべてのピクセルを更新する必要があります。 星を展開する場合には、新しいピクセルのみを更新する必要があります。 前のフレームで更新されたピクセルは変更されずにそのまま残ります。

描画速度

ディスプレイへの転送は、最大32MHzで実行されます。

シリアルFlashはディスプレイと同じ転送速度で動作できます。 つまり、シリアルFlashには、ディスプレイに最大速度でビットを転送するための十分な速度があるということです。

これは、Flash内の画像のピクセル・フォーマットがRGB565である場合にのみ成り立ちます。 この場合は、Flashからの2バイトの読み取りが1ピクセルに相当し、ディスプレイ上でも2バイトになります。 Flash内のピクセル・フォーマットがARGB8888の場合、ディスプレイ上で1ピクセルを生成するにはFlashから2倍の量のデータを読み取る必要があり、シリアルFlashはディスプレイに追いつけなくなります。

この場合、ディスプレイにデータが連続的に転送されなくなり、1フレームでディスプレイの30%を完全に更新することが不可能となります。 可能な解決法の1つは、画像を内蔵Flashに移動することで、もう1つは当然ながらピクセル・フォーマットを変更することです。

その他のウィジェットはFlashの速度に縛られません。 たとえば、 色の付いた長方形を描画するボックス・ウィジェットがあります。 もちろんこのウィジェットは非常に高速で、ディスプレイの転送速度を大きく上回っています。 ラインやサークルなどのその他のウィジェットは、CPUリソースを非常に多く使用します。 これらのウィジェットでは、ディスプレイに転送可能な速度でピクセルを生成することができません。 これらのウィジェットを使用する場合、アプリケーションは、すべてのフレームでディスプレイの30%を更新することを期待できません。

ピクセルのレンダリングの複雑さについては、こちらをご覧ください。

シリアルFlash搭載のTouchGFXの制限事項

シリアルFlashを搭載したSTM32G0上のTouchGFXには、アプリケーション・プログラマが注意する必要のあるいくつかの制限事項があります。

テクスチャ・マッパー

テクスチャ・マッパー・ウィジェット(Texture Mapper、Animation Texture Mapper、Scalable Image)では、外部SPI Flashに保存される画像を描画できません。 シリアルFlashに保存されている画像を使用した画像回転などでは、許容可能な性能を得ることができないからです。

テクスチャ・マッパーで画像を使用するには、その画像を内蔵FlashまたはRAMに保存する必要があります。 TouchGFX Designerで画像設定を変更すれば、簡単に画像を内部Flashに保存できます。

Imagesタブに移動して、画像を選択します。 ウィンドウの右側で、"Section"属性を"IntFlashSection"に変更します。

画像を内蔵Flashに配置

テクスチャ・マッパー・コードは大きすぎるので、すべてのプロジェクトに含めることができません。 このため、STM32G0プロジェクトではデフォルトで無効化されています。 つまり、テクスチャ・マッパーをSTM32G0プロジェクトで使用するには、使用前に有効化する必要があります。

"Config"タブに移動して、"Framework Features"を選択し、関連するテクスチャ・マッパーまたはテクスチャ・マッパーのグループをクリックします。

特定の画像フォーマットに対してテクスチャ・マッパーを有効化

Bitmap Cacheを使用して、画像を一時的にRAMに移動することもできます。

ビットマップ・ペインタ

ライン、サークル、ダイナミック・グラフのウィジェットでは、画像に色付けできます。 ただし、SPI Flashにある画像ではこれはできません。 これらのウィジェットで使用する画像は、内蔵FlashまたはRAMに配置する必要があります。

L8パレット

L8フォーマットの画像をシリアルFlash搭載のハードウェアで使用できます。 ただし、パレット・データを内蔵Flashに配置する必要があるという制限があります(これも性能上の理由です)。

内臓Flashに格納する画像の追加のデータの位置を設定。

画像のパレットを内蔵Flashに移動するには、TouchGFX Designerで"Extra Section"を"IntFlashSection"に変更します([Images]タブを開いて、画像を見つけ、右端の列に移動します)。

ドライバ

TouchGFXボード設定はTouchGFX Generatorを使用して作成します。 Generatorの詳細については、こちらを参照してください。 TouchGFX GeneratorはHALレイヤを生成します。HALレイヤは、TouchGFXフレームワークを一連のローレベル・ドライバ(このTouchGFXボード設定ですでに実装済み)とリンクさせます。 このアプリケーション・テンプレートのローレベル・ドライバは、ユーザのプロジェクトのCore/Srcフォルダにあります。

ドライバは、次の3つのファイルの中にあります。

ドライバファイル
ディスプレイCore/Src/MB1642BDisplayDriver.c
FlashCore/Src/MB1642BDataReader.c
ボタンCore/Src/MB1642BButtonController.cpp

ディスプレイ

ディスプレイではごく標準的なSPIプロトコルが使用されます。 いくつかのレジスタは、ディスプレイを設定するために書き込むことが可能です。 データをディスプレイに転送するときに、チップ・セレクトがアサートされます。 その他のGPIOやDCXは、コマンド・バイトとデータ・バイトを区別するために使用されます。

ドライバはDMAチャネルを使用して、ディスプレイのピクセル・データを転送します。 これにより、マイクロコントローラがピクセルを計算中でも、データを転送することができます。 DMA完了の割込みを使用して、今後の描画での再利用のために伝送済みのメモリを開放したり、新しいデータがすでに用意されていれば転送を再開したりします。

設定データはDMAでは送られません。このディスプレイのプロトコルに応じて、小型パッケージ間(またはパッケージ内)でCSピンとCDXピンを切り替える必要があるからです。

ドライバは設定データの送信時には8bitモードでSPIを使用しますが、ピクセル・データの転送時には16bitモードに変更します。 これは、マイクロコントローラのメモリがリトル・エンディアン・モードで読み出されるからです。 RGB565フォーマットのピクセルは、最初に下位バイト(GおよびB)が、2番目に上位バイト(RおよびG)がRAMに保存されます。 この順序は、8bit SPIが転送のためにメモリを読み取るときにも保持されます。 SPIが16bitモードの場合、データはメモリから16bit RGB565として読み取られ、ディスプレイにとって正しい順序で転送されます。

16bit DMAを使用しないドライバは、転送前にピクセル内のバイトをスワップする必要があります。

初期化

ディスプレイの初期化は、MB1642BDisplayDriver_DisplayInit(void)という関数にあります。

ドライバは6つのコマンドをディスプレイに送信しますが、これは推奨されるパワー・オン・シーケンスに従っています。

  1. Sleep Mode(11h)を終了する
  2. Normal Mode(13h)に入る
  3. MXおよびBGRビットを使用して、Memory Access Control(36h)を設定する
  4. 16bitフォーマットで、Pixel Format(3Ah)を設定する
  5. Tearing Effect Line On(35h)
  6. ライン = 0で、Tear Scanline(44h)を設定する

これらのコマンドの間に、ドライバは100msスリープします。

ティアリング効果

ディスプレイからのティアリング効果(TE)信号は非常に重要です。 これにより、アプリケーションはディスプレイ・メモリの更新をディスプレイのリフレッシュ・レートと正確に同期することができます。 アプリケーションが、ディスプレイ上のティアリングを防止するのにも役立ちます。 ディスプレイは更新サイクルを開始すると、必ずこの信号をアサートします。 マイクロコントローラはこの信号を使用して、ディスプレイへのデータ転送を開始します。

TE信号は、マイクロコントローラの外部割込み入力に接続されています。 CubeMxは、このピン上に割込みを生成して設定します。

ドライバ内のコールバックが、TouchGFXに描画開始の信号を送ります。

MB1642BDisplayDriver.c
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
...
touchgfxSignalVSync();
}

外部Flash

ディスプレイ・シールド上のSPI NOR Flashは、標準のSPI Flashです。 このドライバはディスプレイ・ドライバよりシンプルです。 Flashからデータを読み取るために、特別な初期化の必要はありません。

ドライバはポーリングされたSPI(全バイトでビジー・ウェイト)を使用してデータを読み取るか、DMAを使用することができます。 DMAでデータ受信の開始までの時間は、ポーリング・モードで20バイトを読み取るためにかかる時間とほぼ同じなので、短いデータの読み取りではポーリングより遅くなることがよくあります。 一方、DMAは割込み中(sysTickまたはアプリケーション割込みなど)でも実行を続け、マイクロコントローラがピクセルの描画でビジー状態にあるときでも、バックグラウンドで実行可能です。 こうした理由から両方の方法が使用されます。

Flashドライバはディスプレイ・ドライバとは別のDMAチャネルを使用するので、新しいデータの受信とすでに描画済みのピクセルの転送を同時に実行できます。

リンカ・スクリプト

リンカによって、アプリケーション内のさまざまなデータの配置場所をコントロールします。 これはリンカ・スクリプトで指定します。 gccコンパイラ用のリンカ・スクリプトの最初の部分を以下に示します。

MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 36K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
SPI_FLASH (r) : ORIGIN = 0x90000000, LENGTH = 8M
}

ここでは、NOR Flashのアドレスが0x90000000から始まると宣言しています。 ターゲット・アプリケーションのFlashドライバは、SPI Flashから0x90000000アドレスにあるデータを読み出します(下位24ビットをFlash内のアドレスとして使用)。

STM32CubeProgrammerで使用される外部Flashローダは、この範囲のデータをSPI Flashに書き込むことができます(下記を参照)。

この次のセクションでは、SPI Flashに画像(ExtFlashSection)データとフォント(FontFlashSection)データを配置しています。

  ExtFlashSection :
{
*(ExtFlashSection ExtFlashSection.*)
*(.gnu.linkonce.r.*)
. = ALIGN(0x4);
} >SPI_FLASH

FontFlashSection :
{
*(FontFlashSection FontFlashSection.*)
*(.gnu.linkonce.r.*)
. = ALIGN(0x4);
} >SPI_FLASH

リンカ・スクリプトに同様のセクションを追加することで、その他のデータもSPI Flashに配置することができます。

Flashローダ

G071 TouchGFXボード設定には、STM32CubeProgrammer用のFlashローダが含まれています。 Flashローダは、SPI NOR Flashにデータを書き込むことができます。

このFlashローダは、gcc/S25FL032P_STM32G071B-NUCLEO.stldrというファイルにあります。

STM32CubeIDEプロジェクトはCubeIDEから直接書き込めますが、IARまたはKeilアプリケーションはSTM32CubeProgrammerを使用して書き込む必要があります。

FlashローダはSTM32CubeProgrammerで最初から使用することはできず、インストール場所にstldrファイルをコピーすることでインストールする必要があります。

STM32CubeProgrammerインストール場所へのFlashローダのコピー

これで通常どおりに、STM32CubeProgrammerでFlashローダを選択できるようになります。

STM32CubeProgrammerインストール場所へのFlashローダのコピー

Tip
このFlashローダは、Nucleo-G071RBボードで使用される特定のGPIO設定でのみ動作します。

シリアルFlash用の別のGPIO設定がカスタム・ハードウェア上で使用されている場合は、Flashローダを同じように変更する必要があります。

ボタン

ボタン・ドライバは非常にシンプルです。 ここでは、MB1642B上でジョイスティック用に使用される5つのGPIOと、Nucleoボード上の青色のユーザ・ボタンの状態を取得します。

このボタン・ドライバは、TouchGFXでBottonControllerとしてインストールされています。 つまり、ボタンの押下はTouchGFX Designerのインタラクション内で直接利用可能だということです。 以下のように、ユーザ・コード内で使用することもできます。

void Screen1View::handleKeyEvent(uint8_t key)
{
if (key == '6')
{
application().gotoScreen2Screen();
}
}

使用されるキー・コードは以下のとおりです。

キーコード
左(Left)'4'
右(Right)'6'
上(Up)'8'
下(Down)'2'
中央(Center)'5'
青色のユーザ・ボタン(Blue User Button)'0'

これらのキーは、キーボードのテンキーを使用してシミュレータを実行する(TouchGFX DesignerでF5キーを押す)場合にも使用できます。