SSD1306 OLED display driver  1.6.99
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 
32 #define CMD_ARG 0xFF
33 
34 extern uint16_t ssd1306_color;
35 extern uint32_t s_ssd1306_spi_clock;
36 
37 static uint8_t s_rotation = 0x00;
38 static uint8_t s_rgb_bit = 0b00001000;
39 
40 static const PROGMEM uint8_t s_oled128x128_initData[] =
41 {
42 // 0x01, // sw reset. not needed, we do hardware reset
43  0x11, // exit sleep mode
44  0x3A, CMD_ARG, 0x05, // set 16-bit pixel format
45  0x26, CMD_ARG, 0x04, // set gamma curve: valid values 1, 2, 4, 8
46 // 0xF2, CMD_ARG, 0x01, // enable gamma adjustment, 0 - to disable
47 // 0xE0, CMD_ARG, 0x3F, CMD_ARG, 0x25, CMD_ARG, 0x1C,
48 // CMD_ARG, 0x1E, CMD_ARG, 0x20, CMD_ARG, 0x12,
49 // CMD_ARG, 0x2A, CMD_ARG, 0x90, CMD_ARG, 0x24,
50 // CMD_ARG, 0x11, CMD_ARG, 0x00, CMD_ARG, 0x00,
51 // CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, // positive gamma correction
52 // 0xE1, CMD_ARG, 0x20, CMD_ARG, 0x20, CMD_ARG, 0x20,
53 // CMD_ARG, 0x20, CMD_ARG, 0x05, CMD_ARG, 0x00,
54 // CMD_ARG, 0x15, CMD_ARG, 0xA7, CMD_ARG, 0x3D,
55 // CMD_ARG, 0x18, CMD_ARG, 0x25, CMD_ARG, 0x2A,
56 // CMD_ARG, 0x2B, CMD_ARG, 0x2B, CMD_ARG, 0x3A, // negative gamma correction
57 // 0xB1, CMD_ARG, 0x08, CMD_ARG, 0x08, // frame rate control 1, use by default
58 // 0xB4, CMD_ARG, 0x07, // display inversion, use by default
59  0xC0, CMD_ARG, 0x0A, CMD_ARG, 0x02, // power control 1
60  0xC1, CMD_ARG, 0x02, // power control 2
61  0xC5, CMD_ARG, 0x50, CMD_ARG, 0x5B, // vcom control 1
62  0xC7, CMD_ARG, 0x40, // vcom offset
63 // 0x2A, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x7F, // set column address, not needed. set by direct API
64 // 0x2B, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x9F, // set page address, not needed. set by direct API
65  0x36, CMD_ARG, 0b00101000, // enable fake "vertical addressing" mode (for il9163_setBlock() )
66  0x29, // display on
67 };
68 
69 static const PROGMEM uint8_t s_oled128x160_initData[] =
70 {
71 // 0x01, // sw reset. not needed, we do hardware reset
72  0x11, // exit sleep mode
73 // 0x28, // display off
74  0x3A, CMD_ARG, 0x05, // set 16-bit pixel format
75  0x26, CMD_ARG, 0x04, // set gamma curve: valid values 1, 2, 4, 8
76  0xF2, CMD_ARG, 0x01, // enable gamma adjustment, 0 - to disable
77  0xE0, CMD_ARG, 0x3F, CMD_ARG, 0x25, CMD_ARG, 0x1C,
78  CMD_ARG, 0x1E, CMD_ARG, 0x20, CMD_ARG, 0x12,
79  CMD_ARG, 0x2A, CMD_ARG, 0x90, CMD_ARG, 0x24,
80  CMD_ARG, 0x11, CMD_ARG, 0x00, CMD_ARG, 0x00,
81  CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, // positive gamma correction
82  0xE1, CMD_ARG, 0x20, CMD_ARG, 0x20, CMD_ARG, 0x20,
83  CMD_ARG, 0x20, CMD_ARG, 0x05, CMD_ARG, 0x00,
84  CMD_ARG, 0x15, CMD_ARG, 0xA7, CMD_ARG, 0x3D,
85  CMD_ARG, 0x18, CMD_ARG, 0x25, CMD_ARG, 0x2A,
86  CMD_ARG, 0x2B, CMD_ARG, 0x2B, CMD_ARG, 0x3A, // negative gamma correction
87  0xB1, CMD_ARG, 0x08, CMD_ARG, 0x08, // frame rate control 1, use by default
88  0xB4, CMD_ARG, 0x07, // display inversion, use by default
89  0xC0, CMD_ARG, 0x0A, CMD_ARG, 0x02, // power control 1
90  0xC1, CMD_ARG, 0x02, // power control 2
91  0xC5, CMD_ARG, 0x50, CMD_ARG, 0x5B, // vcom control 1
92  0xC7, CMD_ARG, 0x40, // vcom offset
93 // 0x2A, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x7F, // set column address, not needed. set by direct API
94 // 0x2B, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x9F, // set page address, not needed. set by direct API
95  0x36, CMD_ARG, 0b00100000, // enable fake "vertical addressing" mode (for il9163_setBlock() )
96  0x29, // display on
97 };
98 
99 static uint8_t s_column;
100 static uint8_t s_page;
101 
102 static void il9163_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
103 {
104  uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
105  s_column = x;
106  s_page = y;
109  ssd1306_intf.send(0x2B);
110  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
111  ssd1306_intf.send(0);
112  ssd1306_intf.send(x + (s_rotation == 3 ? 32 : 0));
113  ssd1306_intf.send(0);
114  ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1))
115  + (s_rotation == 3 ? 32 : 0));
117  ssd1306_intf.send(0x2A);
118  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
119  ssd1306_intf.send(0);
120  ssd1306_intf.send((y<<3) + (s_rotation == 2 ? 32: 0));
121  ssd1306_intf.send(0);
122  ssd1306_intf.send((((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1))
123  + (s_rotation == 2 ? 32: 0));
125  ssd1306_intf.send(0x2C);
127 }
128 
129 static void il9163_setBlock2(lcduint_t x, lcduint_t y, lcduint_t w)
130 {
131  uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
134  ssd1306_intf.send(0x2A);
135  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
136  ssd1306_intf.send(0);
137  ssd1306_intf.send(x + (s_rotation == 7 ? 32 : 0));
138  ssd1306_intf.send(0);
139  ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1))
140  + (s_rotation == 7 ? 32 : 0));
142  ssd1306_intf.send(0x2B);
143  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
144  ssd1306_intf.send(0);
145  ssd1306_intf.send(y + (s_rotation == 6 ? 32: 0));
146  ssd1306_intf.send(0);
147  ssd1306_intf.send(ssd1306_lcd.height - 1 + (s_rotation == 6 ? 32: 0));
149  ssd1306_intf.send(0x2C);
151 }
152 
153 static void il9163_nextPage(void)
154 {
155  ssd1306_intf.stop();
156  ssd1306_lcd.set_block(s_column,s_page+1,0);
157 }
158 
159 static void il9163_nextPage2(void)
160 {
161 }
162 
164 {
167  ssd1306_intf.send( 0x36 );
169  ssd1306_intf.send( mode ? 0b00101000 : 0b00001000 );
170  ssd1306_intf.stop();
171  if (mode)
172  {
173  ssd1306_lcd.set_block = il9163_setBlock;
174  ssd1306_lcd.next_page = il9163_nextPage;
175  }
176  else
177  {
178  ssd1306_lcd.set_block = il9163_setBlock2;
179  ssd1306_lcd.next_page = il9163_nextPage2;
180  }
181  s_rotation = mode ? 0x00 : 0x04;
182 }
183 
184 static void il9163_sendPixels(uint8_t data)
185 {
186  for (uint8_t i=8; i>0; i--)
187  {
188  if ( data & 0x01 )
189  {
190  ssd1306_intf.send( (uint8_t)(ssd1306_color>>8) );
191  ssd1306_intf.send( (uint8_t)(ssd1306_color) );
192  }
193  else
194  {
195  ssd1306_intf.send( 0B00000000 );
196  ssd1306_intf.send( 0B00000000 );
197  }
198  data >>= 1;
199  }
200 }
201 
202 static void il9163_sendPixelsBuffer(const uint8_t *buffer, uint16_t len)
203 {
204  while(len--)
205  {
206  il9163_sendPixels(*buffer);
207  buffer++;
208  }
209 }
210 
211 static void il9163_sendPixel8(uint8_t data)
212 {
213  uint16_t color = RGB8_TO_RGB16(data);
214  ssd1306_intf.send( color >> 8 );
215  ssd1306_intf.send( color & 0xFF );
216 }
217 
219 {
221  ssd1306_lcd.height = 128;
222  ssd1306_lcd.width = 128;
223  s_rgb_bit = 0b00001000; // set BGR mode mapping
224  ssd1306_lcd.set_block = il9163_setBlock;
225  ssd1306_lcd.next_page = il9163_nextPage;
226  ssd1306_lcd.send_pixels1 = il9163_sendPixels;
227  ssd1306_lcd.send_pixels_buffer1 = il9163_sendPixelsBuffer;
228  ssd1306_lcd.send_pixels8 = il9163_sendPixel8;
230  ssd1306_configureSpiDisplay(s_oled128x128_initData, sizeof(s_oled128x128_initData));
231 }
232 
233 void il9163_128x128_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
234 {
235  if (rstPin >=0)
236  {
237  pinMode(rstPin, OUTPUT);
238  digitalWrite(rstPin, HIGH);
239  /* Wait at least 1ms after VCC is up for LCD */
240  delay(1);
241  /* Perform reset operation of LCD display */
242  digitalWrite(rstPin, LOW);
243  delay(20);
244  digitalWrite(rstPin, HIGH);
245  }
246  /* ssd1351 cannot work faster than at 4MHz per datasheet */
247  s_ssd1306_spi_clock = 8000000;
248  ssd1306_spiInit(cesPin, dcPin);
250 }
251 
252 void il9163_setRotation(uint8_t rotation)
253 {
254  uint8_t ram_mode;
255  if ((rotation^s_rotation) & 0x01)
256  {
257  uint16_t t = ssd1306_lcd.width;
259  ssd1306_lcd.height = t;
260  }
261  s_rotation = (rotation & 0x03) | (s_rotation & 0x04);
264  ssd1306_intf.send(0x28);
265  ssd1306_intf.send(0x36);
267  switch (s_rotation)
268  {
269  case 0:
270  ram_mode = 0b00100000;
271  break;
272  case 1: // 90 degree CW
273  ram_mode = 0b01000000;
274  break;
275  case 2: // 180 degree CW
276  ram_mode = 0b11100000;
277  break;
278  case 3: // 270 degree CW
279  ram_mode = 0b10000000;
280  break;
281  case 4:
282  ram_mode = 0b00000000;
283  break;
284  case 5: // 90 degree CW
285  ram_mode = 0b01100000;
286  break;
287  case 6: // 180 degree CW
288  ram_mode = 0b11000000;
289  break;
290  default: // 270 degree CW
291  ram_mode = 0b10100000;
292  break;
293  }
294  ssd1306_intf.send( ram_mode | s_rgb_bit );
296  ssd1306_intf.send(0x29);
297  ssd1306_intf.stop();
298 }
299 
301 // ST7735 support
303 
304 static void st7735_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
305 {
306  uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
307  s_column = x;
308  s_page = y;
311  ssd1306_intf.send(0x2B);
312  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
313  ssd1306_intf.send(0);
314  ssd1306_intf.send(x);
315  ssd1306_intf.send(0);
316  ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)));
318  ssd1306_intf.send(0x2A);
319  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
320  ssd1306_intf.send(0);
321  ssd1306_intf.send((y<<3));
322  ssd1306_intf.send(0);
323  ssd1306_intf.send((((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1)));
325  ssd1306_intf.send(0x2C);
327 }
328 
329 #if 0
330 static void st7735_setBlock2(lcduint_t x, lcduint_t y, lcduint_t w)
331 {
332  uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
335  ssd1306_intf.send(0x2A);
336  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
337  ssd1306_intf.send(0);
338  ssd1306_intf.send(x);
339  ssd1306_intf.send(0);
340  ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)));
342  ssd1306_intf.send(0x2B);
343  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
344  ssd1306_intf.send(0);
345  ssd1306_intf.send(y);
346  ssd1306_intf.send(0);
349  ssd1306_intf.send(0x2C);
351 }
352 #endif
353 
355 {
357  ssd1306_lcd.width = 128;
358  ssd1306_lcd.height = 160;
359  s_rgb_bit = 0b00000000; // set RGB mode mapping
360  ssd1306_lcd.set_block = st7735_setBlock;
361  ssd1306_lcd.next_page = il9163_nextPage;
362  ssd1306_lcd.send_pixels1 = il9163_sendPixels;
363  ssd1306_lcd.send_pixels_buffer1 = il9163_sendPixelsBuffer;
364  ssd1306_lcd.send_pixels8 = il9163_sendPixel8;
366  ssd1306_configureSpiDisplay(s_oled128x160_initData, sizeof(s_oled128x160_initData));
367 }
368 
369 void st7735_128x160_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
370 {
371  if (rstPin >=0)
372  {
373  pinMode(rstPin, OUTPUT);
374  digitalWrite(rstPin, HIGH);
375  /* Wait at least 1ms after VCC is up for LCD */
376  delay(1);
377  /* Perform reset operation of LCD display */
378  digitalWrite(rstPin, LOW);
379  delay(20);
380  digitalWrite(rstPin, HIGH);
381  /* Give 120ms display to initialize */
382  delay(120);
383  }
384  /* ssd1351 cannot work faster than at 4MHz per datasheet */
385  s_ssd1306_spi_clock = 8000000;
386  ssd1306_spiInit(cesPin, dcPin);
388 }
void st7735_128x160_init(void)
Inits 128x160 RGB OLED display (based on st7735 controller).
Definition: lcd_il9163.c:354
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:369
void(* send)(uint8_t data)
uint32_t s_ssd1306_spi_clock
Definition: ssd1306_spi.c:37
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:56
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(* send_pixels1)(uint8_t data)
Definition: lcd_common.h:128
void il9163_128x128_init(void)
Inits 128x128 RGB OLED display (based on il9163 controller).
Definition: lcd_il9163.c:218
void ssd1306_spiInit(int8_t cesPin, int8_t dcPin)
Definition: ssd1306_spi.c:39
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:233
#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:163
void(* set_mode)(lcd_mode_t mode)
Sets library display mode for direct draw functions.
Definition: lcd_common.h:157
void il9163_setRotation(uint8_t rotation)
Sets screen orientation (rotation)
Definition: lcd_il9163.c:252