SSD1306 OLED display driver  1.7.6
This library is developed to control SSD1306/SSD1331/SSD1351/IL9163/PCD8554 RGB i2c/spi LED displays
lcd_il9163.c
1 /*
2  MIT License
3 
4  Copyright (c) 2018, Alexey Dynda
5 
6  Permission is hereby granted, free of charge, to any person obtaining a copy
7  of this software and associated documentation files (the "Software"), to deal
8  in the Software without restriction, including without limitation the rights
9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  copies of the Software, and to permit persons to whom the Software is
11  furnished to do so, subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in all
14  copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  SOFTWARE.
23 */
24 
25 #include "lcd_il9163.h"
26 #include "lcd_common.h"
27 #include "intf/ssd1306_interface.h"
28 #include "intf/spi/ssd1306_spi.h"
29 #include "ssd1306_hal/io.h"
30 #include "nano_gfx_types.h"
31 #ifdef SDL_EMULATION
32 #include "sdl_core.h"
33 #endif
34 
35 #define CMD_ARG 0xFF
36 
37 extern uint16_t ssd1306_color;
38 extern uint32_t s_ssd1306_spi_clock;
39 
40 static uint8_t s_rotation = 0x00;
41 static uint8_t s_rgb_bit = 0b00001000;
42 
43 static const PROGMEM uint8_t s_oled128x128_initData[] =
44 {
45 #ifdef SDL_EMULATION
46  SDL_LCD_IL9163,
47  0x00,
48 #endif
49 // 0x01, // sw reset. not needed, we do hardware reset
50  0x11, // exit sleep mode
51  0x3A, CMD_ARG, 0x05, // set 16-bit pixel format
52  0x26, CMD_ARG, 0x04, // set gamma curve: valid values 1, 2, 4, 8
53 // 0xF2, CMD_ARG, 0x01, // enable gamma adjustment, 0 - to disable
54 // 0xE0, CMD_ARG, 0x3F, CMD_ARG, 0x25, CMD_ARG, 0x1C,
55 // CMD_ARG, 0x1E, CMD_ARG, 0x20, CMD_ARG, 0x12,
56 // CMD_ARG, 0x2A, CMD_ARG, 0x90, CMD_ARG, 0x24,
57 // CMD_ARG, 0x11, CMD_ARG, 0x00, CMD_ARG, 0x00,
58 // CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, // positive gamma correction
59 // 0xE1, CMD_ARG, 0x20, CMD_ARG, 0x20, CMD_ARG, 0x20,
60 // CMD_ARG, 0x20, CMD_ARG, 0x05, CMD_ARG, 0x00,
61 // CMD_ARG, 0x15, CMD_ARG, 0xA7, CMD_ARG, 0x3D,
62 // CMD_ARG, 0x18, CMD_ARG, 0x25, CMD_ARG, 0x2A,
63 // CMD_ARG, 0x2B, CMD_ARG, 0x2B, CMD_ARG, 0x3A, // negative gamma correction
64 // 0xB1, CMD_ARG, 0x08, CMD_ARG, 0x08, // frame rate control 1, use by default
65 // 0xB4, CMD_ARG, 0x07, // display inversion, use by default
66  0xC0, CMD_ARG, 0x0A, CMD_ARG, 0x02, // power control 1
67  0xC1, CMD_ARG, 0x02, // power control 2
68  0xC5, CMD_ARG, 0x50, CMD_ARG, 0x5B, // vcom control 1
69  0xC7, CMD_ARG, 0x40, // vcom offset
70 // 0x2A, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x7F, // set column address, not needed. set by direct API
71 // 0x2B, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x9F, // set page address, not needed. set by direct API
72  0x36, CMD_ARG, 0b00101000, // enable fake "vertical addressing" mode (for il9163_setBlock() )
73  0x29, // display on
74 };
75 
76 static const PROGMEM uint8_t s_oled128x160_initData[] =
77 {
78 #ifdef SDL_EMULATION
79  SDL_LCD_ST7735,
80  0x00,
81 #endif
82 // 0x01, // sw reset. not needed, we do hardware reset
83  0x11, // exit sleep mode
84 // 0x28, // display off
85  0x3A, CMD_ARG, 0x05, // set 16-bit pixel format
86  0x26, CMD_ARG, 0x04, // set gamma curve: valid values 1, 2, 4, 8
87  0xF2, CMD_ARG, 0x01, // enable gamma adjustment, 0 - to disable
88  0xE0, CMD_ARG, 0x3F, CMD_ARG, 0x25, CMD_ARG, 0x1C,
89  CMD_ARG, 0x1E, CMD_ARG, 0x20, CMD_ARG, 0x12,
90  CMD_ARG, 0x2A, CMD_ARG, 0x90, CMD_ARG, 0x24,
91  CMD_ARG, 0x11, CMD_ARG, 0x00, CMD_ARG, 0x00,
92  CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, // positive gamma correction
93  0xE1, CMD_ARG, 0x20, CMD_ARG, 0x20, CMD_ARG, 0x20,
94  CMD_ARG, 0x20, CMD_ARG, 0x05, CMD_ARG, 0x00,
95  CMD_ARG, 0x15, CMD_ARG, 0xA7, CMD_ARG, 0x3D,
96  CMD_ARG, 0x18, CMD_ARG, 0x25, CMD_ARG, 0x2A,
97  CMD_ARG, 0x2B, CMD_ARG, 0x2B, CMD_ARG, 0x3A, // negative gamma correction
98  0xB1, CMD_ARG, 0x08, CMD_ARG, 0x08, // frame rate control 1, use by default
99  0xB4, CMD_ARG, 0x07, // display inversion, use by default
100  0xC0, CMD_ARG, 0x0A, CMD_ARG, 0x02, // power control 1
101  0xC1, CMD_ARG, 0x02, // power control 2
102  0xC5, CMD_ARG, 0x50, CMD_ARG, 0x5B, // vcom control 1
103  0xC7, CMD_ARG, 0x40, // vcom offset
104 // 0x2A, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x7F, // set column address, not needed. set by direct API
105 // 0x2B, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x9F, // set page address, not needed. set by direct API
106  0x36, CMD_ARG, 0b00100000, // enable fake "vertical addressing" mode (for il9163_setBlock() )
107  0x29, // display on
108 };
109 
110 static uint8_t s_column;
111 static uint8_t s_page;
112 
113 static void il9163_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
114 {
115  uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
116  s_column = x;
117  s_page = y;
120  ssd1306_intf.send(0x2B);
121  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
122  ssd1306_intf.send(0);
123  ssd1306_intf.send(x + (s_rotation == 3 ? 32 : 0));
124  ssd1306_intf.send(0);
125  ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1))
126  + (s_rotation == 3 ? 32 : 0));
128  ssd1306_intf.send(0x2A);
129  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
130  ssd1306_intf.send(0);
131  ssd1306_intf.send((y<<3) + (s_rotation == 2 ? 32: 0));
132  ssd1306_intf.send(0);
133  ssd1306_intf.send((((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1))
134  + (s_rotation == 2 ? 32: 0));
136  ssd1306_intf.send(0x2C);
138 }
139 
140 static void il9163_setBlock2(lcduint_t x, lcduint_t y, lcduint_t w)
141 {
142  uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
145  ssd1306_intf.send(0x2A);
146  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
147  ssd1306_intf.send(0);
148  ssd1306_intf.send(x + (s_rotation == 7 ? 32 : 0));
149  ssd1306_intf.send(0);
150  ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1))
151  + (s_rotation == 7 ? 32 : 0));
153  ssd1306_intf.send(0x2B);
154  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
155  ssd1306_intf.send(0);
156  ssd1306_intf.send(y + (s_rotation == 6 ? 32: 0));
157  ssd1306_intf.send(0);
158  ssd1306_intf.send(ssd1306_lcd.height - 1 + (s_rotation == 6 ? 32: 0));
160  ssd1306_intf.send(0x2C);
162 }
163 
164 static void il9163_nextPage(void)
165 {
166  ssd1306_intf.stop();
167  ssd1306_lcd.set_block(s_column,s_page+1,0);
168 }
169 
170 static void il9163_nextPage2(void)
171 {
172 }
173 
175 {
178  ssd1306_intf.send( 0x36 );
180  ssd1306_intf.send( mode ? 0b00101000 : 0b00001000 );
181  ssd1306_intf.stop();
182  if (mode)
183  {
184  ssd1306_lcd.set_block = il9163_setBlock;
185  ssd1306_lcd.next_page = il9163_nextPage;
186  }
187  else
188  {
189  ssd1306_lcd.set_block = il9163_setBlock2;
190  ssd1306_lcd.next_page = il9163_nextPage2;
191  }
192  s_rotation = mode ? 0x00 : 0x04;
193 }
194 
195 static void il9163_sendPixels(uint8_t data)
196 {
197  for (uint8_t i=8; i>0; i--)
198  {
199  if ( data & 0x01 )
200  {
201  ssd1306_intf.send( (uint8_t)(ssd1306_color>>8) );
202  ssd1306_intf.send( (uint8_t)(ssd1306_color) );
203  }
204  else
205  {
206  ssd1306_intf.send( 0B00000000 );
207  ssd1306_intf.send( 0B00000000 );
208  }
209  data >>= 1;
210  }
211 }
212 
213 static void il9163_sendPixelsBuffer(const uint8_t *buffer, uint16_t len)
214 {
215  while(len--)
216  {
217  il9163_sendPixels(*buffer);
218  buffer++;
219  }
220 }
221 
222 static void il9163_sendPixel8(uint8_t data)
223 {
224  uint16_t color = RGB8_TO_RGB16(data);
225  ssd1306_intf.send( color >> 8 );
226  ssd1306_intf.send( color & 0xFF );
227 }
228 
230 {
232  ssd1306_lcd.height = 128;
233  ssd1306_lcd.width = 128;
234  s_rgb_bit = 0b00001000; // set BGR mode mapping
235  ssd1306_lcd.set_block = il9163_setBlock;
236  ssd1306_lcd.next_page = il9163_nextPage;
237  ssd1306_lcd.send_pixels1 = il9163_sendPixels;
238  ssd1306_lcd.send_pixels_buffer1 = il9163_sendPixelsBuffer;
239  ssd1306_lcd.send_pixels8 = il9163_sendPixel8;
241  ssd1306_configureSpiDisplay(s_oled128x128_initData, sizeof(s_oled128x128_initData));
242 }
243 
244 void il9163_128x128_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
245 {
246  if (rstPin >=0)
247  {
248  pinMode(rstPin, OUTPUT);
249  digitalWrite(rstPin, HIGH);
250  /* Wait at least 1ms after VCC is up for LCD */
251  delay(1);
252  /* Perform reset operation of LCD display */
253  digitalWrite(rstPin, LOW);
254  delay(20);
255  digitalWrite(rstPin, HIGH);
256  }
257  /* ssd1351 cannot work faster than at 4MHz per datasheet */
258  s_ssd1306_spi_clock = 8000000;
259  ssd1306_spiInit(cesPin, dcPin);
261 }
262 
263 void il9163_setRotation(uint8_t rotation)
264 {
265  uint8_t ram_mode;
266  if ((rotation^s_rotation) & 0x01)
267  {
268  uint16_t t = ssd1306_lcd.width;
270  ssd1306_lcd.height = t;
271  }
272  s_rotation = (rotation & 0x03) | (s_rotation & 0x04);
275  ssd1306_intf.send(0x28);
276  ssd1306_intf.send(0x36);
278  switch (s_rotation)
279  {
280  case 0:
281  ram_mode = 0b00100000;
282  break;
283  case 1: // 90 degree CW
284  ram_mode = 0b01000000;
285  break;
286  case 2: // 180 degree CW
287  ram_mode = 0b11100000;
288  break;
289  case 3: // 270 degree CW
290  ram_mode = 0b10000000;
291  break;
292  case 4:
293  ram_mode = 0b00000000;
294  break;
295  case 5: // 90 degree CW
296  ram_mode = 0b01100000;
297  break;
298  case 6: // 180 degree CW
299  ram_mode = 0b11000000;
300  break;
301  default: // 270 degree CW
302  ram_mode = 0b10100000;
303  break;
304  }
305  ssd1306_intf.send( ram_mode | s_rgb_bit );
307  ssd1306_intf.send(0x29);
308  ssd1306_intf.stop();
309 }
310 
312 // ST7735 support
314 
315 static void st7735_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
316 {
317  uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
318  s_column = x;
319  s_page = y;
322  ssd1306_intf.send(0x2B);
323  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
324  ssd1306_intf.send(0);
325  ssd1306_intf.send(x);
326  ssd1306_intf.send(0);
327  ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)));
329  ssd1306_intf.send(0x2A);
330  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
331  ssd1306_intf.send(0);
332  ssd1306_intf.send((y<<3));
333  ssd1306_intf.send(0);
334  ssd1306_intf.send((((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1)));
336  ssd1306_intf.send(0x2C);
338 }
339 
340 #if 0
341 static void st7735_setBlock2(lcduint_t x, lcduint_t y, lcduint_t w)
342 {
343  uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
346  ssd1306_intf.send(0x2A);
347  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
348  ssd1306_intf.send(0);
349  ssd1306_intf.send(x);
350  ssd1306_intf.send(0);
351  ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)));
353  ssd1306_intf.send(0x2B);
354  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
355  ssd1306_intf.send(0);
356  ssd1306_intf.send(y);
357  ssd1306_intf.send(0);
360  ssd1306_intf.send(0x2C);
362 }
363 #endif
364 
366 {
368  ssd1306_lcd.width = 128;
369  ssd1306_lcd.height = 160;
370  s_rgb_bit = 0b00000000; // set RGB mode mapping
371  ssd1306_lcd.set_block = st7735_setBlock;
372  ssd1306_lcd.next_page = il9163_nextPage;
373  ssd1306_lcd.send_pixels1 = il9163_sendPixels;
374  ssd1306_lcd.send_pixels_buffer1 = il9163_sendPixelsBuffer;
375  ssd1306_lcd.send_pixels8 = il9163_sendPixel8;
377  ssd1306_configureSpiDisplay(s_oled128x160_initData, sizeof(s_oled128x160_initData));
378 }
379 
380 void st7735_128x160_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
381 {
382  if (rstPin >=0)
383  {
384  ssd1306_resetController( rstPin, 20 );
385  /* Give 120ms display to initialize */
386  delay(120);
387  }
388  /* ssd1351 cannot work faster than at 4MHz per datasheet */
389  s_ssd1306_spi_clock = 8000000;
390  ssd1306_spiInit(cesPin, dcPin);
392 }
void st7735_128x160_init(void)
Inits 128x160 RGB OLED display (based on st7735 controller).
Definition: lcd_il9163.c:365
void ssd1306_configureSpiDisplay(const uint8_t *config, uint8_t configSize)
Sends configuration being passed to lcd display spi controller.
Definition: lcd_common.c:52
void st7735_128x160_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
Inits 128x160 RGB TFT display over spi (based on st7735 controller).
Definition: lcd_il9163.c:380
void(* send)(uint8_t data)
uint32_t s_ssd1306_spi_clock
Definition: ssd1306_spi.c:35
void(* set_block)(lcduint_t x, lcduint_t y, lcduint_t w)
Sets block in RAM of lcd display controller to write data to.
Definition: lcd_common.h:114
void(* send_pixels8)(uint8_t data)
Sends RGB pixel encoded in 3-3-2 format to OLED driver. Sends RGB pixel encoded in 3-3-2 format to OL...
Definition: lcd_common.h:142
void ssd1306_spiDataMode(uint8_t mode)
Definition: ssd1306_spi.c:50
lcd_mode_t
Definition: lcd_common.h:69
void(* send_pixels_buffer1)(const uint8_t *buffer, uint16_t len)
Definition: lcd_common.h:135
void ssd1306_resetController(int8_t rstPin, uint8_t delayMs)
Does hardware reset for oled controller.
Definition: lcd_common.c:82
void(* send_pixels1)(uint8_t data)
Definition: lcd_common.h:128
void il9163_setRotation(uint8_t rotation)
Sets screen orientation (rotation)
Definition: lcd_il9163.c:263
void il9163_128x128_init(void)
Inits 128x128 RGB OLED display (based on il9163 controller).
Definition: lcd_il9163.c:229
void ssd1306_spiInit(int8_t cesPin, int8_t dcPin)
Definition: ssd1306_spi.c:37
ssd1306_lcd_t ssd1306_lcd
Definition: lcd_common.c:32
ssd1306_interface_t ssd1306_intf
lcduint_t height
Definition: lcd_common.h:97
void il9163_128x128_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
Inits 128x128 RGB TFT display over spi (based on il9163 controller).
Definition: lcd_il9163.c:244
#define RGB8_TO_RGB16(c)
void(* next_page)(void)
Definition: lcd_common.h:122
lcduint_t width
Definition: lcd_common.h:94
lcd_type_t type
Definition: lcd_common.h:91
void il9163_setMode(lcd_mode_t mode)
Sets GDRAM autoincrement mode.
Definition: lcd_il9163.c:174
void(* set_mode)(lcd_mode_t mode)
Sets library display mode for direct draw functions.
Definition: lcd_common.h:157