{"id":1616,"date":"2020-08-05T20:00:00","date_gmt":"2020-08-05T18:00:00","guid":{"rendered":"http:\/\/msalamon.pl\/?p=1616"},"modified":"2020-09-03T10:23:39","modified_gmt":"2020-09-03T08:23:39","slug":"oled-ze-skala-szarosci-na-ssd1327-cz-2","status":"publish","type":"post","link":"https:\/\/msalamon.pl\/oled-ze-skala-szarosci-na-ssd1327-cz-2\/","title":{"rendered":"OLED ze skal\u0105 szaro\u015bci na SSD1327 cz.2"},"content":{"rendered":"
Ostatnio poteoretyzowa\u0142em na temat OLEDa z 16-stopniow\u0105 skal\u0105 szaro\u015bci.<\/a> Wiemy ju\u017c jak uzyskiwane jest tych 16 kolor\u00f3w oraz jak zorganizowana jest pami\u0119\u0107 RAM wy\u015bwietlacza. Pora wy\u015bwietli\u0107 co\u015b na nim, co nie? Spr\u00f3bujemy w pierwszej kolejno\u015bci u\u017cy\u0107 biblioteki graficznej od zwyk\u0142ego monochromatycznego OLEDa, kt\u00f3rej u\u017cywa\u0142em do SSD1306<\/a>. Do dzie\u0142a!<\/p>\n <\/p>\n Taki OLED ze skal\u0105 szaro\u015bci mo\u017cesz kupi\u0107 u mnie.<\/a><\/strong><\/a><\/p>\n Spis tre\u015bci ca\u0142ego cyklu o OLED na SSD1327:<\/strong><\/span><\/p>\n OLED ze skal\u0105 szaro\u015bci na SSD1327 cz.1<\/a> Do dzisiejszego projektu wykorzysta\u0142em Nucleo F401RE<\/a>.<\/p>\n Takie Nucleo kupisz u mnie w sklepie.<\/a><\/strong><\/span><\/p>\n Wersje u\u017cytych program\u00f3w:<\/p>\n Pod\u0142\u0105czenie jest tak proste, \u017ce nie b\u0119d\u0119 rysowa\u0142. Ja si\u0119 wpi\u0105\u0142em do I\u00b2C1 z przekierowanymi pinami na te ze z\u0142\u0105cza Arduino.<\/p>\n I\u00b2C1 p\u00f3ki co pozostawi\u0142em w domy\u015blnej konfiguracji 100 kHz. Przyjdzie p\u00f3\u017aniej czas na zmiany i por\u00f3wnania.<\/p>\n Pocz\u0105tkowo chcia\u0142em napisa\u0107 samemu procedur\u0119 inicjalizacji. Przecie\u017c to tylko kilka rejestr\u00f3w i maj\u0105c dokumentacj\u0119 mo\u017cna osi\u0105gn\u0105\u0107 pr\u0119dzej czy p\u00f3\u017aniej zadowalaj\u0105cy rezultat. No w\u0142a\u015bnie… p\u00f3\u017aniej. Chwil\u0119 si\u0119 pog\u0142owi\u0142em i zorientowa\u0142em si\u0119, \u017ce kontroler z pixelami po\u0142\u0105czony jest w dosy\u0107 nieoczywisty spos\u00f3b. Pierwsze co mnie spotka\u0142o, to domy\u015blne wy\u015bwietlanie obrazu do g\u00f3ry nogami, ale to by\u0142o dosy\u0107 proste do zrobienia.<\/p>\n Dopiero p\u00f3\u017aniej zauwa\u017cy\u0142em, \u017ce pixele s\u0105 nieco poprzesuwane… Walczy\u0142em dobre 10 minut, a\u017c stwierdzi\u0142em, \u017ce si\u0119 poddaj\u0119. Zacz\u0105\u0142em szuka\u0107 w Internecie jakiego\u015b gotowego kodu, z kt\u00f3rego m\u00f3g\u0142bym zaci\u0105gn\u0105\u0107 procedur\u0119 inicjalizacji.<\/p>\n Pami\u0119taj, \u017ce nie ma nic z\u0142ego w posi\u0142kowaniu si\u0119 gotowcami, je\u015bli wiemy co one robi\u0105 i do czego mog\u0105 nam pos\u0142u\u017cy\u0107.<\/strong> Cz\u0119sto nie ma sensu wymy\u015bla\u0107 ko\u0142a na nowo. Po to zazwyczaj producenci udost\u0119pniaj\u0105 kod demonstracyjny, aby korzysta\u0107. No w\u0142a\u015bnie – producenci. Niestety przy takim OLED firm <\/a>No Name<\/a> <\/em> mo\u017cemy nie znale\u017a\u0107 kodu producenta. Posi\u0142kowa\u0107 si\u0119 trzeba np. bibliotekami Arduino.<\/p>\n Jakie ogromne by\u0142o moje zdziwienie, gdy zobaczy\u0142em, \u017ce ten OLED<\/a> nie jest jako\u015b popularny w\u015br\u00f3d Arduinowc\u00f3w! Na szcz\u0119\u015bcie biblioteka u8g2<\/a> ma zaszyte w sobie inicjalizacje do tych OLED\u00f3w.<\/a> Co prawda troch\u0119 enignatycznie napisane, ale da\u0142em rad\u0119 rozszyfrowa\u0107 to na ludzki j\u0119zyk. Wzi\u0105\u0142em wi\u0119c libk\u0119, przepisa\u0142em i… zadzia\u0142a\u0142o. Dzi\u0119ki koledzy od Arduino za pomoc! \ud83d\ude42<\/p>\n Swoj\u0105 drog\u0105 spr\u00f3bowa\u0142bym uruchomi\u0107 kiedy\u015b t\u0119 bibliotek\u0119 na STM32 pod HALem. Co Ty na co? Daj zna\u0107 w komentarzu!<\/strong><\/p>\n Komendy samego kontrolera SSD1327 s\u0105 bardzo podobne do tych z SSD1306, wi\u0119c zachowa\u0142em konwencj\u0119 pisania biblioteki. Dzi\u0119ki temu sporo pracy mi odpad\u0142o. Tak wygl\u0105da sama inizjalizacja.<\/p>\n Po uruchomieniu tego kodu na wy\u015bwietlaczu pojawia si\u0119… galaktyka!<\/p>\n <\/a>Je\u015bli jeszcze nie wiesz sk\u0105d ona si\u0119 bierze to ju\u017c t\u0142umacz\u0119. Pami\u0119\u0107 RAM ma to do siebie, \u017ce po podaniu napi\u0119cia wszystkie kom\u00f3rki ustawiaj\u0105 si\u0119 w “losowe” warto\u015bci. Jako \u017ce RAM odzwierciedla to, co jest widoczne na wy\u015bwietlaczu, st\u0105d mamy taki obraz.<\/strong> Wystarczy wi\u0119c wyczy\u015bci\u0107 ten RAM, aby by\u0142o jednolicie – np. zgasi\u0107 wszystkie piksele.<\/p>\n W poprzednim wpisie<\/a> zaznaczy\u0142em ma\u0142y problem z ustawianiem koloru pojedynczego w tym wy\u015bwietlaczu. Polega on na tym, \u017ce w jednym bajcie RAM trzymana jest informacja o dw\u00f3ch s\u0105siaduj\u0105cych pikselach. <\/strong>St\u0105d dobrym rozwi\u0105zaniem b\u0119dzie buforowanie takiego obrazu.<\/p>\n Bufor jaki b\u0119dzie trzymany w pami\u0119ci mikrokontrolera ma rozmiar (128 * 96) \/ 2 bajt\u00f3w.<\/strong> <\/p>\n Teraz pomy\u015blmy jak ustawi\u0107 pojedynczy piksel w takin buforze. Wiemy, \u017ce kolejne piksele A i B s\u0105 trzymane w bajcie w ten spos\u00f3b: 0xAB. Jak wi\u0119c wskaza\u0107 poprawn\u0105 po\u0142\u00f3wk\u0119 bajtu dla piksela? Mo\u017cna przyk\u0142adowo u\u017cy\u0107 operacji modulo. Wtedy parzyste (plus zerowy) piksele zaadresujemy do jednej po\u0142\u00f3wki, a nieparzyste do drugiej.<\/p>\n Dochodzi jeszcze maskowanie tych pikseli, kt\u00f3rych nie chcemy modyfikowa\u0107 w buforze oraz wyb\u00f3r kom\u00f3rki bufora. Maskowanie po\u0142owy bajtu jest dosy\u0107 oczywiste. Jak wi\u0119c znale\u017a\u0107 t\u0105 odpowiedni\u0105 kom\u00f3rk\u0119 w tablicy bufora? Na podstawie wsp\u00f3\u0142rz\u0119dnych tego piksela, czyli X i Y.<\/p>\n X jest to pozycja w poziomie, Y w pionie. Wy\u015bwietlacz skanujemy od lewej do prawej po ka\u017cdej linii schodz\u0105c w d\u00f3\u0142. Je\u015bli mieliby\u015bmy wybra\u0107 kom\u00f3rk\u0119 tablicy tylko dla wiersza zerowego, obliczanie wygl\u0105da\u0142oby tak: buffer[X\/2]<\/strong>. Dla piksela nr 0 i 1 b\u0119dzie to buffer[0]. Dalsze r\u00f3wnie\u017c si\u0119 zgadzaj\u0105.<\/p>\n Jak doda\u0107 wi\u0119c numer wiersza? Nale\u017cy przesun\u0105\u0107 numer kom\u00f3rki o ilo\u015b\u0107 bajt\u00f3w dla pe\u0142nych linii, kt\u00f3re s\u0105 przed danym Y. Do tego potrzebna jest informacja o szeroko\u015bci wy\u015bwietlacza.<\/p>\n Ilo\u015b\u0107 bajt\u00f3w dla pe\u0142nych linii poprzedzaj\u0105cych t\u0105 wybran\u0105 o numerze Y, to Y*(SSD1327_LCDWIDTH\/2).<\/strong><\/p>\n Skoro trzeba doda\u0107, to wyb\u00f3r kom\u00f3rki bufora w ca\u0142o\u015bci wygl\u0105da tak.<\/p>\n uint8_t SelectedCell = buffer[X\/2 + Y*(SSD1327_LCDWIDTH\/2)];<\/strong><\/p>\n Sk\u0142adaj\u0105c te informacje do kupy wychodzi nam co powinna zawiera\u0107 funkcja rusyj\u0105ca pojedynczy piksel na buforze.<\/p>\n To, z kt\u00f3rej strony w tym bajcie ma by\u0107 m\u0142odszy piksel determinuje inicjalizacja. Jest tam rejestr z wyborem, gdzie idzie starszy z punkt\u00f3w. Sprawdzi\u0142em to empirycznie i wed\u0142ug wynik\u00f3w bada\u0144 dla mojej inicjalizacji powy\u017cszy kod jest prawdziwy.<\/p>\n Teraz trzeba to przes\u0142a\u0107 do OLED.<\/strong><\/p>\n SSD1327 r\u00f3\u017cni si\u0119 od SSD1306 tym, \u017ce nie ma stronicowania pami\u0119ci RAM. Nie musimy si\u0119 wi\u0119c martwi\u0107 o to, czy inicjalizacja w\u0142\u0105czy\u0142a to stronicowanie. Mamy wi\u0119c ca\u0142y czas dost\u0119p co ca\u0142ej pami\u0119ci RAM.<\/p>\n Wystarczy ustawi\u0107 wska\u017anik pisania po RAM na sam pocz\u0105tek i wypchn\u0105\u0107 ca\u0142y bufor. Tyle!<\/p>\n Dopiszmy jeszcze na szybko funkcj\u0119 czyszcz\u0105c\u0105 ca\u0142y ekran(bufor) na wybrany kolor. Trzeba ca\u0142y czas pami\u0119ta\u0107 o tym jak s\u0105 zapisywane piksele.<\/strong><\/p>\n Sprawd\u017amy dzia\u0142anie! Wszystkie zdj\u0119cia by\u0142y zrobione przy sta\u0142ych ustawieniach aparatu.<\/strong><\/p>\n Kolor: 15 (max). Biel.<\/p>\n <\/a><\/p>\n Kolor 7 (\u015brodek). No jest szaro.<\/p>\n <\/a><\/p>\n Kolor 2 (prawie czer\u0144). Tu ju\u017c prawie nic nie wida\u0107, ale uwierz mi, \u017ce lekka po\u015bwiata jest widoczna \ud83d\ude42<\/strong> To b\u0119dzie fajnie widoczne np. na zdj\u0119ciach.<\/p>\n Mo\u017cna u\u017cy\u0107 biblioteki, kt\u00f3ra jest dla wy\u015bwietlaczy monochromatycznych. Wystarczy do nag\u0142\u00f3wka dopi\u0105\u0107 funkcj\u0119 rysuj\u0105c\u0105 piksel oraz wymiary wy\u015bwietlacza.<\/p>\n Wtedy napisy czy figury dzia\u0142aj\u0105 bardzo dobrze. Tu przyk\u0142ad z rysowaniem prostok\u0105t\u00f3w we wszystkich kolorach.<\/p>\n <\/a><\/p>\n Niestety domy\u015blnie nie b\u0119dzie dzia\u0142a\u0142o rysowanie obraz\u00f3w. Niestety bibliotek\u0119 t\u0105 napisa\u0142em tak, \u017ce przyjmuje ona tylko dwa kolory – bia\u0142y i czarny. W ko\u0144cu jest BW \ud83d\ude42<\/strong><\/p>\n Do generowania i rysowania obraz\u00f3w przejd\u0119 w kolejnych wpisach. Dla ma\u0142ej zajawki tak prezentuje si\u0119 logo msalamon.pl czy zdj\u0119cie – np. m\u00f3j kot.<\/a><\/p>\n <\/a><\/p>\n Organizacja pikseli mo\u017ce da\u0107 troch\u0119 do pomy\u015blenia, ale je\u015bli pomy\u015blisz raz, a dobrze to ju\u017c nigdy wi\u0119cej nie musisz. Pami\u0119taj, aby pisz\u0105c kod pisa\u0107 go w taki spos\u00f3b, aby pomaga\u0142 on na p\u00f3\u017aniejszych etapach pisania aplikacji.<\/p>\n Nie b\u00f3j si\u0119 r\u00f3wnierz szuka\u0107 w Internecie i korzysta\u0107 z pracy innych. Miej tylko \u015bwiadomo\u015b\u0107 co cudzy kod robi \ud83d\ude42<\/p>\n W kolejnym wpisie poka\u017c\u0119 Ci z jakigo programu korzystam do generowania bitmap dla mikrokontroler\u00f3w. Jest to w 100% darmowy program i potrafi naprawd\u0119 wiele!<\/p>\n P\u00f3\u017aniej takie obrazy wrzucimy na mikrokontroler, a docelowo na wy\u015bwietlacz.<\/p>\n Je\u015bli artyku\u0142 Ci si\u0119 spodoba\u0142, kup co\u015b u mnie! \ud83d\ude42 https:\/\/sklep.msalamon.pl\/<\/a><\/strong><\/p>\n Pe\u0142ny projekt wraz z bibliotek\u0105 znajdziesz jak zwykle na moim GitHubie: LINK<\/a><\/p>\n Je\u015bli zauwa\u017cy\u0142e\u015b jaki\u015b b\u0142\u0105d, nie zgadzasz si\u0119 z czym\u015b, chcia\u0142by\u015b co\u015b doda\u0107 istotnego lub po prostu uwa\u017casz, \u017ce chcia\u0142by\u015b podyskutowa\u0107 na ten temat, napisz komentarz. Pami\u0119taj, \u017ce dyskusja ma by\u0107 kulturalna i zgodna z zasadami j\u0119zyka polskiego.<\/span><\/p>\n Spis tre\u015bci ca\u0142ego cyklu o OLED na SSD1327:<\/strong><\/span><\/p>\n OLED ze skal\u0105 szaro\u015bci na SSD1327 cz.1<\/a>
\n<\/strong>OLED ze skal\u0105 szaro\u015bci na SSD1327 cz.2<\/a>
\n<\/strong>Jak przygotowa\u0107 obraz dla wy\u015bwietlacza LCD lub TFT?<\/a>
\n<\/strong>OLED ze skal\u0105 szaro\u015bci na SSD1327 cz.3<\/a><\/strong><\/p>\nPod\u0142\u0105czenie i Cube<\/h1>\n
\n
Inicjalizacja OLED SSD1327<\/h1>\n
void SSD1327_Init(void)\r\n{\r\n\tSSD1327_Command(SSD1327_DISPLAYOFF); \/\/ Display Off\r\n\r\n\tSSD1327_Command(SSD1327_SETMULTIPLEX);\r\n\tSSD1327_Command(0x5F);\r\n\r\n\tSSD1327_Command(SSD1327_SETDISPLAYSTARTLINE);\r\n\tSSD1327_Command(0x00);\r\n\r\n\tSSD1327_Command(SSD1327_SETDISPLAYOFFSET);\r\n\tSSD1327_Command(0x20);\r\n\r\n\tSSD1327_Command(SSD1327_SEGREMAP);\r\n\tSSD1327_Command(0x51);\r\n\r\n\tSSD1327_SetContrast(0x7F);\r\n\r\n\tSSD1327_Command(SSD1327_SETPHASELENGTH);\r\n\tSSD1327_Command(0x22);\r\n\r\n\tSSD1327_Command(SSD1327_SETFRONTCLOCKDIVIDER_OSCILLATORFREQUENCY);\r\n\tSSD1327_Command(0x50);\r\n\r\n\tSSD1327_Command(SSD1327_SELECTDEFAULTLINEARGRAYSCALETABLE);\r\n\r\n\tSSD1327_Command(SSD1327_SETPRECHARGEVOLTAGE);\r\n\tSSD1327_Command(0x10);\r\n\r\n\tSSD1327_Command(SSD1327_SETSETVCOMVOLTAGE);\r\n\tSSD1327_Command(0x05);\r\n\r\n\tSSD1327_Command(SSD1327_SETSECONDPRECHARGEPERTIOD);\r\n\tSSD1327_Command(0x0a);\r\n\r\n\tSSD1327_Command(SSD1327_FUNCTIONSELECTIONB);\r\n\tSSD1327_Command(0x62);\r\n\r\n\tSSD1327_Command(SSD1327_SETCOLUMNADDRESS);\r\n\tSSD1327_Command(0x00);\r\n\tSSD1327_Command(0x3F);\r\n\r\n\tSSD1327_Command(SSD1327_SETROWADDRESS);\r\n\tSSD1327_Command(0x00);\r\n\tSSD1327_Command(0x5F);\r\n\r\n\tSSD1327_Command(SSD1327_NORMALDISPLAY); \/\/ Set Normal Display\r\n\r\n\tSSD1327_Command(SSD1327_DISPLAYALLON_RESUME); \/\/ Entire Display ON\r\n\r\n#if GRAPHIC_ACCELERATION_COMMANDS == 1\r\n\tSSD1327_StopScroll();\r\n#endif\r\n\tSSD1327_DisplayON(1);\r\n}<\/pre>\n
Buforowanie, ustawianie piksela i transfer do RAM wy\u015bwietlacza<\/h2>\n
#define SSD1327_BUFFERSIZE\t(SSD1327_LCDHEIGHT * SSD1327_LCDWIDTH \/ 2)\r\nstatic uint8_t buffer[SSD1327_BUFFERSIZE];<\/pre>\n
\/\/\r\n\/\/ Draw pixel in the buffer\r\n\/\/\r\nvoid SSD1327_DrawPixel(int16_t x, int16_t y, uint8_t Color)\r\n{\r\n\t if ((x < 0) || (x >= SSD1327_LCDWIDTH) || (y < 0) || (y >= SSD1327_LCDHEIGHT))\r\n\t\t return;\r\n\r\n\t uint8_t SelectedCell = buffer[x\/2 + y*(SSD1327_LCDWIDTH\/2)];\r\n\r\n\t if(x % 2)\r\n\t {\r\n\t\t SelectedCell &= ~(0x0F);\r\n\t\t SelectedCell |= (0x0F & Color);\r\n\t }\r\n\t else\r\n\t {\r\n\t\t SelectedCell &= ~(0xF0);\r\n\t\t SelectedCell |= (0xF0 & (Color<<4));\r\n\t }\r\n\r\n\t buffer[x\/2 + y*(SSD1327_LCDWIDTH\/2)] = SelectedCell;\r\n}<\/pre>\n
\/\/\r\n\/\/ Send buffer to OLDE GCRAM\r\n\/\/\r\nvoid SSD1327_Display(void)\r\n{\r\n\tSSD1327_Command(SSD1327_SETCOLUMNADDRESS);\r\n\tSSD1327_Command(0x00);\r\n\tSSD1327_Command(0x3F);\r\n\r\n\tSSD1327_Command(SSD1327_SETROWADDRESS);\r\n\tSSD1327_Command(0x00);\r\n\tSSD1327_Command(0x5F);\r\n\r\n\tHAL_I2C_Mem_Write(ssd1337_i2c, SSD1327_I2C_ADDRESS, 0x40, 1, (uint8_t*)&buffer, SSD1327_BUFFERSIZE, 1000);\r\n}<\/pre>\n
\/\/\r\n\/\/ Clear the buffer\r\n\/\/\r\nvoid SSD1327_Clear(uint8_t Color)\r\n{\r\n\tif(Color > WHITE) Color = WHITE;\r\n\r\n\tmemset(buffer, (Color << 4 | Color), SSD1327_BUFFERSIZE);\r\n}<\/pre>\n
<\/a>Biblioteka GFX<\/h2>\n
#define GFX_DrawPixel(x,y,color) SSD1327_DrawPixel(x,y,color)\r\n#define WIDTH SSD1327_LCDWIDTH\r\n#define HEIGHT SSD1327_LCDHEIGHT\r\n#define PIXEL_BLACK\tBLACK\r\n#define PIXEL_WHITE\tWHITE\r\n#define PIXEL_INVERSE\tINVERSE<\/pre>\n
<\/a>Podsumowanie<\/h2>\n
\n<\/strong>OLED ze skal\u0105 szaro\u015bci na SSD1327 cz.2<\/a>
\n<\/strong>Jak przygotowa\u0107 obraz dla wy\u015bwietlacza LCD lub TFT?<\/a>
\n<\/strong>OLED ze skal\u0105 szaro\u015bci na SSD1327 cz.3<\/a><\/strong><\/p>\n\n\n