跳轉到主要內容

使用非記憶體映射快閃記憶體存儲影像

本節將討論如何將所有圖像連結到可以放入非記憶體映射快閃記憶體的二進位檔案,以及如何在執行時間使用該檔和點陣圖緩存。 TouchGFX不能繪製存儲在非記憶體映射快閃記憶體中的點陣圖,但將點陣圖存在RAM的緩存中,就能在應用中使用點陣圖。

參見緩存點陣圖一文中關於點陣圖緩存的綜合討論。

在本文中,我們假設您設置了點陣圖緩存,並希望將點陣圖存儲在非記憶體映射快閃記憶體中。 該快閃記憶體可以是USB儲存裝置、NAND flash等。

目標是將圖像連結到特定位址,將圖像複製到檔案中,並幫助TouchGFX將其從檔案複製到緩存。

將快閃記憶體中的點陣圖資料複製到緩存

注意,在緩存點陣圖時,TouchGFX會將像素從原始位置複製到點陣圖緩存。

通過從HAL類呼叫此方法來完成這種複製:

HAL.hpp
bool HAL::blockCopy(void* RESTRICT dest, const void* RESTRICT src, uint32_t numBytes);

如果點陣圖存儲在普通可定址快閃記憶體(如內部快閃記憶體或記憶體映射外部快閃記憶體)中,則使用TouchGFX庫中提供的普通blockCopy函數即可,無需任何額外的操作。

另一方面,如果點陣圖存儲在不可定址的存儲位置(如檔案系統),則一般的操作是不夠的,您需要提供更新過的版本,以便能夠從特定快閃記憶體讀取。

但是,首先我們需要確保點陣圖已連結到固定位址。

BitmapDatabase表

TouchGFX中的所有點陣圖都生成到generated/images/src資料夾中的.cpp文件。 在這裡點陣圖表示為位元組陣列。

C++編譯器和編譯其他原始程式碼一樣編譯這些陣列,並且將它們連結到應用程式中。

這是一個簡單應用程式的螢幕截圖,該應用程式有一個按鈕和一個顯示旋轉標示的紋理映射器:

按鈕和紋理映射器

該應用使用3張圖像:Button_Pressed、Button_Released和Logo。

這3張點陣圖被轉換為.cpp檔,並作為應用程式的一部分進行連結。 在名為bitmap_database的表中引用點陣圖。 此表位於文件BitmapDatabase.cpp中。 下表來自上面的範例(刪減了一些細節):

BitmapDatabase.cpp
extern const unsigned char _blue_buttons_round_edge_small[];
extern const unsigned char _blue_buttons_round_edge_small_pressed[];
extern const unsigned char _blue_logo_touchgfx_logo[];

const touchgfx::Bitmap::BitmapData bitmap_database[] =
{
{ _blue_buttons_round_edge_small, ... },
{ _blue_buttons_round_edge_small_pressed, ... },
{ _blue_logo_touchgfx_logo, ... }
};

首先宣告的陣列是包含各點陣圖的像素的陣列。 這些陣列在其他.cpp檔中定義。 bitmap_database陣列保存了這些陣列的位址。 TouchGFX使用此陣列查找點陣圖像素的位址。

當開發者請求緩存點陣圖時,TouchGFX查找快閃記憶體中的點陣圖位址(在bitmap_database陣列中)並從這裡複製資料。

連結器腳本修改

連結器為點陣圖選擇位址。 此類選擇基於點陣圖所在的區段。 TouchGFX中的所有點陣圖默認放入ExtFlashSection中。

標準連結器腳本(此處是就GCC而言)將此分區連同其他唯讀資料一起放入快閃記憶體。

在本例中,我們將圖像資料放入ExtFlashSection中的地址0x24000000。 您可以選擇未使用過的任何位址(不是程式碼或資料位址空間的一部分)。

首先,除了普通的內部FLASH和RAM,我們定義一個新的存儲區(USB快閃記憶體位址0x24000000):

STM32F746.ld
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
USB(r) : ORIGIN = 0x24000000, LENGTH = 1M
}

然後,我們指示連結器將ExtFlashSection放入USB區:

STM32F746.ld
ExtFlashSection :
{
*(ExtFlashSection ExtFlashSection.*)
} >USB

在連結成功後,可通過檢查.map文件(application.map)來檢查點陣圖地址。 下面是application.map的一部分:

application.map
ExtFlashSection
0x24000000 0x23ec0
*(ExtFlashSection ExtFlashSection.*)
ExtFlashSection
0x24000000 0x10000 TouchGFX/build/.../Blue_Logo_touchgfx_logo.o
0x24000000 _blue_logo_touchgfx_logo
ExtFlashSection
0x24010000 0x9f60 TouchGFX/build/.../Blue_Buttons_Round_Edge_small.o
0x24010000 _blue_buttons_round_edge_small
ExtFlashSection
0x24019f60 0x9f60 TouchGFX/build/.../Blue_Buttons_Round_Edge_small_pressed.o
0x24019f60 _blue_buttons_round_edge_small_pressed

在這裡我們可以看到,圖像的總大小為0x23ec0 = 147,136位元組。 保存點陣圖的3個陣列的位址從0x24000000開始相繼排列。

現在,假設您想要將點陣圖資料傳輸到SD卡中。 我們可以用簡單的objcopy指令從.elf檔中提取點陣圖的二進位資料:

$ arm-none-eabi-objcopy.exe --dump-section ExtFlashSection=images.bin TouchGFX/build/bin/target.elf
$ ls -l images.bin
-rw-r--r-- 1 christef Administrators 147136 Feb 20 11:56 images.bin

這樣可以得到一個只包含圖像位元組陣列的檔(images.bin)。 此檔可以複製到USB快閃記憶體、SD卡甚至是快閃記憶體晶片。

現在的觀念是,當TouchGFX請求位址0x24000000以上的資料時,我們從SD卡上的images.bin檔獲取資料。

修改BlockCopy函數

記住,在將點陣圖緩存到RAM時,TouchGFX呼叫HAL::BlockCopy以獲取資料。

為了連結到SD卡上的資料,我們可以在特定HAL類中實現新的BlockCopy。 這裡我們假設類的名稱為TouchGFXHAL(由TouchGFX Generator生成):

TouchGFXHal.hpp
class TouchGFXHAL : public TouchGFXGeneratedHAL
{
public:
...
virtual bool blockCopy(void* RESTRICT dest, const void* RESTRICT src, uint32_t numBytes);
}
TouchGFXHal.cpp
// This function is called whenever a bitmap is cached. Must copy a number of bytes from the (non-memory-mapped) source
// to the cache.
bool TouchGFXHAL::blockCopy(void* RESTRICT dest, const void* RESTRICT src, uint32_t numBytes)
{
// If requested data is located within the memory block we have assigned for ExtFlashSection,
// provide an implementation for data copying.
if (src >= 0x24000000 && src < 0x24100000)
{
void* dataOffset = src - 0x24000000;
// In this example we assume graphics is placed in SD card, and that we have an appropriate function
// for copying data from there.
sdcard_read(dest, dataOffset, numBytes);
return true;
}
else
{
// For all other addresses, just use the default implementation.
// This is important, as blockCopy is also used for other things in the core framework.
return HAL::blockCopy(dest, src, numBytes);
}
}

現在,可以開始從SD卡緩存點陣圖。

如果TouchGFX嘗試繪製沒有緩存的點陣圖,它將嘗試從bitmap_database表中找到的位址讀取像素。 此地址將處於範圍0x24000000 - 0x24100000以內,讀取將導致異常。

將圖像連結到RAM

如果可用RAM足夠大,能夠存儲所有圖像(在上面的例子中,RAM大於147,136位元組),則無需使用點陣圖緩存來複製圖像。

方式如下:

  • 為圖像選擇RAM中的固定位址和範圍
  • 在連結器腳本中刪除RAM區中的範圍
  • 創建具有選定位址和大小的新區IMAGES
  • 將ExtFlashSection放在IMAGES區
  • 連結應用並檢查.map文件
  • 從application.elf創建images.bin文件
  • 在啟動TouchGFX之前,將整個images.bin檔從SD卡複製到RAM中的選定位址

該解決方案較為簡單,但有一些缺點:

  • 可用RAM必須足夠大,能夠保存所有圖像
  • 由於要從SD卡複製,因此啟動時間會比較長(百萬位元組可能需要數秒)