Podłączamy w 7 krokach STM32 Nucleo z ekranem Waveshare E-Paper

Wstęp

Cześć! 👋
Dzisiaj chcę Ci pokazać mój ostatni poboczny projekt: połączenie płytki STM32 Nucleo G474RE z 3,7-calowym ekranem e-paper od Waveshare. W skrócie – chciałem zrozumieć, jak te dwa kawałki sprzętu dogadują się ze sobą, jak skonfigurować CubeMX i jak faktycznie wyświetlić coś sensownego na ekranie.

Zanim przejdziemy do kabli i kodu, ustalmy kilka rzeczy:

  • Czym jest płytka Nucleo?
    STM32 Nucleo to rodzina płytek rozwojowych od STMicroelectronics. Oparte są na mikrokontrolerach STM32 i często używa się ich w profesjonalnych projektach embedded. W porównaniu do Arduino dają Ci znacznie większą kontrolę nad peryferiami i funkcjami niskopoziomowymi. W porównaniu do ESP32, STM32 nie skupia się na Wi-Fi/Bluetooth, tylko na czystej wydajności, deterministycznym czasie działania i niezawodności przemysłowej 🚀.
  • Co jest wyjątkowego w e-paperze?
    Waveshare 3,7’’ to ekran podobny do tego z Kindle’a. Odbija światło zamiast je emitować, więc jest bardzo przyjazny dla oczu. Raz wyrenderowany obraz zostaje na ekranie bez poboru energii, co sprawia, że świetnie nadaje się do projektów zasilanych bateryjnie albo takich, które mają być stale włączone (stacje pogodowe, dashboardy, elektroniczne metki cenowe itd.).
Zdjęcie przedstawiające zestaw: Nucleo, ekran e-paper i płytkę stykową

Część teoretyczna

Zanim odpalimy CubeMX, krótko o teorii.

  • LUT (Look-Up Table)
    Definiuje przebieg sygnałów sterujących cząsteczkami czerni/bieli wewnątrz e-papera. Bez właściwego LUT-u pojawiają się artefakty albo ghosting. Taka lista instrukcji dla wyświetlacza mówiąca jak odbierać nasze dane.
  • Tryby wyświetlania e-paper:
    • GC (Global Clear) – pełne odświeżenie z „mrugnięciem”, bardzo czyste, ale wolne.
    • DU (Direct Update) – bez mrugnięcia, dużo szybsze, ale zostawia ghosting.
    • A2 – tylko czerń i biel, najszybsze, ale z wyraźnym ghostingiem. Idealne do edytorów tekstu czy terminali.
  • Komunikacja: SPI
    Ekran komunikuje się przez SPI (Serial Peripheral Interface). Jest proste, szybkie i powszechnie obsługiwane.
  • Piny GPIO:
    • DC – informuje ekran, czy wysyłane są komendy, czy dane.
    • BUSY – w stanie wysokim oznacza, że wyświetlacz jest zajęty i nie można mu jeszcze wysyłać nowych danych.

Tworzymy nowy projekt STM32

Odpalam STM32CubeMX, czyli graficzne narzędzie od ST do konfigurowania mikrokontrolerów. Dzięki niemu nie musimy pisać tony boilerplate’u.

Zrzut ekranu przedstawiający tworzenie projektu Nucleo w STM32CubeMX
  1. Tworzę nowy projekt i wybieram płytkę Nucleo G474RE.
  2. Zmieniam toolchain na CMake/GCC (można wtedy pracować z VSCode zamiast przestarzałego Eclipse).
  3. W ustawieniach generowania zaznaczam „Generate peripheral initialization as a pair of .c/.h files per peripheral” – dzięki temu kod jest bardziej modularny.
Zrzut ekranu pokazujący konfigurację projektu Nucleo w STM32CubeMX

Po wygenerowaniu kodu otwieram projekt w VSCode, importuję go przez wtyczkę STM32, wciskam F5 i… debugowanie działa od strzału ✅.

Zrzut ekranu pokazujący debugowanie z VSCode

Podłączanie ekranu

Darmowe bonusowe treści

⚡ Chcesz od razu dostać jeszcze lepszy sterownik za darmo?
Zapisz się do mojego newslettera!
Dołączając do mojego newslettera, odblokujesz dodatkowe materiały do tego poradnika:
– Pełny, zrefactorowany plik main.c z dodatkowymi komentarzami i integracją LVGL (rysowanie, czcionki itd)
– Dostęp do całego repozytorium z kompletnym kodem integracji STM32 + Waveshare e-paper
👉 Zapisz się i pobierz gotowe pliki projektu.

E-paper potrzebuje 8 połączeń:

  • Zasilanie: VCC, GND, RST (reset). Nucleo daje 3,3V, które w zupełności wystarcza.
  • SPI: CS, MOSI, SCK.
  • Sterowanie: DC (komenda/dane) i BUSY (status).

RST jest aktywne w stanie niskim, czyli trzeba go ściągnąć do masy, żeby zresetować ekran. BUSY to pin tylko do odczytu, informujący, że ekran nadal się odświeża.

Zdjęcie pokazujące tył ekranu e-paper Waveshare 3.7'

Konfiguracja SPI i GPIO

SPI

SPI to po prostu szybka magistrala szeregowa z linią zegara i danych. W CubeMX włączyłem SPI2 jako „Transmit Only Master” z rozmiarem danych 8 bitów.

CubeMX zaproponował:

  • PB15 → MOSI
  • PB13 → SCK

Preskaler ustawiłem na 64, co dało mi około 2,65 Mbit/s. W zupełności wystarczy do e-papera.
Profesjonalniej byłoby dostroić zegary całego mikrokontrolera, zamiast walić taki duży preskaler, ale w tym krótkim poradniku nie będziemy komplikować 😉.

Zrzut ekranu przedstawiający konfigurację pinów w STM32CubeMX

GPIO

Dla pinów GPIO zrobiłem tak:

  • PB0, PB1, PB14 → Wyjścia (DC, RST, CS).
  • PB2 → Wejście (BUSY).

Moja przygoda ze sterownikiem

Tutaj zaczęło się robić ciekawie.

Jak zwykle w hobbystycznych projektach, postanowiłem „zrobić to po trudniejszej drodze” i napisać własny sterownik zamiast kopiować gotowy. Logika była prosta: inicjalizacja → załadowanie LUT → ustawienie okna → wysłanie bufora.

Pierwszy test się udał: wyrenderowałem szachownicę. Kolejny krok: częściowe odświeżanie. I tu klops.

Normalnie partial update działa tak: ustawiasz okno rysowania (x, y, szerokość, wysokość), ładujesz dane do bufora, ewentualnie zmieniasz LUT i wysyłasz. Ale w tym ekranie… nie działało. Pomyślałem, że mój kod jest zły, więc sprawdziłem oficjalny sterownik Waveshare. Wynik? To samo – popsute.

Po kilku godzinach grzebania znalazłem taki komentarz w kodzie oficjalnego sterownika:

C++
/******************************************************************************
function :  Sends part the image buffer in RAM to e-Paper and displays
notes:
 * You can send a part of data to e-Paper,But this function is not recommended
 * 1. Xsize must be as big as EPD_3IN7_WIDTH
 * 2. Ypointer must be start at 0
 ******************************************************************************/
int EPD_3IN7_1Gray_Display_Part(const UBYTE *Image, UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend)

No i super… partial update jest „udawany”. Działa tylko wtedy, gdy szerokość X = pełny ekran, a Y zaczyna się od 0. To wyjaśniało wszystko 🤦.

W końcu udało mi się to obejść, ale tylko jeśli poprzednia komenda nie była GC i jeśli wcześniej zrobiłem DU całego ekranu. Strasznie toporne, ale jakoś działa.

Na dodatek w oficjalnym sterowniku znalazłem bugi: pełne odświeżenie nie resetuje okna rysowania, więc po partial update kolejne pełne odświeżenie wyświetlało śmieci. To też poprawiłem w swojej wersji.


Sterownik

Zaadaptowałem sterownik od Waveshare, trochę go posprzątałem i dodałem poprawki. Nie będę tu wklejał całego pliku (jest długi), ale idea jest taka:

  • epd_3in7.h → sekcja konfiguracji z definicjami pinów.
  • epd_3in7.c → integracja ze STM32 + obsługa LUT.

Musisz tylko zmienić sekcję konfiguracyjną.


Program

W main.c napisałem małe demo:

  1. Czyszczenie ekranu w trybie GC.
  2. Narysowanie szachownicy w trybach GC i DU.
  3. Rysowanie na zmianę czarnego/białego kwadratu na środku przy użyciu „partial update”.
C++
  EPD_3IN7_1Gray_Init();
  EPD_3IN7_1Gray_Clear(1); // 1 = GC

  UBYTE black = 1;              // starting with black square
  UBYTE partial_since_full = 0; // count partial updates since last full refresh
  UBYTE toggles = 0;            // total square color toggles

  // One-time "top full" push so partials won't blank the rest
  draw_checker_full();
  EPD_3IN7_1Gray_Display(frame_bw, 1); // GC
  EPD_3IN7_1Gray_Display(frame_bw, 2); // DU

  while (1)
  {
  
  // (...)

Dzięki temu widzimy:

  • pełne odświeżanie działa,
  • DU zostawia ghosting,
  • pseudo-partial update działa tak, jak można się tego spodziewać, ale jest szybciej

Oficjalny sterownik obsługuje też 4-poziomową skalę szarości, ale jej nie testowałem, więc nic nie obiecuję.


Podsumowanie

Ten mały projekt nauczył mnie więcej, niż się spodziewałem. Udało mi się zmusić Nucleo do gadania z e-paperem, odkryłem dziwactwa partial update i poprawiłem kilka bugów w oficjalnym sterowniku.

Jeśli chcesz samemu poeksperymentować, weź mój poprawiony sterownik, podłącz ekran i spróbuj wyrenderować własne rzeczy.

Jeśli potrzebujesz czegoś więcej, polecam zajrzeć do pełnej wersji mojego sterownika (newsletter). W oficjalnym sterowniku LUT-y są wysyłane niepotrzebnie, pozycje rysowania nie są zbyt niskopoziomowe, a abstrakcja jest trochę dziurawa. Najlepiej byłoby mieć rdzeń niskopoziomowy, a dopiero na nim warstwę wyższego poziomu do prostszego rysowania.

Zdjęcie pokazujące Nucleo, ekran e-paper z narysowanym tekstem za pomocą LVGL

Dołącz do newslettera

Subskrybuj po bonusowe treści. Nie przegap nowych artykułów.

    We won’t send you spam. Unsubscribe at any time.

    Zostaw komentarz

    Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

    Przewijanie do góry