e-paper: wyświetlacze w teorii i praktyce [1]
List. 2. Procedura zapisywania jednego wiersza wyświetlacza
void SendSOURCEData(u8 *pArray) { EPD_LE_H; //LE =1 EPD_CL_L; //CL=0 EPD_CL_H; //CL=1 EPD_CL_L; //CL=0 EPD_CL_H; //CL=1 EPD_LE_L; //LE=0 EPD_CL_L; //CL=0 EPD_CL_H; //CL=1 EPD_CL_L; //CL=0 EPD_CL_H; //CL=1 EPD_OE_H; //OE =1 EPD_CL_L; //CL=0 EPD_CL_H; //CL=1 EPD_CL_L; //CL=0 EPD_CL_H; //CL=1 EPD_SPH_L; //SPH=0 old_data = (uint16_t)(EPD_DB_PORT->ODR); old_data &= 0xFF00; for(column= 0; column < 200; column++) // zapisanie 200bajtów z tablicy wiersza { new_data = old_data | (u16)pArray[column]; (EPD_DB_PORT->ODR) = new_data; EPD_CL_L; //CL=0 takt zegara taktującego rejestr SOURCE EPD_CL_H; //CL=1 } EPD_SPH_H; //STH=1 EPD_CL_L; //CL=0 EPD_CL_H; //CL=1 EPD_CL_L; //CL=0 EPD_CL_H; //CL=1 EPD_CPV_L; //CPV=0 – zegar taktujacy bufor GATE EPD_OE_L; //OE =0 EPD_CL_L; //CL=0 EPD_CL_H; //CL=1 EPD_CL_L; //CL=0 EPD_CL_H; //CL=1 EPD_CPV_H; //CPV=1 }
Sekwencja zapisu rozpoczyna się od ustawienia LE=1 i LE=0 oraz OE=1. Każda zmiana stanu tych linii sterujących wymaga jednego cyklu. Potem jest zapisywanych 200 bajtów z wcześniej przygotowanego bufora pArray. Każdy bajt jest wpisywany narastającym zboczem sygnału zegara CL. Wprowadzenie zmiennej old_data zapobiega niszczeniu stanów nie używanych linii portu przy zapisywaniu linii magistrali danych.
Po zapisaniu 200 bajtów jest aktywowany sygnał OE i zawartość rejestru LATCH pojawia się na wyjściu bufora SOURCE. Jednocześnie na linii CPV jest wymuszane zbocze opadające a potem narastające. Po każdym zapisaniu wiersza trzeba zmienić zawartość licznika wierszy – czyli rejestru GATE, tak by następny wiersz był zapisywany w następnej pozycji na wyświetlaczu. Cykl uaktywnienia zapisywania rejestru, tak by sterował pierwszym wierszem (G1) rozpoczyna się od wystawienia stanu niskiego na STV i wymuszeniu zbocza narastającego na linii zegarowej CPV (szczegóły w dokumentacji sterownika).
Każda sekwencja zapisu rejestrów wyświetlacza powinna się zaczynać od wykonania procedury EPD-StartScan() wymuszającej taką sekwencję – listing 3.
List. 3. Wymuszenie początku skanowania linii wyświetlacza
void EPD_Start_Scan(void) { EPD_STV_H; //STV=1 loop = 2; while(loop--) { EPD_CPV_L; CPV=0 Delay(0xf); EPD_CPV_H; CPV=1 Delay(0xf); } EPD_STV_L; //STV=0 loop = 2; while(loop--) { EPD_CPV_L; //CPV=0 Delay(0xf); EPD_CPV_H; //CPV=1 Delay(0xf); } EPD_STV_H; //STV=1 loop = 2; while(loop--) { EPD_CPV_L; Delay(0xf); EPD_CPV_H; Delay(0xf); } }
W teorii mamy wszystko do potrzeba by wyświetlić dowolną bitmapę. Zapisujemy 600 razy rejestr SOURCE o rozmiarze 800×2 bity jednocześnie zmieniając wpisy do rejestru GATE. Zależnie od wartości 2 bitów programujących napięcie wyjściowe dla określonego piksela (kapsułki) punkt na ekranie będzie czarny lub biały, tak jak to zostało już wyżej opisane. Jednak w praktyce nie jest to takie proste. Okazuje się, że do zmiany „świecenia” punktu na ekranie potrzeba czegoś więcej, niż prostego przebiegunowania elektrod sterujących. Po to by obraz wyświetlił się tak jak chcemy i w dodatku mógł pozostawać w tym stanie przez długi czas potrzeba kilku zdefiniowanych sekwencji zapisywania całego wyświetlacza. Na elektrodach sterujących kapsułkami trzeba wymusić coś w rodzaju przebiegu cyfrowego (waveform). Długość przebiegu i jego „kształt” może zależeć zależy od producenta matrycy, a nawet o konkretnego modelu wyświetlacza. Przebiegi sterujące będą wyglądać inaczej dla zmiany „świecenia” kapsułki , a inaczej dla sekwencji „odświeżenia” już wyświetlanej informacji.
Podanie przebiegu na każdą z elektrod sterujących sprowadza się do wykonania kilku zapisów (sekcji) całego wyświetlacza tak jak to zostało pokazane na rysunku 4. Okres skanowania wyświetlacza jest określony przez czas od wysterowania G0 do wysterowania G599, czy czas potrzebny do zapisania całego wyświetlacza.
Rys. 4. Skanowanie wyświetlacza
Rys. 5. Przykładowe ustawienie piksela w czasie 12 zapisów
Przykład zapisu piksela jest pokazany na rysunku 5. Każdy z pikseli jest zapisywany 12 razy (12 sekcji). Każda sekcja to jeden zapis całego wyświetlacza. W czasie sterowania wyświetlaczem każdy piksel może zmieniać swój stan w następujący sposób:
- Z białego na biały
- Z białego na czarny
- Z czarnego na biały
- Z czarnego na czarny
Dla każdej z takich sekwencji trzeba zdefiniować przebieg sterujący – tabela 2.
Tab. 2. Przykładowe sekwencje zmiany stanu pikseli
W naszym przypadku definicja sekwencji sterujących jest wykonywana przez funkcję make_vave_table – listing 4.
List. 4. Tworzenie tablicy definicji sekwencji sterującej
void make_wave_table(void)
void make_wave_table(void) { int frame, num; unsigned char tmp,value; for(frame=0; frame>6)&0x3][frame]; tmp = tmp < < 2; tmp &= 0xfffc; tmp |= wave_end[(num > >4)&0x3][frame]; tmp = tmp < < 2; tmp &= 0xfffc; tmp |= wave_end[(num > >2)&0x3][frame]; tmp = tmp < < 2; tmp &= 0xfffc; tmp |= wave_end[(num)&0x3][frame]; value = 0; value = (tmp < <6) & 0xc0; value += (tmp < <2) & 0x30; value += (tmp > >2) & 0x0c; value += (tmp > >6) & 0x03; wave_end_table[num][frame] = value; } } }
W wyniku działania tej funkcji jest zapisywana dwuwymiarowa tablica vave_end_table o wymiarach 256×12. Procedura wyświetlania całego obrazu jest pokazana na listingu 5. Rozpoczyna się od włączenia zasilania matrycy (procedura EPD_PowerOn()).
List. 5. Procedura wyświetlania całego obrazu
void EPD_Display_PIC(void) { int line, frame; bool led_flag = TRUE; unsigned char *ptr; EPD_PowerOn(); //włączenie zasilania ptr = (unsigned char *)(ac); for(frame=0; frameIlość sekcji zapisu jest określona przez wartość FRAME_END_LEN. W każdej sekcji zapisu najpierw jest wywoływana funkcja EPD_Start_Scan() ustawiająca skanowanie linii na początek, czyli od aktywnego sygnału na linii G0. Potem program wywołuje 600 razy w pętli funkcję line_end_pic – listing 6.