SSD1306 OLED display driver  1.8.2
This library is developed to control SSD1306/SSD1331/SSD1351/IL9163/PCD8554 RGB i2c/spi LED displays
lcd_ili9341.c
1 /*
2  MIT License
3 
4  Copyright (c) 2018-2019, 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_ili9341.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 static uint8_t s_rotate_output = 0;
43 
44 
45 static const PROGMEM uint8_t s_oled240x320_initData[] =
46 {
47 #ifdef SDL_EMULATION
48  SDL_LCD_ILI9341,
49  0x00,
50 #endif
51  0x01, // sw reset. not needed, we do hardware reset
52  0x11, // exit sleep mode
53  0x3A, CMD_ARG, 0x05, // set 16-bit pixel format
54  0x26, CMD_ARG, 0x04, // set gamma curve: valid values 1, 2, 4, 8
55  0xF2, CMD_ARG, 0x01, // enable gamma adjustment, 0 - to disable
56  0xE0, CMD_ARG, 0x3F, CMD_ARG, 0x25, CMD_ARG, 0x1C,
57  CMD_ARG, 0x1E, CMD_ARG, 0x20, CMD_ARG, 0x12,
58  CMD_ARG, 0x2A, CMD_ARG, 0x90, CMD_ARG, 0x24,
59  CMD_ARG, 0x11, CMD_ARG, 0x00, CMD_ARG, 0x00,
60  CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, // positive gamma correction
61  0xE1, CMD_ARG, 0x20, CMD_ARG, 0x20, CMD_ARG, 0x20,
62  CMD_ARG, 0x20, CMD_ARG, 0x05, CMD_ARG, 0x00,
63  CMD_ARG, 0x15, CMD_ARG, 0xA7, CMD_ARG, 0x3D,
64  CMD_ARG, 0x18, CMD_ARG, 0x25, CMD_ARG, 0x2A,
65  CMD_ARG, 0x2B, CMD_ARG, 0x2B, CMD_ARG, 0x3A, // negative gamma correction
66 // 0xB1, CMD_ARG, 0x08, CMD_ARG, 0x08, // frame rate control 1, use by default
67 // 0xB4, CMD_ARG, 0x07, // display inversion, use by default
68  0xC0, CMD_ARG, 0x0A, CMD_ARG, 0x02, // power control 1
69  0xC1, CMD_ARG, 0x02, // power control 2
70  0xC5, CMD_ARG, 0x50, CMD_ARG, 0x5B, // vcom control 1
71  0xC7, CMD_ARG, 0x40, // vcom offset
72  0x36, CMD_ARG, 0b10100000, // enable fake "vertical addressing" mode (for ili9341_setBlock() )
73  0x29, // display on
74 };
75 
76 static lcduint_t s_column;
77 static lcduint_t s_page;
78 
79 static void ili9341_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
80 {
81  lcduint_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
82  s_column = x;
83  s_page = y;
86  ssd1306_intf.send(0x2B);
87  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
88  ssd1306_intf.send(x >> 8);
89  ssd1306_intf.send(x & 0xFF);
90  ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)) >> 8);
91  ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)) & 0xFF);
93  ssd1306_intf.send(0x2A);
94  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
95  ssd1306_intf.send((y<<3) >> 8);
96  ssd1306_intf.send((y<<3) & 0xFF);
97  ssd1306_intf.send((((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1))>>8);
98  ssd1306_intf.send((((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1)) & 0xFF);
100  ssd1306_intf.send(0x2C);
102 }
103 
104 static void ili9341_setBlock2(lcduint_t x, lcduint_t y, lcduint_t w)
105 {
106  lcduint_t width = s_rotate_output ? ssd1306_lcd.height : ssd1306_lcd.width;
107  lcduint_t height = s_rotate_output ? ssd1306_lcd.width : ssd1306_lcd.height;
108  lcduint_t rx = w ? (x + w - 1) : (width - 1);
111  ssd1306_intf.send(0x2A);
112  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
113  ssd1306_intf.send(x >> 8);
114  ssd1306_intf.send(x & 0xFF);
115  ssd1306_intf.send((rx < width ? rx : (width - 1))>>8);
116  ssd1306_intf.send((rx < width ? rx : (width - 1)) & 0xFF);
118  ssd1306_intf.send(0x2B);
119  ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
120  ssd1306_intf.send(y >> 8);
121  ssd1306_intf.send(y & 0xFF);
122  ssd1306_intf.send((height - 1) >> 8);
123  ssd1306_intf.send((height - 1) & 0xFF);
125  ssd1306_intf.send(0x2C);
127 }
128 
129 static void ili9341_nextPage(void)
130 {
131  ssd1306_intf.stop();
132  ssd1306_lcd.set_block(s_column,s_page+1,0);
133 }
134 
135 static void ili9341_nextPage2(void)
136 {
137 }
138 
140 {
141  s_rotation &= 0x03;
142  s_rotation |= (mode == LCD_MODE_SSD1306_COMPAT ? 0x00 : 0x04);
143  ili9341_setRotation( s_rotation );
144  if (mode == LCD_MODE_SSD1306_COMPAT)
145  {
146  ssd1306_lcd.set_block = ili9341_setBlock;
147  ssd1306_lcd.next_page = ili9341_nextPage;
148  }
149  else if (mode == LCD_MODE_NORMAL)
150  {
151  ssd1306_lcd.set_block = ili9341_setBlock2;
152  ssd1306_lcd.next_page = ili9341_nextPage2;
153  }
154 }
155 
156 static void ili9341_sendPixels(uint8_t data)
157 {
158  for (uint8_t i=8; i>0; i--)
159  {
160  if ( data & 0x01 )
161  {
162  ssd1306_intf.send( (uint8_t)(ssd1306_color>>8) );
163  ssd1306_intf.send( (uint8_t)(ssd1306_color) );
164  }
165  else
166  {
167  ssd1306_intf.send( 0B00000000 );
168  ssd1306_intf.send( 0B00000000 );
169  }
170  data >>= 1;
171  }
172 }
173 
174 static void ili9341_sendPixelsBuffer(const uint8_t *buffer, uint16_t len)
175 {
176  while(len--)
177  {
178  ili9341_sendPixels(*buffer);
179  buffer++;
180  }
181 }
182 
183 static void ili9341_sendPixel8(uint8_t data)
184 {
185  uint16_t color = RGB8_TO_RGB16(data);
186  ssd1306_intf.send( color >> 8 );
187  ssd1306_intf.send( color & 0xFF );
188 }
189 
190 static void ili9341_sendPixel16(uint16_t color)
191 {
192  ssd1306_intf.send( color >> 8 );
193  ssd1306_intf.send( color & 0xFF );
194 }
195 
197 {
199  ssd1306_lcd.width = 240;
201  s_rgb_bit = 0b00001000; // set BGR mode mapping
202  ssd1306_lcd.set_block = ili9341_setBlock;
203  ssd1306_lcd.next_page = ili9341_nextPage;
204  ssd1306_lcd.send_pixels1 = ili9341_sendPixels;
205  ssd1306_lcd.send_pixels_buffer1 = ili9341_sendPixelsBuffer;
206  ssd1306_lcd.send_pixels8 = ili9341_sendPixel8;
207  ssd1306_lcd.send_pixels16 = ili9341_sendPixel16;
209  ssd1306_configureSpiDisplay(s_oled240x320_initData, sizeof(s_oled240x320_initData));
210 }
211 
212 void ili9341_240x320_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
213 {
214  if (rstPin >=0)
215  {
216  pinMode(rstPin, OUTPUT);
217  digitalWrite(rstPin, HIGH);
218  /* Wait at least 1ms after VCC is up for LCD */
219  delay(1);
220  /* Perform reset operation of LCD display */
221  digitalWrite(rstPin, LOW);
222  delay(100);
223  digitalWrite(rstPin, HIGH);
224  delay(100);
225  }
226  s_ssd1306_spi_clock = 10000000;
227  ssd1306_spiInit(cesPin, dcPin);
229 }
230 
231 void ili9341_setRotation(uint8_t rotation)
232 {
233  uint8_t ram_mode;
234  if ((rotation^s_rotation) & 0x01)
235  {
236  uint16_t t = ssd1306_lcd.width;
238  ssd1306_lcd.height = t;
239  }
240  s_rotation = (rotation & 0x03) | (s_rotation & 0x04);
243  ssd1306_intf.send(0x28);
244  ssd1306_intf.send(0x36);
246  switch (s_rotation)
247  {
248  case 0:
249  ram_mode = 0b10100000;
250  break;
251  case 1: // 90 degree CW
252  ram_mode = 0b11010000;
253  break;
254  case 2: // 180 degree CW
255  ram_mode = 0b01100000;
256  break;
257  case 3: // 270 degree CW
258  ram_mode = 0b00000000;
259  break;
260  case 4:
261  ram_mode = s_rotate_output ? 0b11100100: 0b10000100;
262  break;
263  case 5: // 90 degree CW
264  ram_mode = 0b11100000;
265  break;
266  case 6: // 180 degree CW
267  ram_mode = 0b01010100;
268  break;
269  default: // 270 degree CW
270  ram_mode = 0b00100000;
271  break;
272  }
273  ssd1306_intf.send( ram_mode | s_rgb_bit );
275  ssd1306_intf.send(0x29);
276  ssd1306_intf.stop();
277 }
278 
279 void ili9341_rotateOutput(uint8_t on)
280 {
281  s_rotate_output = on;
282  ili9341_setRotation( s_rotation );
283 }
void ssd1306_configureSpiDisplay(const uint8_t *config, uint8_t configSize)
Sends configuration being passed to lcd display spi controller.
Definition: lcd_common.c:53
void(* send)(uint8_t data)
void ili9341_setRotation(uint8_t rotation)
Sets screen orientation (rotation)
Definition: lcd_ili9341.c:231
void ili9341_240x320_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
Inits 240x320 RGB TFT display over spi (based on ili9341 controller).
Definition: lcd_ili9341.c:212
uint32_t s_ssd1306_spi_clock
Definition: ssd1306_spi.c:35
void(* send_pixels16)(uint16_t data)
Sends RGB pixel encoded in 5-6-5 format to OLED driver. Sends RGB pixel encoded in 5-6-5 format to OL...
Definition: lcd_common.h:149
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
unsigned int lcduint_t
Definition: io.h:65
void ili9341_240x320_init(void)
Inits 240x320 RGB OLED display (based on ili9341 controller).
Definition: lcd_ili9341.c:196
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(* send_pixels1)(uint8_t data)
Definition: lcd_common.h:128
void ili9341_setMode(lcd_mode_t mode)
Sets GDRAM autoincrement mode.
Definition: lcd_ili9341.c:139
void ili9341_rotateOutput(uint8_t on)
Sets rotation of all output functions.
Definition: lcd_ili9341.c:279
void ssd1306_spiInit(int8_t cesPin, int8_t dcPin)
Definition: ssd1306_spi.c:37
ssd1306_lcd_t ssd1306_lcd
Definition: lcd_common.c:33
ssd1306_interface_t ssd1306_intf
lcduint_t height
Definition: lcd_common.h:97
#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(* set_mode)(lcd_mode_t mode)
Sets library display mode for direct draw functions.
Definition: lcd_common.h:164