SSD1306 OLED display driver  1.5.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 "spi/ssd1306_spi.h"
29 #include "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 
160 {
163  ssd1306_intf.send( 0x36 );
165  ssd1306_intf.send( mode ? 0b00101000 : 0b00001000 );
166  ssd1306_intf.stop();
167  if (mode)
168  {
169  ssd1306_lcd.set_block = il9163_setBlock;
170  }
171  else
172  {
173  ssd1306_lcd.set_block = il9163_setBlock2;
174  }
175  s_rotation = mode ? 0x00 : 0x04;
176 }
177 
178 static void il9163_sendPixels(uint8_t data)
179 {
180  for (uint8_t i=8; i>0; i--)
181  {
182  if ( data & 0x01 )
183  {
184  ssd1306_intf.send( (uint8_t)(ssd1306_color>>8) );
185  ssd1306_intf.send( (uint8_t)(ssd1306_color) );
186  }
187  else
188  {
189  ssd1306_intf.send( 0B00000000 );
190  ssd1306_intf.send( 0B00000000 );
191  }
192  data >>= 1;
193  }
194 }
195 
196 static void il9163_sendPixelsBuffer(const uint8_t *buffer, uint16_t len)
197 {
198  while(len--)
199  {
200  il9163_sendPixels(*buffer);
201  buffer++;
202  }
203 }
204 
205 static void il9163_sendPixel8(uint8_t data)
206 {
207  uint16_t color = RGB8_TO_RGB16(data);
208  ssd1306_intf.send( color >> 8 );
209  ssd1306_intf.send( color & 0xFF );
210 }
211 
213 {
215  ssd1306_lcd.height = 128;
216  ssd1306_lcd.width = 128;
217  s_rgb_bit = 0b00001000; // set BGR mode mapping
218  ssd1306_lcd.set_block = il9163_setBlock;
219  ssd1306_lcd.next_page = il9163_nextPage;
220  ssd1306_lcd.send_pixels1 = il9163_sendPixels;
221  ssd1306_lcd.send_pixels_buffer1 = il9163_sendPixelsBuffer;
222  ssd1306_lcd.send_pixels8 = il9163_sendPixel8;
224  ssd1306_configureSpiDisplay(s_oled128x128_initData, sizeof(s_oled128x128_initData));
225 }
226 
227 void il9163_128x128_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
228 {
229  if (rstPin >=0)
230  {
231  pinMode(rstPin, OUTPUT);
232  digitalWrite(rstPin, HIGH);
233  /* Wait at least 1ms after VCC is up for LCD */
234  delay(1);
235  /* Perform reset operation of LCD display */
236  digitalWrite(rstPin, LOW);
237  delay(20);
238  digitalWrite(rstPin, HIGH);
239  }
240  /* ssd1351 cannot work faster than at 4MHz per datasheet */
241  s_ssd1306_spi_clock = 8000000;
242  ssd1306_spiInit(cesPin, dcPin);
244 }
245 
246 void il9163_setRotation(uint8_t rotation)
247 {
248  uint8_t ram_mode;
249  if ((rotation^s_rotation) & 0x01)
250  {
251  uint16_t t = ssd1306_lcd.width;
253  ssd1306_lcd.height = t;
254  }
255  s_rotation = (rotation & 0x03) | (s_rotation & 0x04);
258  ssd1306_intf.send(0x28);
259  ssd1306_intf.send(0x36);
261  switch (s_rotation)
262  {
263  case 0:
264  ram_mode = 0b00100000;
265  break;
266  case 1: // 90 degree CW
267  ram_mode = 0b01000000;
268  break;
269  case 2: // 180 degree CW
270  ram_mode = 0b11100000;
271  break;
272  case 3: // 270 degree CW
273  ram_mode = 0b10000000;
274  break;
275  case 4:
276  ram_mode = 0b00000000;
277  break;
278  case 5: // 90 degree CW
279  ram_mode = 0b01100000;
280  break;
281  case 6: // 180 degree CW
282  ram_mode = 0b11000000;
283  break;
284  default: // 270 degree CW
285  ram_mode = 0b10100000;
286  break;
287  }
288  ssd1306_intf.send( ram_mode | s_rgb_bit );
290  ssd1306_intf.send(0x29);
291  ssd1306_intf.stop();
292 }
293 
295 // ST7735 support
297 
298 static void st7735_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
299 {
300  uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
301  s_column = x;
302  s_page = y;
305  ssd1306_intf.send(0x2B);
306  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
307  ssd1306_intf.send(0);
308  ssd1306_intf.send(x);
309  ssd1306_intf.send(0);
310  ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)));
312  ssd1306_intf.send(0x2A);
313  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
314  ssd1306_intf.send(0);
315  ssd1306_intf.send((y<<3));
316  ssd1306_intf.send(0);
317  ssd1306_intf.send((((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1)));
319  ssd1306_intf.send(0x2C);
321 }
322 
323 #if 0
324 static void st7735_setBlock2(lcduint_t x, lcduint_t y, lcduint_t w)
325 {
326  uint8_t rx = w ? (x + w - 1) : (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(x);
333  ssd1306_intf.send(0);
334  ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)));
336  ssd1306_intf.send(0x2B);
337  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
338  ssd1306_intf.send(0);
339  ssd1306_intf.send(y);
340  ssd1306_intf.send(0);
343  ssd1306_intf.send(0x2C);
345 }
346 #endif
347 
349 {
351  ssd1306_lcd.width = 128;
352  ssd1306_lcd.height = 160;
353  s_rgb_bit = 0b00000000; // set RGB mode mapping
354  ssd1306_lcd.set_block = st7735_setBlock;
355  ssd1306_lcd.next_page = il9163_nextPage;
356  ssd1306_lcd.send_pixels1 = il9163_sendPixels;
357  ssd1306_lcd.send_pixels_buffer1 = il9163_sendPixelsBuffer;
358  ssd1306_lcd.send_pixels8 = il9163_sendPixel8;
360  ssd1306_configureSpiDisplay(s_oled128x160_initData, sizeof(s_oled128x160_initData));
361 }
362 
363 void st7735_128x160_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
364 {
365  if (rstPin >=0)
366  {
367  pinMode(rstPin, OUTPUT);
368  digitalWrite(rstPin, HIGH);
369  /* Wait at least 1ms after VCC is up for LCD */
370  delay(1);
371  /* Perform reset operation of LCD display */
372  digitalWrite(rstPin, LOW);
373  delay(20);
374  digitalWrite(rstPin, HIGH);
375  /* Give 120ms display to initialize */
376  delay(120);
377  }
378  /* ssd1351 cannot work faster than at 4MHz per datasheet */
379  s_ssd1306_spi_clock = 8000000;
380  ssd1306_spiInit(cesPin, dcPin);
382 }
void st7735_128x160_init(void)
Inits 128x160 RGB OLED display (based on st7735 controller).
Definition: lcd_il9163.c:348
unsigned int lcduint_t
Definition: io.h:42
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:363
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:110
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:138
void ssd1306_spiDataMode(uint8_t mode)
Definition: ssd1306_spi.c:54
lcd_mode_t
Definition: lcd_common.h:65
void(* send_pixels_buffer1)(const uint8_t *buffer, uint16_t len)
Definition: lcd_common.h:131
void(* send_pixels1)(uint8_t data)
Definition: lcd_common.h:124
void il9163_128x128_init(void)
Inits 128x128 RGB OLED display (based on il9163 controller).
Definition: lcd_il9163.c:212
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:93
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:227
#define RGB8_TO_RGB16(c)
void(* next_page)(void)
Definition: lcd_common.h:118
lcduint_t width
Definition: lcd_common.h:90
lcd_type_t type
Definition: lcd_common.h:87
void il9163_setMode(lcd_mode_t mode)
Sets GDRAM autoincrement mode.
Definition: lcd_il9163.c:159
void(* set_mode)(lcd_mode_t mode)
Sets library display mode for direct draw functions.
Definition: lcd_common.h:153
void il9163_setRotation(uint8_t rotation)
Sets screen orientation (rotation)
Definition: lcd_il9163.c:246