使用串列快閃記憶體存儲圖像和字體
本節將討論如何使用串列快閃記憶體(或其他未映射記憶體)來存儲圖像和字體。 這裡介紹的技術在STM32G0和其他配備極小RAM的設備上特別有用。
有關部分影像緩衝區(通常與串列快閃記憶體一起使用)的介紹,請參閱文章“使用部分影像緩衝區降低記憶體使用”。 另請參閱文章使用非記憶體映射存儲圖像,瞭解如何將點陣圖從未映射Flash快取到RAM。
配置
為了讓TouchGFX應用使用串列快閃記憶體,您必須更改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
類的實例,並將該實例傳遞給顯示器物件、HAL物件和ApplicationFontProvider物件。 這三個物件將使用dataReader物件訪問串列快閃記憶體中的資料。 這些資料可以是圖像和字體資料。
系統程式師必須完成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()
LCD16bppSerialFlash
類使用addressIsAddressable
法來決定某些資料是否可以直接讀取(即位於內部RAM或內部快閃記憶體中)或是否應通過dataReader物件讀取。
copyData
*法用於從快閃記憶體同步複製資料到RAM。 當不對資料進行進一步處理時,常使用此函數。 如 將立體影像複製到影像緩衝時。
當需要從快閃記憶體獲取多行資料時,使用startFlashLineRead
法。 startFlashLineRead
法開始資料讀取。 此方法可以開始非同步讀取,並且應在開始讀取後立即返回。 waitFlashReadComplete法應等待讀取完成,並返回指向保存資料的緩衝區的指標。
LCD16bppSerialFlash
可以在處理之前讀取的資料時發起一次快閃記憶體讀取(在某些情況下)。 這意味著dataReader中需要至少兩個緩衝區來實現。
TouchGFX Generator生成分別屬於兩個類的FlashDataReader
:TouchGFXGeneratedDataReader
和TouchGFXDataReader
。 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;
...
}
此實現特定於快閃記憶體使用的協議以及SPI和CS使用的GPIO。 必須實現TouchGFXGeneratedDataReader
類的全部三個C函數才能發揮作用。
圖像
如簡介中所述,LCD16bppSerialFlash
類可通過dataReader物件讀取圖像像素。 為此,必須更改連結器腳本,以便將圖像的地址放在內部快閃記憶體範圍之外。
在STM32G071上,我們選擇了位址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地址範圍。
剩餘的任務是用Flasher工具將資料寫入外部快閃記憶體。
關於STM32CubeProgrammer的寫入快閃記憶體載入器的簡要說明,可以在以下文檔的第2.3.3節中找到:UM2237 STMCubeProgrammer用戶手冊
字體資料
以上連結器腳本將字體像素資料和字體字元的中繼資料(寬和高)放入外部快閃記憶體(兩類資料都在FontFlashSection中)。 在螢幕上繪製字元時,也通過dataReader物件讀取此資料
如果您未使用“未映射存儲格式”,則必須更改連結器腳本和檔案include/touchgfx/hal/Config.hpp
,以便將字體字元中繼資料移動到內部快閃記憶體。
參見未映射存儲中的字體一文獲取關於字體格式的更多資訊。