画像とフォント用にシリアルFlashの使用
このセクションでは、シリアルFlash(またはその他の非マップド・ストレージ)を使用して画像とフォントを保存する方法について説明します。 ここで説明する手法は、STM32G0や、その他のRAM搭載量が極めて少ないデバイスで特に役立ちます。
シリアルFlashと一緒によく使用されるパーシャル・フレームバッファの概要については、パーシャル・フレームバッファによるメモリ使用量の軽減を参照してください。 また、非マップドFlashからRAMにビットマップをキャッシュする方法の概要について、画像保存のための非メモリ・マップドFlashの使用も参照してください。
設定
TouchGFXアプリケーションでシリアルFlashを使用するには、TouchGFX Generatorの設定を変更し、"Additional Features"の中にある"External 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
を、TouchGFXGeneratedDataReader
とTouchGFXDataReader
の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
}
これにより、ExtFlashSection
とFontFlashSection
が、0x90000000アドレス範囲内に配置されます。
残っているタスクは、フラッシャ・ツールを使用して外部Flashにデータを書き込むことです。
STM32CubeProgrammer用のFlashローダの作成方法については、次のドキュメントのセクション2.3.3を参照してください。 UM2237 STMCubeProgrammerユーザマニュアル
フォント・データ
上記のリンカ・スクリプトでは、フォントのピクセル・データとフォント・キャラクタのメタデータ(幅と高さ)が外部Flashに配置されます(どちらのタイプのデータもFontFlashSection内にあります)。 このデータも、画面上に文字を描画するときにdataReaderオブジェクト経由で読み込まれます。
"Unmapped Storage Format"を使用しない場合は、リンカ・スクリプトとinclude/touchgfx/hal/Config.hpp
ファイルを変更して、フォント・キャラクタのメタデータを内部Flashに移動する必要があります。
フォント・フォーマットの詳細については、非マップド・ストレージ内のフォントに関する記事を参照してください。