Skip to main content
Version: 4.16

Using Non-Memory Mapped Flash for Font Data

In this section we will discuss how to use a new font-layout that will allow you to put almost all font data into unmapped external flash. The effect is that you can have many thousand letters in an application using only 50 kb of flash.

Font Layouts#

TouchGFX supports two different font layouts for the fonts compiled into your application. The layout used is selected in TouchGFX Designer in the configurations tab:

Configurating font layout

The Mapped storage format is the default font layout and should be used on systems where fonts are stored in memory mapped flash (internal or e.g. external QSPI flash).

The Unmapped storage format is the new font layout. It allows most of the font data to be stored in unmapped flash. This will typically be a SPI-flash, but can be any type of storage.

Mapped Storage Format#

The mapped storage format keeps the font data in two tables.

The first table is an array of touchgfx::GlyphNode. These contain the properties of the individual characters: height, width, unicode, and similar.

generated/fonts/src/Table_verdana_20_4bpp.cpp
FONT_TABLE_LOCATION_FLASH_PRAGMA
KEEP extern const touchgfx::GlyphNode glyphs_verdana_20_4bpp[] FONT_TABLE_LOCATION_FLASH_ATTRIBUTE =
{
{ 0, 0x0020, 0, 0, 0, 0, 7, 0, 0, 0x00 },
{ 0, 0x002C, 5, 7, 3, 1, 7, 0, 2, 0x00 },
{ 21, 0x0030, 11, 14, 14, 1, 13, 0, 0, 0x00 },
{ 105, 0x0032, 11, 14, 14, 1, 13, 0, 0, 0x00 },
{ 189, 0x0033, 11, 14, 14, 1, 13, 0, 0, 0x00 },
{ 273, 0x0034, 12, 14, 14, 0, 13, 0, 0, 0x00 },
...
}

The second table (split in multiple files for large fonts) contains the pixel-patterns for the characters.

generated/fonts/src/Font_verdana_20_4bpp_0.cpp
FONT_GLYPH_LOCATION_FLASH_PRAGMA
KEEP extern const uint8_t unicodes_verdana_20_4bpp_0[] FONT_GLYPH_LOCATION_FLASH_ATTRIBUTE =
{
// Unicode: [0x0020]
// (Has no glyph data)
// Unicode: [0x002C]
0x00, 0x87, 0x04, 0x20, 0xFF, 0x03, 0x60, 0xBF, 0x00, 0xA0, 0x5F, 0x00, 0xE0, 0x0D, 0x00, 0xF3,
0x07, 0x00, 0xF6, 0x01, 0x00,
// Unicode: [0x0030]
0x00, 0xA3, 0xFE, 0x9D, 0x01, 0x00, 0x40, 0xFF, 0x9B, 0xFC, 0x1D, 0x00, 0xD0, 0x4F, 0x00, 0x80,
0x9F, 0x00, 0xF3, 0x0B, 0x00, 0x10, 0xEE, 0x00, 0xF7, 0x07, 0x00, 0x00, 0xFB, 0x03, 0xF9, 0x06,
...
}

The GlyphNodes will be used by the TouchGFX engine during text layout. The pixels will be read by the DMA2D or software routines during drawing.

On platforms using the normal LCD classes, e.g. LCD16Bpp or LCD24Bpp, these tables must be stored in internal flash or memory mapped external flash.

On platforms using a unmapped external flash, the LCD16BppSerialFlash can read the pixels-patterns from unmapped serial flash, but the GlyphNodes must be in internal flash.

Unmapped Storage Format#

The unmapped storage format splits the font data in three tables. The two tables from the mapped storage layout is reused, but a third table is added:

generated/fonts/src/Table_verdana_20_4bpp.cpp
FONT_SEARCHTABLE_LOCATION_FLASH_PRAGMA
KEEP extern const uint16_t unicodelist_verdana_20_4bpp[] FONT_SEARCHTABLE_LOCATION_FLASH_ATTRIBUTE =
{
0x0020,
0x002E,
0x003F,
0x004E,
0x0054,
....
}

This third table just contains the unicodes present in the font.

When this font layout is used, the third table must be present in internal flash, but the other two tables can be moved to external flash. This is a considerable saving, as the third table uses two bytes for each character, whereas the GlyphNode table uses 14 bytes. This reduces the storage requirement in internal flash.

When the font data is placed in unmapped flash, the mcu cannot access it directly. We therefore have to provide a flash reader object to the font subsystem.
The code for this is automatically generated by TouchGFXGenerator:

TouchGFXConfiguration.cpp
static TouchGFXDataReader dataReader;
static LCD16bppSerialFlash display(dataReader);
static ApplicationFontProvider fontProvider;
static Texts texts;
static TouchGFXHAL hal(dma, display, tc, 240, 320);
void touchgfx_init()
{
Bitmap::registerBitmapDatabase(BitmapDatabase::getInstance(), BitmapDatabase::getInstanceSize());
TypedText::registerTexts(&texts);
Texts::setLanguage(0);
hal.setDataReader(&dataReader);
fontProvider.setFlashReader(&dataReader);
...

If you are not using the generator, you must do this manually.

Remember to implement the functions in TouchGFXDataReader so data is actually read from your flash.

Example#

Below is a screenshot of an application using the new font layout:

Example application with 4000 Chinese characters

This application runs on a STM32G071 Nucleo board with a MB1642A display module:

Example application running on STM32G071Nucleo

In this application we have 4000 Chinese characters in size 20, 4 bits pr pixel. The application and data takes up 61Kb of 128 Kb available on the STM32G071. The font data is distributed as follows (excluding minor objects):

TableLocationSize
GlyphNodesExternal SPI flash57.372 bytes
Pixel patternsExternal SPI flash3.116.296 bytes
Unicode listInternal flash8.000 bytes

Linker Script Modifications#

To use the unmapped font layout correctly, you must update your linker script to place the tables correctly.

STM32F746.ld
define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
define symbol __ICFEDIT_region_ROM_end__ = 0x0801FFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x20008FFF;
define symbol __ICFEDIT_region_SERIAL_FLASH_start__ = 0x90000000;
define symbol __ICFEDIT_region_SERIAL_FLASH_end__ = 0x91000000;
place in ROM_region { readonly };
place in RAM_region { readwrite,
block CSTACK, block HEAP };
place in SERIAL_FLASH_region {section ExtFlashSection, section FontFlashSection };

In this linker script we put both the ExtFlashSection (images and font pixels) and FontFlashSection (the GlyphNodes) in the external flash. Any other read-only data is in the internal flash (ROM_region).