Elektronika     Wykrywanie sterownika wyświetlacza OLED z magistralą I2C      


Obecnie na rynku można kupić moduły wyświetlaczy OLED z magistralą I2C (4-pin), które używają
kilku popularnych sterowników (kontrolerów) różnych producentów: CH1115/CH1116 (Chip Wealth),
SH1106/SH1107/SH1108 (Sino Wealth), czy SSD1306/SSD1309/SSD1312/SSD1315/SSD1327
(Solomon Systech). Istnieje programowy sposób na wykrycie typu sterownika przez odczytanie
wartości identyfikacyjnej, która znajduje się w jego rejestrze stanu (status register). Poniżej jest
przedstawiona budowa i opis poszczególnych bitów tego rejestru.

Status Register
76  5    4    3    2    1    0  
BUSYON/OFFID
BUSY - bit sygnalizuje zajętość sterownika (1 = zajęty).
Dostępny tylko w sterownikach CH1116 i SH110x.

ON/OFF - bit sygnalizuje włączenie wyświetlacza (1 = wyłączony).
Dostępny w każdym sterowniku.

ID - 6-bitowa wartość identyfikacyjna. Podana w dokumentacji sterowników CH111x i SH110x:
CH1115 = 010101, CH1116 = 010110, SH1106 = xxx000, SH1107 = 000111, SH1108 = 001000.
Nie określona (reserved) dla sterowników SSD13xx.


W przypadku sterowników SSD13xx ich dokumentacja informuje, że odczyt jakichkolwiek danych
(graficznych oraz rejestru stanu) nie jest możliwy przez interfejs szeregowy (I2C/SPI). Nie podaje też
wartości bitów identyfikacyjnych w rejestrze stanu (wszystkie bity poza nr 6 "ON/OFF", są oznaczone
jako "Reserved"). Mimo to da się odczytać rejestr stanu wraz z nieudokumentowaną wartością iden-
tyfikacyjną, na podstawie której można określić typ sterownika wyświetlacza. Taki sposób detekcji
sterownika stosuje nie rozwijana już biblioteka "ss_oled" oraz nowsza "OneBitDisplay" dla Arduino
- jednak obie korzystają tylko z najmłodszych 4-bitów wartości identyfikacyjnej (2-najstarsze jej bity
są zerowane).

Poniższa tabela zawiera szesnastkowe wartości identyfikacyjne (najmłodsze 6-bitów rejestru stanu),
zwracane przez przykładowe moduły wyświetlaczy OLED z różnymi sterownikami, które udało mi się
przetestować. Podane informacje o danym wyświetlaczu obejmują: typ sterownika, przekątna ekranu,
rozdzielczość matrycy oraz całkowite wymiary płytki modułu.

  ID  WYŚWIETLACZ / STEROWNIK
01


SSD1309 1.54"
128x64 43x38mm



SSD1312 0.96"
128x64 40x14mm
02
(^)



SSD1315 0.91"
128x32 38x12mm



SSD1315 0.96"
128x64 28x28mm



SSD1327 1.32"
128x96 33x40mm
03


SSD1306 0.91"
128x32 38x12mm



SSD1306 0.96"
128x64 27x28mm
04


SSD1315 0.96"
128x64 26x26mm

Na taśmie widoczne
czarne oznaczenie
"1315".



SSD1315 0.96"
128x64 25x27mm

Na taśmie widoczne
czarne oznaczenie
"1315".



SSD1315 0.96"
128x64 26x26mm

Na taśmie widoczne
białe oznaczenie
"1315".



SSD1315 0.96"
128x64 28x28mm

Na taśmie widoczne
białe oznaczenie
"1315".
06
(*)
SSD1306
07
(#)



SH1107 1.5"
128x128 34x47mm



SSD1315 0.96"
128x64 26x26mm

 Zwraca wartość modułu 
SH1107, ale wygląda
jak moduł SSD1315.
08


SH1106 1.3"
128x64 36x34mm
SH1108
0F
(*)
SH1107
15


CH1115 1.29"
128x64 46x20mm
16


CH1116 1.54"
128x64 43x38mm

(^) - ta wartość przypuszczalnie może być również zwracana przez sterownik SSD1306.
(*) - wartość nie odczytana przeze mnie (podana w pliku źródłowym "ss_oled.cpp" biblioteki "ss_oled").
(#) - taką wartość zwrócił też wyświetlacz, zawierający prawdopodobnie sterownik SSD1315
        (jest o tym nawet wzmianka w pliku źródłowym "obd.inl" biblioteki "OneBitDisplay").


Program testujący

Wartości identyfikacyjne odczytywałem napisanym przeze mnie programem testującym, skompilowa-
nym w środowisku "Arduino 1.8.19" i wgranym do modułu Arduino Nano 3.0. W archiwum znajduje się
szkic "OLEDchk.ino" i wsady programu: bez bootloadera "OLEDchk.hex" oraz z dołączonym nowym/
starym bootloaderem Arduino "OLEDchk_new_bootloader.hex" / "OLEDchk_old_bootloader.hex".
Wyprowadzenia testowanego wyświetlacza, należy podłączyć do Arduino w następujący sposób:
SCL=A5, SDA=A4. Magistrala I2C jest obsługiwana przez bibliotekę "Wire" z częstotliwością 100 kHz
(sterowniki obsługują szybkość transmisji do 400 kHz). Do magistrali może być podłączony tylko jeden
wyświetlacz jednocześnie. Program szkicu komunikuje się z użytkownikiem, wysyłając dane tekstowe
przez interfejs USART-USB do monitora portu szeregowego (szybkość 9600 B/s, tryb 8N1), dostęp-
nego w środowisku Arduino. Można też użyć innego programu terminala i dowolnego odbiornika
szeregowego TTL, podłączonego do Arduino w następujący sposób: TX=RX0, RX=TX1.

Po inicjalizacji magistrali I2C oraz interfejsu USART, program przechodzi do wykonywania głównej
pętli. Po upływie 5s następuje wykrywanie obecności wyświetlacza OLED, o adresie $3C ($78) lub
$3D ($7A). Jeśli nie zostanie on wykryty na magistrali I2C, to pojawi się komunikat "OLED not found",
a program po upływie 5s wznowi wykrywanie.
Natomiast, jeśli wyświetlacz zostanie wykryty, to program spróbuje odczytać wartość identyfikacyjną
z rejestru stanu jego sterownika. Jeśli nie uda się nawiązać transmisji i odczytać danych, to pojawi się
komunikat "Can't read ID", a program po upływie 5s wznowi działanie od wykrywania obecności wyś-
wietlacza. Taki błąd wystąpi, gdy zostanie przekroczony czas oczekiwania (timeout) na wykonanie
operacji I2C (np. w wyniku uszkodzenia linii SCL/SDA magistrali - należy sprawdzić połączenia).
Natomiast, jeśli odczyt danych z rejestru stanu powiedzie się, to pojawi się kolejna linia tekstu zawie-
rająca: wartość identyfikacyjną (najmłodsze 6-bitów rejestru stanu) w postaci szesnastkowej "0xNN"
(1 lub 2 cyfry), znak równości " = ", nazwę sterownika ustaloną na podstawie wartości identyfikacyjnej
(napis "Unknown", jeśli wartość nie odpowiada żadnemu znanemu sterownikowi), 7-bitowy adres wyś-
wietlacza OLED w postaci szesnastkowej "(0x3C)" lub "(0x3D)". Następnie program wznowi działanie
od początku głównej pętli.

Znalazłem informację, że wartość rejestru stanu odczytana w pierwszej transmisji I2C może nie być
prawidłowa (zwłaszcza w przypadku sterownika SH1106/CH1116), a dopiero drugi odczyt zwraca
prawidłową wartość. W praktyce okazało się, że wartość identyfikacyjna zawsze była prawidłowa
już po pierwszym odczycie.

Wyświetlacze 3.3V

Istnieją moduły wyświetlaczy przeznaczone tylko do zasilania napięciem 3.3V. Zasilane napięciem
i sterowane sygnałami 5V z Arduino mogą ulec uszkodzeniu. W praktyce podłączałem do Arduino kilka
wyświetlaczy opisanych jako 3.3V i nadal działają, co nie znaczy że każdy wytrzyma takie napięcie.

Najprostszym rozwiązaniem jest użycie przejściówki, która obniża napięcie zasilania 5V (VBUS)
portu USB do wartości 3.3V (np. liniowym stabilizatorem LM1117-3.3V typu LDO). Poniżej jest
widoczna taka przejściówka, którą zbudowałem wykorzystując: moduły PCB z męskim i żeńskim
złączem USB-A (połączone zworkami z drutu), stabilizator LM1117-3.3V (obudowa SOT-223) oraz
dołączone do niego kondensatory tantalowe: wejściowy 10uF/10V i wyjściowy 22uF/6.3V.

   

Dzięki takiej przejściówce cały moduł Arduino Nano (bez jego modyfikowania) będzie zasilany napię-
ciem 3.3V, które jest bezpieczne dla wszystkich wyświetlaczy. Oczywiście przy napięciu zasilania 3.3V,
należało by obniżyć też częstotliwość pracy mikrokontrolera ATmega328 z 16 MHz do maksymalnie
12 MHz. Wynika to z tego, że im mniejsze napięcie zasilania, tym niższa jest maksymalna częstotliwość
z jaką może pracować mikrokontroler. Poniższy wykres przedstawia zależność maksymalnej częstotli-
wości taktowania Fmax mikrokontrolera od jego napięcia zasilania Vcc.



Najlepszym rozwiązaniem była by wymiana rezonatora kwarcowego 16 MHz w module Arduino, na taki
o niższej częstotliwości pracy (8-12 MHz) oraz wpisanie jej wartości w zmiennej "xxx.build.f_cpu" doty-
czącej danej płytki, która jest umieszczona w pliku "boards.txt" z definicjami wszystkich płytek, obsłu-
giwanych przez środowisko Arduino. Jednak ze względu na bardzo małe wymiary użytego rezonatora
jest to utrudnione. W praktyce większość modułów Arduino Nano powinna działać w stanie przetakto-
wania mikrokontrolera (16 MHz) w stosunku do jego napięcia zasilania (3.3V), ale nie jest to gwaran-
towane przez producenta.

Szkic zawiera wyłączone instrukcje, zmieniające programowo częstotliwość pracy mikrokontrolera
ATmega328 z 16 MHz na 8 MHz, używając jego wewnętrznego dzielnika przez 2 ("CLKPR = 0x80",
"CLKPR = 0x01"). Po ich włączeniu, dodatkowo należy zmodyfikować wartość zmiennej "nano.bui-
ld.f_cpu" z "16000000L" na "8000000L", która jest umieszczona w definicji płytki Arduino Nano w pliku
"hardware\arduino\avr\boards.txt". Po takich zmianach Arduino Nano będzie pracowało z częstotliwo-
ścią 8 MHz, co zapewnia bezproblemowe działanie nawet przy minimalnym napięciu zasilania, wyno-
szącym 2.7V (niezbędne do pracy oscylatora "Full Swing Crystal"). Jednak zanim częstotliwość pracy
mikrokontrolera zostanie programowo obniżona, nadal musi się on uruchomić i wykonać odpowiednie
instrukcje, będąc w stanie przetaktowania (16 MHz/3.3V).