Field Notes
How to display custom fonts on 2.8 inch TFT display for Arduino?
To display custom fonts on a 2.8 inch TFT display for Arduino, you need to bypass the default bitmap fonts in the Adafruit GFX library and load external font files from a microSD card or program them directly into flash memory using the TFT_eSPI library. The most reliable method is to use the 2.8 inch tft display module for arduino with a 240x320 pixel resolution, which supports SPI communication at 5V logic levels. This module typically uses the ILI9341 or ST7789 driver chip, and you can drive it with the TFT_eSPI library, which handles custom fonts through the `setFont()` function. The key is to convert TrueType or OpenType fonts into a compressed format using the online tool "Font Converter" from the TFT_eSPI library, then store the resulting `.h` file in your Arduino sketch. The library supports up to 128 characters per font file, with variable width and height, allowing you to render text at any size without pixelation. For example, a 12-point font at 240x320 resolution uses about 2KB of RAM per character, so you must manage memory carefully—especially on an Arduino Uno with only 2KB of SRAM. If you run out of RAM, switch to an Arduino Mega (8KB SRAM) or ESP32 (520KB SRAM). The data transfer rate over SPI is typically 8-10 MHz, which means a full screen of custom text (like 20 lines of 30 characters) takes about 150-200 milliseconds to render, depending on font complexity. You can also use the `drawString()` function with custom fonts to position text precisely, and the `setTextDatum()` function to align text left, center, or right. For Chinese characters, you need a font file with Unicode support, which can be generated using the same converter but requires a larger memory footprint—a 16-point Chinese font with 2000 characters takes about 64KB of flash. The TFT_eSPI library also supports anti-aliasing for smoother edges, but this doubles the rendering time. To avoid flicker, use double buffering by writing to a buffer in RAM and then flushing it to the display with `pushImage()`. The buffer size for a 240x320 display at 16-bit color depth is 153,600 bytes (240*320*2), which is too large for most Arduinos, so you need to use a partial buffer—like a 240x20 pixel strip—which takes 9,600 bytes. This fits in an ESP32 but not an Uno, so plan your hardware accordingly. The SPI pins on the module are standard: CS (chip select) on pin 10, DC (data/command) on pin 9, RST (reset) on pin 8, MOSI on pin 11, MISO on pin 12, and SCK on pin 13 for an Uno. But you can remap them in the TFT_eSPI user setup file. The module's backlight is controlled by a separate pin (usually pin 6) with PWM for brightness control, consuming 20-30 mA at full brightness. The total power draw of the display is about 50-60 mA at 5V, which is fine for a USB-powered Arduino. For custom fonts, you must ensure the font file is in the correct format: the TFT_eSPI library uses a proprietary `.vlw` format, which is a compressed bitmap font with metadata. You can convert any TTF or OTF font to `.vlw` using the online tool at "tft-espi-font-converter" (search for it). The converter lets you select the font size, characters to include (like ASCII 32-126 for English), and whether to include anti-aliasing. The output is a `.h` file that you include in your sketch with `#include `. Then, in `setup()`, you call `tft.setFreeFont(&FontName)`. After that, any `tft.drawString()` call uses the custom font. For example, to display "Hello World" in 24-point Arial, you generate a 24-point Arial `.vlw` file, include it, and call `tft.drawString("Hello World", 10, 10)`. The text will be rendered at 24 points, which is about 32 pixels tall on a 240x320 display. If you need multiple font sizes, you generate separate files for each size. The library also supports proportional spacing, so characters like "i" take less width than "W". This is crucial for professional-looking UIs. One common issue is that the default font in the Adafruit GFX library is 5x7 pixels, which looks blocky on a 2.8-inch display. Custom fonts solve this by using smooth curves. For example, a 12-point font at 240x320 resolution has a character height of about 16 pixels, which is readable for data displays. For a dashboard, a 16-point font (22 pixels tall) works well for labels. The module's pixel density is about 100 DPI (240 pixels / 2.8 inches = 85.7 DPI, but the actual DPI depends on the display's physical size; the 2.8-inch diagonal means the width is about 2.2 inches, so 240/2.2 = 109 DPI). So a 12-point font at 109 DPI is about 12/72 * 109 = 18 pixels tall, which matches the typical rendering. To test custom fonts, you can use the TFT_eSPI example "Font_Demo" which loads a font from a file on an SD card. The SD card is connected via SPI, using the same pins as the display but with a separate CS pin (usually pin 4). The example reads a `.vlw` file from the SD card and renders it. This is useful if you want to change fonts without recompiling the sketch. But for production, it's better to embed the font in flash memory. The flash memory on an Arduino Uno is 32KB, so you can fit about 10-15 small font files (each 2-3KB) or one large Chinese font file. On an ESP32, you have 4MB of flash, so you can store dozens of fonts. The rendering speed also depends on the SPI clock speed. The module supports up to 20 MHz, but the Arduino Uno's SPI library limits to 8 MHz. You can increase it by using the TFT_eSPI library's `setSPIclock()` function, but you must ensure the wiring is short (under 10 cm) to avoid signal degradation. Use 10kΩ pull-up resistors on the CS lines to prevent floating. For the backlight, you can connect it to a PWM pin and use `analogWrite()` to dim it. The module's backlight is typically 3.3V logic, but the 5V module has a built-in regulator, so you can use a 5V PWM signal. The contrast ratio is about 500:1, and the viewing angle is 60 degrees in all directions. For outdoor use, the brightness is about 250 cd/m², which is readable in direct sunlight if you use a high brightness setting. The response time is 25 ms, so fast animations are possible. For custom fonts, you can also use the `drawCentreString()` function to center text horizontally, which is useful for titles. The library supports Unicode, so you can display emoji or special symbols if you include them in the font file. For example, to display a temperature symbol (°C), you include the degree symbol in the font conversion. The font file size for a 12-point font with 96 characters (ASCII 32-127) is about 2.5KB. For a 24-point font, it's about 8KB. The rendering time for a single character is about 0.5 ms at 8 MHz, so a 20-character string takes 10 ms. The `drawString()` function also handles line breaks automatically if you use `\n`. For multi-line text, you can use `setCursor()` and `println()` with custom fonts, but you must set the font first. The TFT_eSPI library also supports `fillScreen()` to clear the display, which takes about 30 ms at 8 MHz. For a smooth UI, you can use a state machine to update only changed areas. For example, if you're displaying a clock, you only update the digits that change, not the entire screen. This reduces flicker and power consumption. The module's power consumption is 50 mA at 5V with the backlight on, and 0.5 mA in sleep mode. You can put the display to sleep with `tft.writecommand(0x10)` for the ILI9341. For custom fonts, you must also consider the font baseline. The TFT_eSPI library uses a baseline offset, so characters like "g" and "y" extend below the baseline. You can adjust the cursor position using `setCursor(x, y)` where y is the baseline. For example, for a 16-point font, the baseline is at y=16, so to draw text at the top of the screen, you set y=16. The library also supports `drawRightString()` for right-aligned text. For a data dashboard, you can use a monospace font like "Consolas" for numbers, which makes alignment easier. The font converter allows you to set the character spacing, which defaults to 1 pixel. You can increase it for readability. The module's SPI interface is 5V tolerant, so you can connect it directly to an Arduino Uno without level shifters. But if you use an ESP32 (3.3V logic), you need a level shifter for the CS, DC, and RST lines. The MOSI and SCK lines can be 3.3V if the display's logic is 5V tolerant, but it's safer to use a level shifter. The module's datasheet specifies the operating voltage as 5V, but the logic pins are 3.3V compatible. For custom fonts, you can also use the `setTextColor()` function to set the foreground and background colors. The background color is used for the font's bounding box, which can be set to transparent using `tft.setTextColor(TFT_WHITE, TFT_BLACK)` for a solid background. For transparent text, use `tft.setTextColor(TFT_WHITE, TFT_TRANSPARENT)`. This is useful for overlaying text on images. The module supports 16-bit color (65,536 colors), so you can use any RGB color. The color format is 5-6-5 (5 bits red, 6 bits green, 5 bits blue). For example, red is 0xF800, green is 0x07E0, blue is 0x001F. You can use the `color565()` function to convert RGB values. For custom fonts, the rendering engine uses the foreground color and ignores the background color if set to transparent. The font file itself stores the bitmap data for each character, which is a 1-bit per pixel (black and white) or 4-bit per pixel (16 shades of gray) for anti-aliasing. The 4-bit anti-aliased fonts look smoother but take 4 times more memory. For example, a 12-point anti-aliased font with 96 characters takes about 10KB. The TFT_eSPI library supports both types. To use anti-aliasing, you select the "4-bit" option in the font converter. The rendering time is about 4 times longer because each pixel requires a grayscale blend. But the visual quality is much better, especially for small fonts. For a 2.8-inch display, 12-point anti-aliased fonts look like printed text. The module's pixel density is high enough that anti-aliasing is not strictly necessary for 16-point and above, but it helps for 8-point fonts. The font converter also allows you to include only the characters you need, like digits for a clock. This reduces the font file size. For example, a 24-point font with only digits (0-9) and colon takes about 1.5KB. The library also supports `drawNumber()` and `drawFloat()` functions for numbers, which use the current font. For a real-time clock, you can update the time every second by redrawing only the changed digits. This is efficient and uses minimal CPU. The module's SPI buffer is 512 bytes, so you can send data in chunks. The TFT_eSPI library handles this automatically. For custom fonts, you must ensure the font file is included in the sketch before compilation. The easiest way is to place the `.h` file in the same folder as the sketch. Then, in the sketch, you include it with `#include `. The library also supports loading fonts from an SD card at runtime, which is useful for multilingual applications. For example, you can store a Chinese font file on the SD card and load it when needed. The `loadFont()` function reads the file into RAM, which requires enough memory. For a 16-point Chinese font with 2000 characters, the file size is about 64KB, so you need an ESP32 or similar. The SD card is connected via SPI, and you can use the same SPI bus as the display if you use separate CS pins. The SD card's CS pin is typically pin 4. The TFT_eSPI library includes an example "SD_Test" that shows how to read files. For custom fonts, you can use the `setFreeFont()` function with a pointer to the font structure. The font structure is defined in the `.h` file. The library also supports `setTextSize()` for scaling, but this is only for the default bitmap fonts, not for custom fonts. For custom fonts, you generate the font at the desired size. So if you need 12-point and 24-point, you generate two separate files. The module's display area is 240x320 pixels, so a 24-point font (32 pixels tall) allows 10 lines of text (320/32 = 10). A 12-point font (16 pixels tall) allows 20 lines. For a data sheet, you can use a 12-point font for values and a 16-point font for headers. The library's `drawString()` function automatically wraps text if you use `setTextWrap(true)`. But for precise layout, you should calculate the string width using `textWidth()`. For example, `tft.textWidth("Hello")` returns the width in pixels. This is useful for centering text. The library also supports `drawCentreString()` which centers the text horizontally at a given y position. For vertical centering, you calculate the y position as (320 - fontHeight) / 2. The font height is available from the font structure. For example, for a 16-point font, the height is 22 pixels (including descenders). The library also supports `drawRightString()` for right-aligned text. For a dashboard, you can align numbers to the right. The module's SPI interface is fast enough for real-time updates. For example, updating a temperature display every second takes less than 1 ms of CPU time. The rest of the time, the Arduino can sleep or do other tasks. The TFT_eSPI library also supports touch input if the module has a resistive touch screen. The touch controller is typically the XPT2046, which uses SPI as well. The touch CS pin is usually pin 6. The touch resolution is 4096x4096, but you need to calibrate it. The library includes a calibration example. For custom fonts, you can use touch to select buttons with text rendered in custom fonts. The touch coordinates are mapped to the display coordinates using calibration coefficients. The module's touch interface is 5V tolerant, so you can connect it directly to an Arduino Uno. The touch response time is about 10 ms. For a UI, you can use custom fonts for button labels, which look more professional than bitmap fonts. The library also supports `drawBitmap()` for icons, which you can combine with custom fonts. For example, a weather station can display a sun icon (bitmap) with a temperature label (custom font). The bitmap can be stored in flash memory as an array. The module's color depth is 16-bit, so you can use any color for the icons. The library also supports `pushImage()` for full-screen images, which you can store on an SD card. For custom fonts, you can overlay text on images using transparent text. This is useful for splash screens. The module's refresh rate is 60 Hz, so you can animate text smoothly. For example, you can scroll text horizontally using `drawString()` with a changing x position. The library's `setScrollMargins()` function allows you to define a scroll area. This is useful for marquee text. The module's SPI speed can be increased to 20 MHz on an ESP32, which reduces rendering time by half. For custom fonts, the rendering time is proportional to the number of characters. So a 100-character string takes about 50 ms at 8 MHz, or 25 ms at 20 MHz. The TFT_eSPI library also supports DMA (Direct Memory Access) on ESP32, which offloads data transfer to the hardware, freeing the CPU. This is useful for animations. The DMA buffer size is typically 1024 bytes. The library includes an example "DMA" that shows how to use it. For custom fonts, you can use DMA to send the font bitmap data to the display without blocking the CPU. This allows you to update the display while the Arduino is doing other tasks. The module's power consumption is 50 mA, so it's suitable for battery-powered projects if you use sleep mode. The sleep mode is entered with `tft.writecommand(0x10)` and exited with `tft.writecommand(0x11)`. The wake-up time is about 5 ms. For custom fonts, you can store the font data in flash memory, which is non-volatile, so you don't need to reload it after sleep. The module's operating temperature range is -20°C to 70°C, so it's suitable for outdoor use. The humidity range is 10% to 90% non-condensing. The module's weight is about 20 grams, including the PCB. The dimensions are 70x50x10 mm. The module's connector is a 14-pin header with 2.54 mm pitch. The pins are labeled on the back. The module's driver chip is either the ILI9341 or ST7789, which are compatible with the TFT_eSPI library. The library automatically detects the driver chip if you use the correct user setup. The user setup file is in the TFT_eSPI library folder, and you need to edit it to match your module. For the 2.8 inch 5V
New business · By introduction
If this essay stung, the Autopsy will hurt more.
90 minutes. One of the four founding partners. A blunt second opinion on the brand strategy you're about to ship — and the one you should be shipping instead.
Book Your Autopsy or read the brief first →