Wstęp
Kiedy kupujemy wyświetlacz TFT z rodziny ST77xx (ST7789, ST7735, ST7796 itp.) — zwłaszcza na portalach aukcyjnych, bez dokładnej dokumentacji — często nie wiemy, jaką ma prawdziwą rozdzielczość ani jakie są jego offsety (colstart / rowstart). Biblioteki Adafruit domyślnie zakładają konkretne wartości, a gdy się pomylimy, efekt jest natychmiastowy:
obraz jest przesunięty, ucięty na krawędzi,
widać „duchy" pikseli poza obszarem rysowania,
tekst jest lustrzany lub do góry nogami,
kolory są odwrócone (negatyw),
podświetlenie nie działa.

Błąd przesunięcia H. 
Błąd przesunięcia H i V.
Zamiast metodą prób i błędów modyfikować docelowy projekt — można użyć dedykowanego testera. Poniżej opisuję program, który napisałem na ESP32 z myślą o szybkiej kalibracji dowolnego panelu z rodziny ST77xx.
Co potrafi tester
Program obsługuje się wyłącznie z Serial Monitora (115200 baud, Newline) — nie trzeba podłączać żadnych przycisków, enkoderów ani potencjometrów. Po wgraniu na ESP32 i podłączeniu wyświetlacza wystarczy otworzyć Serial Monitor i wydawać komendy.
Wzorzec testowy
Na ekranie rysowany jest czytelny wzorzec referencyjny:
Biała ramka dokładnie na krawędziach zadeklarowanego obszaru
W × H— od razu widać, czy rozdzielczość jest poprawna.Siatka co 20 px (ciemnoszara) — ułatwia ocenę przesunięcia.
Dwie przekątne (cyjan) — przecinają się w geometrycznym środku.
4 kolorowe znaczniki w rogach:
czerwony — lewy-górny,
zielony — prawy-górny,
niebieski — lewy-dolny,
żółty — prawy-dolny.
Dzięki nim od razu widać orientację i ewentualne lustro. Czerwony znacznik zawsze musi trafić w lewy-górny róg czytelnego obrazu.
Na środku ekranu wyświetlane są: aktualne
W × H,colstart/rowstart, rotacja oraz statusINV / MX / MY.
Gotowe profile
Program zawiera kilkanaście wpisanych profili najpopularniejszych paneli — m.in.:
| Profil | Rozdzielczość | Uwagi |
|---|---|---|
| ST7789 240×240 | 1.3" / 1.54" | klasyk prosto z AliExpress |
| ST7789 240×320 | 2.0" / 2.4" | najczęstszy „2.4 cala" |
| ST7789 135×240 | 1.14" | mały IPS |
| ST7789 170×320 | 1.9" | |
| ST7789 172×320 | 1.47" | |
| ST7789 240×280 | 1.69" | |
| ST7789 240×296 | 1.72" | |
| ST7789P3 76×282 | pasek | aktywny LOW, rotacja 1 |
| ST7735 128×160 | 1.8" | |
| ST7735 128×128 | 0.96" / 1.44" | |
| ST7735 80×160 | 0.96" mini | |
| ST7796 320×480 | 3.5" |
Plus osobny profil „MANUAL / nieznany" — do kalibracji od zera.
Sterowanie z Serial Monitora
n / p - następny / poprzedni gotowy profil
w / W - width -1 / +1
h / H - height -1 / +1
x / X - colstart -1 / +1
y / Y - rowstart -1 / +1
r - rotacja 0 -> 1 -> 2 -> 3 -> 0
v - przełącz negatyw / pozytyw
m - lustro w poziomie (bit MX w MADCTL)
M - lustro w pionie (bit MY w MADCTL)
f - cykl przez 4 kombinacje MX/MY (naprawa lustrzanego obrazu)
c - wyczyść CAŁY obszar GRAM (480×480)
B - przełącz polaryzację podświetlenia (HIGH/LOW)
i - wymuś ponowną inicjalizację i przerysowanie
s - zapisz konfigurację do NVS i wypisz gotowy kod
l - lista wbudowanych profili z numerami
g<nr> - skocz bezpośrednio do profilu o numerze <nr>, np. "g3"
a - włącz / wyłącz auto-cykl (zmiana profilu co 8 s)
b - mignij podświetleniem (test przewodu BL)
? - pomocPo zmianie dowolnego parametru ekran jest natychmiast czyszczony i rysowany od nowa — efekt widoczny od razu, bez restartu ESP32.
Zapis i eksport gotowego kodu
Komenda s zapisuje aktualną konfigurację do NVS (pamięci nieulotnej ESP32) — po restarcie program startuje z tymi samymi ustawieniami. Co ważniejsze, na Serial wypisuje gotowy kod do wklejenia w docelowym projekcie:
class ST77xxDisplay : public Adafruit_ST7789 {
public:
ST77xxDisplay(int8_t cs, int8_t dc, int8_t rst) : Adafruit_ST7789(cs, dc, rst) {}
void setOffsets(int8_t col, int8_t row) { setColRowStart(col, row); }
};
ST77xxDisplay tft(TFT_CS, TFT_DC, TFT_RST);
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, HIGH); // podświetlenie aktywne HIGH
tft.init(240, 320);
tft.setOffsets(0, 0);
tft.setRotation(0);
tft.invertDisplay(false);
{ uint8_t m = 0xC0; tft.sendCommand(0x36, &m, 1); } // rot=0 MX=0 MY=0Wklejasz, kompilujesz, działa.
Ostatnia poprawka do starej wersji: pełne czyszczenie GRAM
Problem
Podczas kalibracji zmienia się rozdzielczość, offsety, rotację i inwersję dziesiątki razy. Standardowa funkcja fillScreen() czyści tylko obszar bieżącego W × H — więc jeśli wcześniej testowałeś panel 320×480, a teraz przeskakujesz na 135×240, to poza nowym oknem adresowym zostają śmieci z poprzedniego profilu. Utrudnia to ocenę, czy np. colstart jest już ustawiony dobrze, bo widać „duchy" pikseli w miejscach, których nowy obraz nie zdołał zamalować.
Dodatkowo okazuje się, że Adafruit_ST7789::setAddrWindow() automatycznie dodaje offsety colstart / rowstart do podanych współrzędnych. Więc próba wyczyszczenia ekranu przez setAddrWindow(0, 0, 480, 480) przy profilu z colstart = 80 adresuje w rzeczywistości 80..559 × 80..559 — sterownik zawija licznik GRAM, część ekranu pozostaje nietknięta, a inne piksele są zapisywane wielokrotnie.
Rozwiązanie
W wersji v1.6 funkcja clearScreen() wysyła surowe komendy CASET / RASET / RAMWR bezpośrednio przez sendCommand(), z pełnym zakresem 0..479 i bez offsetów:
void clearScreen() {
uint8_t caset[4] = { 0x00, 0x00, (uint8_t)((CLEAR_MAX_W - 1) >> 8), (uint8_t)((CLEAR_MAX_W - 1) & 0xFF) };
uint8_t raset[4] = { 0x00, 0x00, (uint8_t)((CLEAR_MAX_H - 1) >> 8), (uint8_t)((CLEAR_MAX_H - 1) & 0xFF) };
tft.sendCommand(ST77XX_CASET, caset, 4);
tft.sendCommand(ST77XX_RASET, raset, 4);
tft.sendCommand(ST77XX_RAMWR, (const uint8_t *)NULL, 0);
tft.startWrite();
tft.writeColor(ST77XX_BLACK, (uint32_t)CLEAR_MAX_W * CLEAR_MAX_H);
tft.endWrite();
}Ta funkcja jest wywoływana automatycznie w applyProfile(), przed narysowaniem wzorca. Efekt: po każdej zmianie profilu / rozdzielczości / offsetów / rotacji / inwersji / lustra ekran jest w 100% czysty — żadnych „duchów" po poprzednich próbach.
Jak używać — krok po kroku
Podłącz wyświetlacz zgodnie z pinami zdefiniowanymi na górze pliku (
TFT_CS=15,TFT_DC=2,TFT_RST=4,TFT_MOSI=23,TFT_SCLK=18,TFT_BL=32).Wgraj program na ESP32 (Arduino IDE, płytka ESP32 Dev Module).
Otwórz Serial Monitor — 115200 baud, Newline.
Wpisz
l, żeby zobaczyć listę profili.Wybierz profil komendą
g<nr>— np.g1dla ST7789 240×320.Dostrajaj:
w/W,h/H,x/X,y/Y— aż biała ramka pokryje się z krawędziami ekranu, a czerwony znacznik będzie w lewym-górnym rogu czytelnego obrazu.Jeśli obraz jest lustrzany — wciskaj
f, aż tekst będzie czytelny.Jeśli kolory są odwrócone — wciśnij
v.Jeśli podświetlenie nie działa — wciśnij
Bi/lubb.Wpisz
s— konfiguracja trafia do NVS i na Serial wypisuje się gotowy kod do wklejenia w projekcie docelowym.
Kalibruj w rotacji 0 (pionowej) — dopiero po ustaleniu offsetów i rozdzielczości przechodź na inne rotacje.
Pod maską — ciekawe rozwiązania
ST77xxTesterjako podklasaAdafruit_ST7789—setColRowStart()bywa oznaczone jakoprotectedw niektórych wersjach biblioteki. Utworzenie podklasy z publicznym wrapperemsetOffsets(col, row)obchodzi ten problem czysto, bez modyfikowania biblioteki.Ręczne wysyłanie
MADCTLposetRotation()—init()resetuje rejestr MADCTL, więc ustawienia lustra trzeba nakładać po każdej inicjalizacji. Program robi to wapplyMADCTL().Obszar czyszczenia 480×480 — pokrywa wszystkie panele z listy profili (w tym ST7796 320×480). Nadmiarowe adresy po prostu zawijają licznik GRAM, a ponieważ piszemy wszędzie czarny — efekt jest dokładnie taki, jak trzeba.
Rzutowanie
(const uint8_t *)NULL— bez tego kompilator nie wie, które przeciążeniesendCommandwybrać (zuint8_t*czyconst uint8_t*), boNULLpasuje do obu.
Wnioski
Tester skrócił mi czas kalibracji nowego panelu z nawet godzin (metodą prób i błędów w docelowym projekcie) do kilku minut w dedykowanym narzędziu. Kluczowe okazały się:
Natychmiastowa reakcja na każdą zmianę — czysty ekran i świeżo narysowany wzorzec po każdym naciśnięciu klawisza.
Czytelny wzorzec — kolorowe znaczniki w rogach od razu pokazują orientację i ewentualne lustro.
Eksport gotowego kodu — komenda
seliminuje przepisywanie parametrów do projektu ręcznie.Pełne czyszczenie GRAM — bez tego połowa czasu kalibracji schodzi na odróżnianie śmieci od rzeczywistych artefaktów nowego ustawienia.
Program jest dostępny na licencji otwartej — wystarczy wkleić do Arduino IDE, wgrać na ESP32 i cieszyć się szybką kalibracją kolejnych egzotycznych paneli z rodziny ST77xx. Miło by było gdybyś pamiętał o jego autorze i włożonej przez niego pracy 😊.
Na koniec kilka fotek z kalibrowania:
![]() |
| Źle dobrana rozdzielczość i rotacja. |
![]() |
| Źle dobrana rozdzielczość. Rotacja OK. |
![]() |
| Jeszcze zła rozdzielczość i rotacja. |
![]() |
| Poprawna rozdzielczość, zła rotacja. |
![]() |
| Poprawna rozdzielczość i rotacja. |
![]() |
Po włączeniu negacji widać przesunięcie krawędzi. |
![]() |
Teraz jest poprawnie. Tak można zapisać -> [s]. |
Przepraszam za jakość zdjęć ale tak mój telefon widzi ekran wyświetlacza.
Miłego kalibrowania!
✍️ Autor: Robert HF5WWL
📅 Data projektu: wrzesień 2026 r.
📍 Lokalizacja: Wołomin, POLSKA
📁 Coś nie jasne? Pytaj poprzez e-mail (hf5wwl@gmail.com) lub w komentarzu
🛠️ Poziom trudności: Łatwy (jak się wie co się robi) 😊

























