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;
84 ssd1306_intf.start();
85 ssd1306_spiDataMode(0);
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);
92 ssd1306_spiDataMode(0);
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);
99 ssd1306_spiDataMode(0);
100 ssd1306_intf.send(0x2C);
101 ssd1306_spiDataMode(1);
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);
109 ssd1306_intf.start();
110 ssd1306_spiDataMode(0);
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);
117 ssd1306_spiDataMode(0);
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);
124 ssd1306_spiDataMode(0);
125 ssd1306_intf.send(0x2C);
126 ssd1306_spiDataMode(1);
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
139 void ili9341_setMode(lcd_mode_t mode)
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
196 void ili9341_240x320_init()
197 {
198 ssd1306_lcd.type = LCD_TYPE_SSD1331;
199 ssd1306_lcd.width = 240;
200 ssd1306_lcd.height = (lcduint_t)320;
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;
208 ssd1306_lcd.set_mode = ili9341_setMode;
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);
228 ili9341_240x320_init();
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;
237 ssd1306_lcd.width = ssd1306_lcd.height;
238 ssd1306_lcd.height = t;
239 }
240 s_rotation = (rotation & 0x03) | (s_rotation & 0x04);
241 ssd1306_intf.start();
242 ssd1306_spiDataMode(0);
243 ssd1306_intf.send(0x28);
244 ssd1306_intf.send(0x36);
245 ssd1306_spiDataMode(1);
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 );
274 ssd1306_spiDataMode(0);
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 }
ssd1306_configureSpiDisplay
void ssd1306_configureSpiDisplay(const uint8_t *config, uint8_t configSize)
Sends configuration being passed to lcd display spi controller.
Definition: lcd_common.c:53
ssd1306_interface_t::send
void(* send)(uint8_t data)
Definition: ssd1306_interface.h:70
lcd_common.h
ili9341_setRotation
void ili9341_setRotation(uint8_t rotation)
Sets screen orientation (rotation)
Definition: lcd_ili9341.c:231
LCD_MODE_NORMAL
Definition: lcd_common.h:75
ssd1306_interface_t::stop
void(* stop)(void)
Definition: ssd1306_interface.h:65
ili9341_240x320_spi_init
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
s_ssd1306_spi_clock
uint32_t s_ssd1306_spi_clock
Definition: ssd1306_spi.c:35
ssd1306_lcd_t::send_pixels16
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
ssd1306_lcd_t::set_block
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
lcduint_t
unsigned int lcduint_t
Definition: io.h:65
io.h
ili9341_240x320_init
void ili9341_240x320_init(void)
Inits 240x320 RGB OLED display (based on ili9341 controller).
Definition: lcd_ili9341.c:196
ssd1306_lcd_t::send_pixels8
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
ssd1306_spiDataMode
void ssd1306_spiDataMode(uint8_t mode)
Definition: ssd1306_spi.c:50
lcd_mode_t
lcd_mode_t
Definition: lcd_common.h:69
ssd1306_lcd_t::send_pixels_buffer1
void(* send_pixels_buffer1)(const uint8_t *buffer, uint16_t len)
Definition: lcd_common.h:135
ssd1306_lcd_t::send_pixels1
void(* send_pixels1)(uint8_t data)
Definition: lcd_common.h:128
ili9341_setMode
void ili9341_setMode(lcd_mode_t mode)
Sets GDRAM autoincrement mode.
Definition: lcd_ili9341.c:139
ssd1306_spi.h
ili9341_rotateOutput
void ili9341_rotateOutput(uint8_t on)
Sets rotation of all output functions.
Definition: lcd_ili9341.c:279
ssd1306_interface_t::start
void(* start)(void)
Definition: ssd1306_interface.h:61
ssd1306_spiInit
void ssd1306_spiInit(int8_t cesPin, int8_t dcPin)
Definition: ssd1306_spi.c:37
ssd1306_lcd
ssd1306_lcd_t ssd1306_lcd
Definition: lcd_common.c:33
nano_gfx_types.h
ssd1306_intf
ssd1306_interface_t ssd1306_intf
Definition: ssd1306_interface.c:31
LCD_MODE_SSD1306_COMPAT
Definition: lcd_common.h:82
ssd1306_lcd_t::height
lcduint_t height
Definition: lcd_common.h:97
ssd1306_interface.h
RGB8_TO_RGB16
#define RGB8_TO_RGB16(c)
Definition: nano_gfx_types.h:50
ssd1306_lcd_t::next_page
void(* next_page)(void)
Definition: lcd_common.h:122
ssd1306_lcd_t::width
lcduint_t width
Definition: lcd_common.h:94
ssd1306_lcd_t::type
lcd_type_t type
Definition: lcd_common.h:91
ssd1306_lcd_t::set_mode
void(* set_mode)(lcd_mode_t mode)
Sets library display mode for direct draw functions.
Definition: lcd_common.h:164
lcd_ili9341.h
LCD_TYPE_SSD1331
Definition: lcd_common.h:59