Explain to a beginner, give an example, please. The built-in fonts are not satisfied with the size, a size of 180 is required. I converted the font to VLW, which contains only ",.0123456789", and tried to use the memory card on the built-in SD reader. The built-in font is used anyway. Arduino 2.3.6. does not support ESP32FS, LittleFS is installed, but there is no mention of it in the Tools menu.
Moderator
Topic moved to the English forum because it's the most appropriate place for this subject.
First, please follow How to get the best out of this forum and properly describe your execution environment to quickly resolve the issue.
I'm assuming that "ESP32FS" refers to me-no-dev/arduino-esp32fs-plugin.
This plugin does not work with Arduino IDE 2.x. Try earlephilhower/arduino-littlefs-upload. Instructions for use are in README.md.
Neither plugin can be accessed from the "Tools" menu.
I believe using LittleFS will display fonts faster than loading them from an SD card.
I still want to try with an SD card. The verification sketch shows that the memory card is visible, the device sees the font file. But it is in a state of perpetual loading. An example of a sketch would really help. Converting a font to code for storage in SPIFFS is a dark forest for me.
ESP32-WROOM-32
Without PSRAM
Flash 4MB
SRAM 520KB
2 Cores
Arduino IDE 2.3.6 (Windows 10)
IPS display 480X320 ILI9488
Hi,
Which graphics library and method do you use? TFT_eSPI and loadFont()?
Or could you post your current minimal code?
Don't mix several problems together. Move gradually.
You've created a new font. First, test it by loading it normally, from memory. Does the font work?
With this tool, you can convert any ttf font.
//File of font in root of sd-card "DSportAutoRegular-48.vlw"
#include <TFT_eSPI.h>
#include <SD.h>
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI();
// Пины для SD карты
#define SD_CS 26
#define SD_MOSI 25
#define SD_MISO 33
#define SD_CLK 32
SPIClass hspi = SPIClass(HSPI);
void setup() {
Serial.begin(115200);
delay(1000);
// Инициализация дисплея
tft.init();
tft.setRotation(1); // Альбомная ориентация
tft.fillScreen(TFT_BLACK);
// Инициализация SD карты
hspi.begin(SD_CLK, SD_MISO, SD_MOSI, SD_CS);
if (!SD.begin(SD_CS, hspi)) {
showError("SD CARD FAILED");
return;
}
Serial.println("SD card OK");
// Проверяем наличие шрифта
if (!SD.exists("/DSportAutoRegular-48.vlw")) {
showError("FONT NOT FOUND");
return;
}
Serial.println("Font found, loading...");
// Загружаем шрифт
tft.loadFont("/DSportAutoRegular-48.vlw", SD);
Serial.println("Font loaded");
// Проверяем параметры шрифта
Serial.print("Font height: ");
Serial.println(tft.fontHeight());
// Отображаем цифры по правому краю
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.setTextDatum(TR_DATUM); // Выравнивание: правый верх
// Большие цифры у правого края экрана
tft.drawString("12345", 470, 10);
// Можно добавить еще цифр в других местах
tft.setTextDatum(MC_DATUM); // Центр
tft.drawString("88", 240, 160);
Serial.println("Digits displayed");
// Не разгружаем шрифт, чтобы видеть результат
}
void showError(const char* message) {
Serial.println(message);
tft.setTextColor(TFT_RED, TFT_BLACK);
tft.setTextSize(2);
tft.setTextDatum(MC_DATUM);
tft.drawString(message, 240, 160);
}
void loop() {
// Пустой цикл - шрифт остается загруженным
}
DSportAutoRegular-48.zip (5,1 КБ)
Although you might get error message Font file /DSportAutoRegular-48.vlw not found! at the following line:
Because the method loadFont():
So try to specify just font name only like this:
// Загружаем шрифт
tft.loadFont("DSportAutoRegular-48", SD);
For reference, loadFont() is defined as follows:
(not path to the font, but font name ![]()
Yeah, in the example, the font name is actually written as fileName, which can be confusing.
Thank you very much. such a small thing has solved so much.
But there is a problem - some kind of background under the numbers and flickering when changing the number.
video_2025-11-04_17-40-45.zip (4,4 МБ)
Please edit post #15 to wrap the code within <code/> tags to make it easier to read.
#include <TFT_eSPI.h>
#include <SD.h>
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI();
// Пины для SD карты
#define SD_CS 26
#define SD_MOSI 25
#define SD_MISO 33
#define SD_CLK 32
SPIClass hspi = SPIClass(HSPI);
void setup() {
Serial.begin(115200);
delay(1000);
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
// Инициализация SD
hspi.begin(SD_CLK, SD_MISO, SD_MOSI, SD_CS);
if (!SD.begin(SD_CS, hspi)) {
showMessage("SD CARD FAILED", TFT_RED);
return;
}
// Загружаем большой шрифт для скорости
tft.loadFont("DSportAuto-120", SD);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
// Запускаем имитацию набора скорости
speedSimulation();
}
void speedSimulation() {
int speed = 0;
unsigned long lastUpdate = 0;// Разгон 0-150
while (speed <= 150) {
unsigned long currentTime = millis();
// Обновляем скорость каждые 50ms для плавности
if (currentTime - lastUpdate >= 50) {
lastUpdate = currentTime;
// Вычисляем позицию для выравнивания по правому краю
String speedStr = String(speed);
int textWidth = tft.textWidth(speedStr);
int xPos = 480 - textWidth - 20; // 20px от правого края
int yPos = (320 - 120) / 2; // Центр по вертикали
// Очищаем только область цифр
tft.fillRect(xPos, yPos, textWidth, 120, TFT_BLACK);
// Выводим скорость
tft.setCursor(xPos, yPos);
tft.print(speedStr);
speed++;
Serial.print("Speed: ");
Serial.println(speed);
// Прерываем по Serial
if (Serial.available() && Serial.read() == 's') break;
}
}
// Финальное сообщение
tft.fillScreen(TFT_BLACK);
tft.setCursor(50, 120);
tft.print("0-150 COMPLETE");
}
void showMessage(const char* msg, uint16_t color) {
tft.setTextColor(color, TFT_BLACK);
tft.setCursor(10, 10);
tft.print(msg);
}
void loop() {
// После завершения симуляции ничего не делаем
delay(1000);
}
The reason is that the displaying rect for number is cleared every time in the while() loop.
// Разгон 0-150
while (speed <= 150) {
...
// Очищаем только область цифр
tft.fillRect(xPos, yPos, textWidth, 120, TFT_BLACK);
...
}
Since the speed variable has a maximum of three digits and the foreground and background colors are specified with setTextColor(), you can reduce flickering by formatting the string length to three digits (e.g. by sprintf()) and overwriting it instead of clearing it with fillRect().
You can also combine setCursor() and print() by using drawString(const char *string, int32_t x, int32_t y).
Thanks! There are fewer flickers. But the background of the previous characters under the numbers turns out to be a font problem, I'm trying to fix it in FontCreator.
Video.zip (6,4 МБ)
What exactly is the problem?
If the font is not monospaced (= fixed-width font), the overwritten areas may be of different sizes, and previous drawing results may remain.
The problem may be solved by preparing a sprite image large enough to completely overwrite the previous image, outputting text to that image, and then transferring it to the LCD.
Using a sprite image may also reduce flickering further.
The following example may be helpful:
It isn't a bug, it is a feature.
A graphic fonts in the most libraries are opaque, i.e. doesn't fill the background between letter pixels. In case you draw the text replacing the previous one, you need to clear background explicitly.