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

画像とフォント用にシリアルFlashの使用

このセクションでは、シリアルFlash(またはその他の非マップド・ストレージ)を使用して画像とフォントを保存する方法について説明します。 ここで説明する手法は、STM32G0や、その他のRAM搭載量が極めて少ないデバイスで特に役立ちます。

シリアルFlashと一緒によく使用されるパーシャル・フレームバッファの概要については、パーシャル・フレームバッファによるメモリ使用量の軽減を参照してください。 また、非マップドFlashからRAMにビットマップをキャッシュする方法の概要について、画像保存のための非メモリ・マップドFlashの使用も参照してください。

設定

TouchGFXアプリケーションでシリアルFlashを使用するには、TouchGFX Generatorの設定を変更し、"Additional Features"の中にある"External Data Reader"を有効化する必要があります。

Additional FeaturesのData Reader

この機能を有効にすると、TouchGFX Generatorの設定が変更され、LCD16bppSerialFlash LCDクラスを使用するようになります。 さらに、touchgfx::FlashDataReaderのサブクラスも生成されます。

TouchGFXConfiguration.cpp
static TouchGFXDataReader dataReader;
static LCD16bppSerialFlash display(dataReader);
static ApplicationFontProvider fontProvider;
...
void touchgfx_init()
{
...
hal.setDataReader(&dataReader);
fontProvider.setFlashReader(&dataReader);
...
}

このコードによって、TouchGFXDataReaderクラスのインスタンスが作成され、そのインスタンスがdisplayオブジェクト、HALオブジェクト、ApplicationFontProviderオブジェクトに渡されます。 この3つのオブジェクトは、dataReaderオブジェクトを使用して、シリアルFlash内のデータにアクセスします。 そのデータは画像またはフォント・データの場合があります。

システム・プログラマは、実際にFlashからデータを読み取るために、TouchGFXDataReaderクラスの実装を完了させる必要があります。

実装

TouchGFXDataReaderクラスは、touchgfx::FlashDataReaderインタフェースを実装します。 このインタフェースには次の4つのメソッドがあり、それぞれを特定のハードウェアに実装する必要があります。

include/touchgfx/hal/FlashDataReader.hpp
    bool addressIsAddressable(const void* address)
void copyData(const void* src, void* dst, uint32_t bytes)
void startFlashLineRead(const void* src, uint32_t bytes)
const uint8_t* waitFlashReadComplete()

addressIsAddressableメソッドはLCD16bppSerialFlashクラスによって使用され、データを直接読み取ることができるのか(すなわち、内部RAMまたは内部Flash内にあるのか)、あるいはdataReaderオブジェクト経由で読み取る必要があるのかを決定します。

copyData*メソッドは、データをFlashからRAMへ同期的にコピーするために使用されます。 この機能は一般的に、それ以上のデータ処理を行わない場合に使用されます。 たとえば、 塗りつぶし画像をフレームバッファにコピーする場合などです。

startFlashLineReadメソッドは、Flashから複数行のデータを必要とする場合に使用されます。 startFlashLineReadメソッドはデータの読み取りを始動します。 このメソッドは非同期的な読み取りを始動し、読み取り開始後にすぐに戻る必要があります。 waitFlashReadCompleteメソッドは、読み取りの終了を待ち、データを保存するバッファにポインタを返す必要があります。

LCD16bppSerialFlashは、(一部の状況で)前に読み取ったデータの処理中に、1つのFlash読み取り命令を発行できます。 つまり、完全な同時処理を行うには、dataReader内に少なくとも2つのバッファが必要になります。

TouchGFX Generatorは、FlashDataReaderを、TouchGFXGeneratedDataReaderTouchGFXDataReaderの2つのクラスに生成します。 2つのうちTouchGFXGeneratedDataReaderの方がスーパークラスで、デフォルトで実装されます。 その実装が適さない場合、アプリケーション・プログラマはTouchGFXDataReaderクラス内で仮想関数の実装を変更できます。

TouchGFXGeneratedDataReaderが実装されると、それが動作するためにC関数を呼び出します。 これらのアプリケーションは、システム・プログラマが実装します。

TouchGFX/target/generated/TouchGFXGeneratedDataReader.cpp
extern "C" __weak void DataReader_WaitForReceiveDone();
extern "C" __weak void DataReader_ReadData(uint32_t address24, uint8_t* buffer, uint32_t length);
extern "C" __weak void DataReader_StartDMAReadData(uint32_t address24, uint8_t* buffer, uint32_t length);

void TouchGFXGeneratedDataReader::startFlashLineRead(const void* src, uint32_t bytes)
{
/* Start transfer using DMA */
DataReader_StartDMAReadData((uint32_t)src, (readToBuffer1 ? buffer1 : buffer2), bytes);
}

この実装は、MB1642BDataReader.cファイルにあります。

Core/Src/MB1642BDataReader.c
void DataReader_StartDMAReadData(uint32_t address24, uint8_t* buffer, uint32_t length)
{
readDataDMA(address24, buffer, length);
}

void readDataDMA(uint32_t address24, uint8_t* buffer, uint32_t length)
{
// Pull Flash CS pin low
isReceivingData = 1;
FLASH_CS_GPIO_Port->BRR = FLASH_CS_Pin;

*((__IO uint8_t*)&hspi2.Instance->DR) = CMD_READ;

...
}

この実装は、Flashで使用されるプロトコルと、SPIやCS用に使用されるGPIOに特化したものです。 機能させるためには、3つのC関数のすべてをTouchGFXGeneratedDataReaderクラス向けに実装する必要があります。

画像

概要で触れたように、LCD16bppSerialFlashクラスは、dataReaderオブジェクト経由で画像ピクセルを読み取ることができます。 これを機能させるには、リンカ・スクリプトを変更して、内部Flash範囲外のアドレス範囲に画像を配置する必要があります。

STM32G071では、シリアルFlashの開始アドレスとして、0x90000000というアドレスを選択済みです。

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

/* Sections */
SECTIONS
{
...

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

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

これにより、ExtFlashSectionFontFlashSectionが、0x90000000アドレス範囲内に配置されます。

残っているタスクは、フラッシャ・ツールを使用して外部Flashにデータを書き込むことです。

STM32CubeProgrammer用のFlashローダの作成方法については、次のドキュメントのセクション2.3.3を参照してください。 UM2237 STMCubeProgrammerユーザマニュアル

フォント・データ

上記のリンカ・スクリプトでは、フォントのピクセル・データとフォント・キャラクタのメタデータ(幅と高さ)が外部Flashに配置されます(どちらのタイプのデータもFontFlashSection内にあります)。 このデータも、画面上に文字を描画するときにdataReaderオブジェクト経由で読み込まれます。

"Unmapped Storage Format"を使用しない場合は、リンカ・スクリプトとinclude/touchgfx/hal/Config.hppファイルを変更して、フォント・キャラクタのメタデータを内部Flashに移動する必要があります。

フォント・フォーマットの詳細については、非マップド・ストレージ内のフォントに関する記事を参照してください。