チュートリアル7: TSDノブ・ディスプレイ向けアプリケーションの作成
このチュートリアルでは、TSD TSS013004A-ADディスプレイ・ノブ・モジュール用のアプリケーションを作成して書き込みます。 これは、STM32C091 + 8MB外部Flashをベースとする1.3インチ円形ディスプレイ・モジュールを使用したエントリレベルのグラフィックスで、パーシャル・フレームバッファで実行されます。 このアプリケーションは簡単なGUIを備えており、ディスプレイ・モジュール(物理コントロール、周辺光、UART通信)のインタフェースの使用方法を表示します。 TSD TSS013004A-ADディスプレイ・ノブ・モジュールのマイコン・プラットフォームの仕様は以下のとおりです。
- 48MHz CPU(STM32C091)
- 36KB内蔵SRAM
- 256KB内蔵Flash
- 8MB外部シリアルFlash
- 24MHz SPIディスプレイ・インタフェース
このチュートリアルの内容を理解するための前提条件として、チュートリアル1とチュートリアル2を学習することをお勧めします。
ステップ1: TouchGFXプロジェクトの開始
TouchGFX Designerでは、ディスプレイ・モジュール用のアプリケーション・テンプレート(TBS)が提供されており、それを使用してすべての基本機能をセットアップします。 以下に基づいて新しいプロジェクトを作成します。
- [Create]タブで、"TSDHD TSS013-1"という名前のボードを選択します。
- [Application Name]を設定します(例: KnobApplication)。
- [Create]をクリックします。
ステップ2: 基本的なGUIの構築
プロジェクトを作成すると、240x240ピクセルの空白のキャンバスが表示されます。 このステップでは、アプリケーション用のGUIをデザインします。 次に示すような1つのスクリーン(Screen1)を作成します。
このスクリーン用の画像アセットはこのリンクからダウンロードできます。 このファイルを、自分のプロジェクト内のTouchGFX/assets/imagesフォルダに解凍します。 GUIを作成するには、次の表に従って、TouchGFX Designerにウィジェットを追加して設定します。
| 順序 | ウィジェット | 名前 | プロパティ |
|---|---|---|---|
| 1 | Image | backgroundImage |
|
| 2 | CircleProgress | valueCircleProgress |
|
| 3 | Image | wifiImage |
|
| 4 | Image | alarmImage |
|
| 5 | Image | unlockedImage |
|
| 6 | Image | lockedImage |
|
ステップ3: ディスプレイに対するアプリケーションのプログラミング
次に、ディスプレイ上にGUIを表示するために、ディスプレイ・モジュールに対する予備的なアプリケーションをプログラムします。 STマイクロエレクトロニクスが作成したすべてのDiscovery KitとNUCLEOボードにはST-LINKハードウェアが搭載されており、通常はこれを使用して、こうしたアプリケーションをプログラムします。 しかし、このサードパーティのディスプレイ・モジュールにはST-LINKが組み込まれていません。 その代わりに、以下の2つの代替方法を使用してプログラムできます。
UARTを使用するプログラミング
このディスプレイ・モジュールのアダプタ・ボードにはUSB-to-UARTチップが搭載されており、これによってPCとディスプレイ・モジュール内のマイクロコントローラとの通信が可能になります。 マイコン・ブートローダのUARTインタフェースを利用して、この方法でディスプレイ・モジュールをプログラムすることもできます。 この方法は、TouchGFX Designerで[Run target]をクリックしたときに、このプロジェクトのmakefileによって使用されます。 このプロジェクトの"Run target"スクリプトが機能するには、以下の要件があります。
- ディスプレイ・モジュールがデータUSBケーブル経由でPCに接続されていること。
- STM32CubeProgrammer(v2.18.0以降)がデフォルトの場所にインストール済みであること。
- USB-to-UARTのドライバがインストール済みであること。 ここからダウンロード可能: https://www.wch-ic.com/downloads/ch341ser_exe.html
- マイクロコントローラのnBOOT_SELオプションバイトがFALSEに設定されていること。 これは配布されたモジュールのデフォルトです。
[Run target]をクリックし、コンパイルとプログラミングが完了するまで待つと、DesignerキャンバスのGUIがモジュール・ディスプレイに表示されます。
Tip
Further reading
- マイクロコントローラのRESETおよびBOOT0ピンを制御して、マイクロコントローラを再起動し、内蔵ブートローダを実行します。
- マイクロコントローラのRAM(ST OpenBootloaderに基づく)にカスタム・ブートローダをプログラムして実行し、外部Flashをプログラムできるようにします。
- マイクロコントローラの内部Flashと外部FlashにTouchGFXアプリケーションをプログラムします。
- マイクロコントローラのRESETピンを制御し、マイクロコントローラを再起動してTouchGFXアプリケーションを実行します。
外部ST-LINKを使用するプログラミング
モジュールのもう1つのプログラム方法では、ディスプレイ・モジュールのアダプタ・ボード上のピンに有線接続されている外部デバッガを使用します。 ST-LINK/V2デバッガを使用する際には、以下の表に示すような有線接続が必要です。
| ST-LINK/V2、20ピン・コネクタ | ノブ・アダプタ・ボード |
|---|---|
| 1 | 5V |
| 4 | GND |
| 7 | SWD |
| 9 | SWC |
ST-LINKとSTM32CubeProgrammerを使用して外部Flashも書き込むことができるように、プロジェクトのLoading/TSDHD-TSS013-1.stldrに外部ローダ・ファイルが提供されています。 ST-LINKを使用する利点の1つは、プログラミングに加えて、(STM32CubeIDEなどを使用して)実行しているアプリケーションのデバッグも可能になることです。
外部ST-LINKはこのチュートリアルでは必須ではありません。
ステップ4: 物理入力へのインタラクションの追加
ディスプレイ・ノブ・モジュールには3つの物理的なユーザ入力メカニズム(左回し、右回し、押下)が存在します。 このステップでは、ノブを回したときにGUIのCircleProgressの値が変更され、ノブを押したときに画面のロックがオン/オフされるようにします。
TouchGFX/target/KeySampler.cppにあるコードはハードウェア入力を読み出し、さまざまなキーIDにマッピングします。 これらを使用して、以下に示すようなTouchGFX Designerのハードウェア・ボタン・インタラクションをトリガできます。
次の表に従い、入力ごとに1つのインタラクションを追加します。
| インタラクション | プロパティ |
|---|---|
| Knob_Turn_Left |
|
| Knob_Turn_Right |
|
| Knob_Press |
|
TouchGFX Designerでインタラクションを追加してコードを生成すると、TouchGFX/generated/gui_generated/src/screen1_screen/Screen1ViewBase.cppに、指定された仮想関数を呼び出すコードが生成されます。 目的の機能を実装するには、これら(およびヘルパ関数)を自分のユーザ・コードのスクリーン・クラスのヘッダ・ファイルに追加する必要があります。
TouchGFX/gui/include/gui/screen1_screen/Screen1View.hpp
public:
...
virtual void toggleLock();
virtual void decrementValue();
virtual void incrementValue();
void changeValue(int change);
次に、これらをユーザ・コード・スクリーン・クラスのソース・ファイルに実装します。
TouchGFX/gui/src/screen1_screen/Screen1View.cpp
void Screen1View::toggleLock()
{
lockedImage.setVisible(!lockedImage.isVisible());
lockedImage.invalidate();
}
void Screen1View::decrementValue()
{
if (!lockedImage.isVisible())
{
changeValue(-5);
}
}
void Screen1View::incrementValue()
{
if (!lockedImage.isVisible())
{
changeValue(5);
}
}
void Screen1View::changeValue(int change)
{
const int newValue = valueCircleProgress.getValue() + change;
valueCircleProgress.updateValue(newValue, 0);
}
更新されたアプリケーションでディスプレイ・モジュールをプログラムできるようになりました。 これで、ノブを押してGUIをロック解除し、その後にノブを回してCircleProgressの値を変更できます。
Tip
ステップ5: LED周辺光の制御
ディスプレイ・ノブ・モジュールには赤色LED、緑色LED、青色LEDのリングがあり、これらをオンにして周辺光として照らすことができます。 各カラー・チャネルはマイクロコントローラからのPWM対応出力で制御されます。 ここで使用するアプリケーション・テンプレートでは、この照明を制御する機能がCore/Inc/knob_interface.cppに実装されており、Core/Src/knob_interface.hppを介して入手できます。
Core/Src/knob_interface.hpp
public:
...
void knobSetAmbientLightRGB(uint8_t red, uint8_t green, uint8_t blue);
...
このデモでは、CircleProgressの値に基づいて照明の色を制御します。 値がゼロのときの照明は青色で、値が大きくなるにつれて徐々に紫色から赤色へと変化していくように制御します。 そのためには、Screen1Viewに以下のコードを追加します。
TouchGFX/gui/src/screen1_screen/Screen1View.cpp
#include <gui/screen1_screen/Screen1View.hpp>
#ifndef SIMULATOR
#include "knob_interface.hpp"
#endif
void Screen1View::setupScreen()
{
Screen1ViewBase::setupScreen();
changeValue(0); // Ensure that the system state is synchronized at start-up
}
void Screen1View::changeValue(int change)
{
const int newValue = valueCircleProgress.getValue() + change;
valueCircleProgress.updateValue(newValue, 0);
#ifndef SIMULATOR
const int value = valueCircleProgress.getValue(); // Always inside the range set in TouchGFX Designer (0-100)
//Update ambient light
const uint8_t red = (value * 255) / 100;
const uint8_t green = 0;
const uint8_t blue = 255 - red;
knobSetAmbientLightRGB(red, green, blue);
#endif
}
ディスプレイ・モジュールでこのアプリケーションを実行すると、ノブをロック解除して回したときに、周辺光が有効になり色が変更されます。
Tip
ステップ6: UARTでのデータ送信
ノブ・ディスプレイ・モジュールにはUART通信インタフェースがあり、コネクタ・ケーブルを介して6つのGPIO(PA0-5)を外部使用できます。 このステップでは、CircleProgressの値が更新されるたびに、アプリケーションがUART上でASCII文字列を送信するようにします。 UARTインタフェースはディスプレイ・モジュールのテンプレート・プロジェクト内で設定され、Core/Src/knob_interface.hppを通じて使用できます。
Core/Src/knob_interface.hpp
public:
...
void knobUartSendByte(uint8_t data);
void knobUartSendBytes(uint8_t* data, uint16_t size);
void knobUartSendString(uint8_t* data);
...
ここでは、knobUartSendByte関数を複数回使用して、値を表す文字列のさまざまなASCII文字を送信します。
TouchGFX/gui/src/screen1_screen/Screen1View.cpp
void Screen1View::changeValue(int change)
{
const int newValue = valueCircleProgress.getValue() + change;
valueCircleProgress.updateValue(newValue, 0);
#ifndef SIMULATOR
const int value = valueCircleProgress.getValue(); // Always inside the range set in TouchGFX Designer (0-100)
//Update ambient light
const uint8_t red = (value * 255) / 100;
const uint8_t green = 0;
const uint8_t blue = 255 - red;
knobSetAmbientLightRGB(red, green, blue);
// Send new value on UART
knobUartSendByte('0' + value / 100);
knobUartSendByte('0' + (value % 100) / 10);
knobUartSendByte('0' + value % 10);
knobUartSendByte('\r');
knobUartSendByte('\n');
#endif
}
ディスプレイ・モジュールでこのアプリケーションを実行すると、ノブをロック解除して回したときにUART上でデータが送信されるようになります。 このUARTデータは、UARTプログラミングで使用するものと同じインタフェースを介してPC上で受信できます。 そのためには、PC上にターミナル・アプリケーション(Tera TermやPuTTYなど)をインストールする必要があります。 例として、Tera Termで必要なインタフェース設定を示します。
PC上のターミナル・アプリケーションに接続した後、ノブを回すと値の文字列の受信と表示が開始されます。
ステップ7: UARTからのデータ受信
このステップでは、PCからUARTコマンドを受信したときに、以下の簡単なプロトコルに従ってアプリケーションが反応するようにします。
| コマンド | アクション |
|---|---|
| 'q' | wifiアイコンを非表示にする |
| 'w' | wifiアイコンを表示する |
| 'e' | アラーム・アイコンを非表示にする |
| 'r' | アラーム・アイコンを表示する |
Core/Src/knob_interface.hppには、プロジェクト・テンプレートで使用可能なUARTデータを受信するための関数が含まれています。
Core/Src/knob_interface.hpp
public:
...
uint8_t knobUartReceiveByte(uint8_t* data);
...
新しいデータを受信し、実際のバイトを指定のポインタにコピーすると、この関数はtrueを返します。 この関数を使用して、ToucHGFXアプリケーションのティックごとにUART受信バッファをポーリングします。 そのためには、ティックごとにメソッドを呼び出すためのTouchGFXインタラクションを追加する必要があります。
| インタラクション | プロパティ |
|---|---|
| Poll UART communication |
|
次に以下のコードを追加することで、UARTを読み出し、上記のプロトコルを実装します。
TouchGFX/gui/include/gui/screen1_screen/Screen1View.hpp
public:
...
virtual void toggleLock();
virtual void decrementValue();
virtual void incrementValue();
void changeValue(int change);
virtual void receiveUartCommand();
TouchGFX/gui/src/screen1_screen/Screen1View.cpp
void Screen1View::receiveUartCommand()
{
#ifndef SIMULATOR
uint8_t data;
if (knobUartReceiveByte(&data))
{
switch (data)
{
case 'q':
wifiImage.setVisible(false);
wifiImage.invalidate();
break;
case 'w':
wifiImage.setVisible(true);
wifiImage.invalidate();
break;
case 'e':
alarmImage.setVisible(false);
alarmImage.invalidate();
break;
case 'r':
alarmImage.setVisible(true);
alarmImage.invalidate();
break;
}
}
#endif
}
更新されたアプリケーションを実行すると、上の表に示したプロトコルに従って、ディスプレイ上で2つのアイコンを表示/非表示にできるようになります。 これは前のステップで使用したターミナル・プログラムによってテストできます。 ここでは、接続されたターミナル・プログラムのウィンドウを選択し、キーボード上でq、w、e、rキーをクリックすることで、簡単にコマンドを送信できます。
これでチュートリアル7は終了です。




