LinkedIn YouTube Facebook
Szukaj

Newsletter

Proszę czekać.

Dziękujemy za zgłoszenie!

Wstecz
Artykuły

[MBED] STM32 i SSD1306 – sterowanie dwukolorowym OLED [1]

Rys. 8. Adresowanie horyzontalne z ograniczonym zakresem zmian adresów

Rys. 8. Adresowanie horyzontalne z ograniczonym zakresem zmian adresów

Komendy sterownika SSD1306

Przy okazji omawiania adresowania pamięci RAM obrazu opisałem kilka komend przeznaczonych do wyboru trybu adresowania i ustawiania liczników adresu. Sterownik SSD1306 ma dosyć spory zestaw komend sterujących. Dokładne opisywanie wszystkich znacznie wykracza poza zakres tego artykułu i nie jest tez konieczne, bo dane te można znaleźć w dokumentacji.

Obsługa SSD1306 w mbed

Jak już wspomniałem moduł wyświetlacza jest skonfigurowany do pracy z 4-przewodową magistralą SPI. Jako sterownik – host wykorzystałem moduł Nucleo-F401RE z mikrokontrolerem rodziny STM32F401, produkowany przez firmę STM. Główne powody tego wyboru to wbudowany programator i wsparcie w systemie bezpłatnego środowiska projektowego mbed oferowanego przez firmę ARM.

Wsparcie Nucleo przez mbed zapewnia bardzo prostą konfigurację układów peryferyjnych i pozwala skupić się na głównym problemie, czyli na obsłudze wyświetlacza.

Na początek zajmiemy się interfejsem komunikacyjnym SPI. W środowisku mbed trzeba zainicjalizować SPI podając linie na których będą dostępne sygnały MOSI (dane wyjściowe), MISO (dane wejściowe) i SCK (zegar taktujący przesyłaniem danych). Standardowo te sygnały są dostępne na złączu zgodnym ze standardem Arduino Uno modułu Nucleo. Jeżeli chcemy z nich skorzystać to wystarczy zadeklarować interfejs z predefiniowanymi definicjami (listing 1).

List. 1. Konfiguracja interfejsu SPI i linii dodatkowych

SPI dev(SPI_MOSI, SPI_MISO, SPI_SCK);
DigitalOut CS(PB_6);
DigitalOut DC(PC_7);
DigitalOut RES(PA_9);

Interfejs SPI oprócz linii MOSI, MISO i SCK wymaga linii CS (standardowa linii interfejsu SPI) i linii DC określającej miejsce docelowe przesyłanych danych (rejestry sterujące, lub pamięć obrazu). Poza tym sterownik SSD1306 musi zostać sprzętowo wyzerowany przez wymuszenie stanu niskiego na linii RESET. Linie interfejsu SPI łącznie z linią RESET należy również zdefiniować. Konfiguracja sprzętowa została pokazana na listingu 1.

Wyprowadzenia płytki wyświetlacza nie zawierają linii wyjścia danych ze sterownika, a to oznacza, że żadnych danych nie będziemy mogli odczytywać.

Do sterowania wyświetlaczem będą nam potrzebne dwie użyteczne procedury: zapisania rejestrów stepujących, czyli kodu komendy i ewentualnie jej argumentów, oraz zapisania danej do pamięci obrazu wyświetlacza – listing 2 i listing 3.

List. 2. Wysłanie kodu komendy do sterownika

//***********************************************
//wysłanie danej przez SPI
//**********************************************
void WriteSpi(unsigned char data)
{
  dev.write(data);
}
//***********************************************
//zapisanie kodu komendy do sterownika SSD1306
//***********************************************
void WriteCmd(unsigned char cmd)
{
    CS=1;      
    DC=0;                           //DC=0 przesłanie komendy     
    CS=0;      
    WriteSpi(cmd);                  //zapis kodu komendy
    CS=1;      
}

List. 3. Zapisanie danej do pamięci RAM

//***********************************************
//zapisanie danej do pamięci obrazu sterownika SSD1306
//***********************************************
void WriteData(unsigned char data)
{
    CS=1;      
    DC=1;                                //DC=1 przesłanie danej do pamięci RAM     
    CS=0;      
    WriteSpi(data);                //zapis danej
    CS=1;   
}

SSD1306 tak jak większość sterowników po włączeniu zasilania ustawia w rejestrach domyślne wartości. To jakie wartości trzeba wpisać do tych rejestrów zależy od rodzaju użytej matrycy OLED i zazwyczaj program użytkownika musi je zapisać w procesie inicjalizacji. Kompletna procedura inicjalizacji void InitSSD1306 () została pokazana na listingu 4.

 List. 4. Inicjalizacja sterownika wyświetlacza

//***********************************************
//inicjalizacja sterownika SSD1306
//***********************************************
void InitSSD1306 (void)
{
  CS=1;      
  DC=0;
  RES=1;    //_reset = 1;
  wait(0.01);
  RES=0;    //_reset = 0;
  wait(0.10);
  RES=1;    //_reset = 1;
 
  WriteCmd(0xAE);//wyłącz panel OLED
  WriteCmd(0x00);//adres koluny LOW
  WriteCmd(0x10);//adres koluny HIGH
  WriteCmd(0x40);//adres startu linii
  WriteCmd(0x20);//tryb adresowania strony
  WriteCmd(0x02);
  WriteCmd(0x81);//ustaw kontrast
  WriteCmd(0xCF);
  WriteCmd(0xA1);//ustaw remapowanie
  WriteCmd(0xC0);//kierunek skanowania
  WriteCmd(0xA6);//wyświetlanie bez inwersji
  WriteCmd(0xA8);//ustaw multiplex ratio
  WriteCmd(0x3F);//1/64
  WriteCmd(0xD3);//ustaw display offset
  WriteCmd(0x00);//bez offsetu
  WriteCmd(0xD5);//ustaw divide ratio/częstotliwość oscylatora
  WriteCmd(0x80);//100ramek/sec
  WriteCmd(0xD9);//ustaw okres pre charge
  WriteCmd(0xF1);//pre charge 15 cykli, discharge 1 cykl
  WriteCmd(0xDA);//konfiguracja wyprowadzeń sterownika
  WriteCmd(0x12);
  WriteCmd(0xDB);//ustawienie vcomh
  WriteCmd(0x40);
  WriteCmd(0x8D);//ustawienie Charge Pump
  WriteCmd(0x14);
  WriteCmd(0xA4);//"podłączenie" zawartości RAM do panelu OLED
  WriteCmd(0xA6);//wyłączenie inwersji wyświetlania
  WriteCmd(0xAF);//włącza wyświetlacz
  DisplayCls(0);

Najpierw wykonywana jest sprzętowa sekwencja wygenerowania impulsu zerującego o długości 10 ms i zainicjowaniu linii CS =1 i DC=0. Właściwa programowa inicjalizacja zaczyna się wysłania komendy AE wyłączającej sterowanie matrycą OLED. Potem są inicjowane(zerowane) liczniki adresowe kolumn i stron i wprowadzany tryb adresowania Page Addressing Mode. Zakładamy, że wyświetlacz będzie pracował w układzie normalnym, to znaczy, że dół wyświetlacza będzie przy krawędzi płytki z wyprowadzeniami. Do tej orientacji mechanicznej jest ustawiane remapowanie, kierunek skanowania i konfiguracja wyprowadzeń sterownika.

Ponieważ sterownik może współpracować z różnymi matrycami, to ma możliwość ustawienia wielu parametrów takich jak divide ratio, częstotliwość odświeżania, oraz napięcie zasilające (prąd segmentów) matrycy OLED. Z tymi ustawieniami jest bardzo często problem. Albo mamy wyświetlacz, o którym tylko wiemy jaki ma sterownik, albo w danych katalogowych nie są podane tego typu istotne informacje. Pozostaje inicjowanie pracy układu sterującego metodą prób i błędów. W przypadku opisywanego wyświetlacza istnieje coś w rodzaju dokumentacji technicznej, ale niestety opisuje ona głównie komunikację ze sterownikiem, a te informacje są doskonale opisane w dokumentacji sterownika SSD1306.

Zacznijmy inicjowanie sterownika od ustawienia kontrastu. Prąd segmentu OLED można wyliczyć z zależności:

image020

Parametr Contrast to wartość argumentu komendy 81h zmieniająca się w zakresie od 0 do 255.

Parametr Scale Factor ma stałą wartość równą 8.

Żeby zasilić matrycę OLED napięciem wyższym od napięcia zasilającego układy cyfrowe w układ SSD1306 wbudowano przetwornicę podwyższająca napięcie działająca na zasadzie pompy ładunkowej charge pump. Do działania takiego układu potrzebne są tylko 2 zewnętrzne kondensatory podłączane do wyprowadzeń C1N, C1P i C2N oraz C2P. Wartość napięcia wyjściowego określa się zewnętrznym rezystorem podłączonym do wyprowadzenia IREF. Napięcie na tym wyjściu jest równe Vcc-2,5, gdzie Vcc jest napięciem zasilającym matrycę. W opisywanym wyświetlaczu rezystor R1 ma wartość 1MΩ i powinien wymuszać prąd o wartości ok 12,5µA +/- 2µA. Powoduje on spadek na R1 równy 12,5V. Zatem matryca jest zasilana napięciem 12,5V+2,5V=15V.

Po włączeniu zasilania sterownika przetwornica jest domyślnie wyłączona. Dlatego w procedurze inicjalizacji należy ją włączyć wysyłając komendę 8D z argumentem 14h (A2=1).

Po wyliczeniu prądu jednego segmentu można optymalnie dobrać wartość kontrastu dla matrycy. Ja wpisałem DFh, ale eksperymentowałem również z innymi wartościami.

Stopień podziału częstotliwości taktującej ustala się w zakresie od 1 do 16 komendą D5 Set Display Clock Divide Ratio/Oscillator Frequency. Najmłodsze 4 bity zawierają wartość D, a DCLK=Fosc/D+1. Jak można zobaczyć w procedurze inicjalizacji argument komendy D5 ma wartość 80h, czyli D+1=1. Sterownik jest taktowany częstotliwością równą częstotliwości Fosc. Cztery starsze bity argumentu zawierają współczynnik K określający ile cykli zegara jest przeznaczonych na wyświetlenie jednego rzędu (linijki). Częstotliwość z jaka są wyświetlane ramki można wyliczyć z zależności:

image022

W przykładzie mamy D=1, K=8.

Współczynnik multipleksowania Mux jest ustawiany komendą A8 i wynosi 64. Zatem FFRM=Fosc/(8*64)=Fosc/512. Częstotliwość oscylatora to ok. 370kHz i FFRM jest równa ~720Hz.

Ostatnią czynnością inicjalizacji jest wyczyszczenie (wyzerowanie) pamięci obrazu RAM tak by po inicjalizacji na ekranie ni wyświetlały się przypadkowe wartości. Procedura czyszczenia wyświetlacza została pokazana na listingu 5. Działa ona poprawnie dla trybu adresowania Page Addressing Mode ustawionego w czasie inicjalizacji sterownika.

List. 5. Czyszczenie zawartości wyświetlacza

//**********************************************
//zeruj bufor wyświetlacza
//i zapisz jego zwartość do RAM obrazu
//**********************************************  
void DisplayCls(unsigned char fill)
{
  unsigned char i, j;
 

  for (i = 0; i < 8; i ++) {
    for (j = 0; j < 128; j ++) {
      DispBuff[j][i] = fill;
    }
  }
 
  RefreshRAM();//zawartość bufora do RAM obrazu
}
//****************************************************
//zapisanie zawartości bufora do RAM wyświetlacza
//****************************************************
void RefreshRAM(void)
{
  uint8_t i, j;
 
  for (i = 0; i < 8; i ++) {
    WriteCmd(0xB0 + i);
    SetColStart();   
    for (j = 0; j < 128; j ++) {
      WriteData(DispBuff[j][i]);
    }
  }  
}
Absolwent Wydziału Elektroniki Politechniki Wrocławskiej, współpracownik miesięcznika Elektronika Praktyczna, autor książek o mikrokontrolerach Microchip i wyświetlaczach graficznych, wydanych nakładem Wydawnictwa BTC. Zawodowo zajmuje się projektowaniem zaawansowanych systemów mikroprocesorowych.