1 /*
2 * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
3 * Copyright (c) 2014 Intel Corporation.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <stdexcept>
26 #include <string>
27 #include <unistd.h>
28
29 #include "hd44780_bits.h"
30 #include "ssd1327.h"
31
32 using namespace upm;
33
34 #define INIT_SLEEP 50000
35 #define CMD_SLEEP 10000
36
SSD1327(int bus_in,int addr_in)37 SSD1327::SSD1327(int bus_in, int addr_in) : m_i2c_lcd_control(bus_in)
38 {
39 mraa::Result error = mraa::SUCCESS;
40
41 m_lcd_control_address = addr_in;
42 m_name = "SSD1327";
43
44 error = m_i2c_lcd_control.address(m_lcd_control_address);
45 if (error != mraa::SUCCESS) {
46 throw std::invalid_argument(std::string(__FUNCTION__) +
47 ": I2c.address() failed");
48 return;
49 }
50
51 usleep(INIT_SLEEP);
52 m_i2c_lcd_control.writeReg(LCD_CMD, 0xFD); // Unlock OLED driver IC MCU
53 // interface from entering command.
54 // i.e: Accept commands
55 usleep(INIT_SLEEP);
56 m_i2c_lcd_control.writeReg(LCD_CMD, 0x12);
57 usleep(INIT_SLEEP);
58 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xAE); // Set display off
59 usleep(INIT_SLEEP);
60 m_i2c_lcd_control.writeReg(LCD_CMD, 0xA8); // set multiplex ratio
61 usleep(INIT_SLEEP);
62 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x5F); // 96
63 usleep(INIT_SLEEP);
64 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xA1); // set display start line
65 usleep(INIT_SLEEP);
66 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x00); //
67 usleep(INIT_SLEEP);
68 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xA2); // set display offset
69 usleep(INIT_SLEEP);
70 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x60);
71 usleep(INIT_SLEEP);
72 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xA0); // set remap
73 usleep(INIT_SLEEP);
74 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x46);
75 usleep(INIT_SLEEP);
76 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xAB); // set vdd internal
77 usleep(INIT_SLEEP);
78 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x01); //
79 usleep(INIT_SLEEP);
80 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x81); // set contrasr
81 usleep(INIT_SLEEP);
82 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x53); // 100 nit
83 usleep(INIT_SLEEP);
84 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xB1); // Set Phase Length
85 usleep(INIT_SLEEP);
86 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0X51); //
87 usleep(INIT_SLEEP);
88 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xB3); // Set Display Clock Divide Ratio/Oscillator
89 // Frequency
90 usleep(INIT_SLEEP);
91 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x01); //
92 usleep(INIT_SLEEP);
93 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xB9); //
94 usleep(INIT_SLEEP);
95 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xBC); // set pre_charge
96 // voltage/VCOMH
97 usleep(INIT_SLEEP);
98 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x08); // (0x08);
99 usleep(INIT_SLEEP);
100 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xBE); // set VCOMH
101 usleep(INIT_SLEEP);
102 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0X07); // (0x07);
103 usleep(INIT_SLEEP);
104 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xB6); // Set second pre-charge
105 // period
106 usleep(INIT_SLEEP);
107 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x01); //
108 usleep(INIT_SLEEP);
109 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xD5); // enable second precharge and enternal vsl
110 usleep(INIT_SLEEP);
111 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0X62); // (0x62);
112 usleep(INIT_SLEEP);
113 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xA4); // Set Normal Display Mode
114 usleep(INIT_SLEEP);
115 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x2E); // Deactivate Scroll
116 usleep(INIT_SLEEP);
117 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0xAF); // Switch on display
118 usleep(INIT_SLEEP);
119
120 // Row Address
121 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x75); // Set Row Address
122 usleep(INIT_SLEEP);
123 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x00); // Start 0
124 usleep(INIT_SLEEP);
125 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x5f); // End 95
126 usleep(INIT_SLEEP);
127
128 // Column Address
129 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x15); // Set Column Address
130 usleep(INIT_SLEEP);
131 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x08); // Start from 8th Column of
132 // driver IC. This is 0th
133 // Column for OLED
134 usleep(INIT_SLEEP);
135 error = m_i2c_lcd_control.writeReg(LCD_CMD, 0x37); // End at (8 + 47)th
136 // column. Each Column has 2
137 // pixels(segments)
138 usleep(INIT_SLEEP);
139
140 clear();
141 setNormalDisplay();
142 setVerticalMode();
143 }
144
~SSD1327()145 SSD1327::~SSD1327()
146 {
147 }
148
149 mraa::Result
draw(uint8_t * data,int bytes)150 SSD1327::draw(uint8_t* data, int bytes)
151 {
152 mraa::Result error = mraa::SUCCESS;
153
154 setHorizontalMode();
155 for (int row = 0; row < bytes; row++) {
156 for (uint8_t col = 0; col < 8; col += 2) {
157 uint8_t value = 0x0;
158
159 uint8_t bitOne = (data[row] << col) & 0x80;
160 uint8_t bitTwo = (data[row] << (col + 1)) & 0x80;
161
162 value |= (bitOne) ? grayHigh : 0x00;
163 value |= (bitTwo) ? grayLow : 0x00;
164
165 m_i2c_lcd_control.writeReg(LCD_DATA, value);
166 usleep(CMD_SLEEP - 2000);
167 }
168 }
169
170 return error;
171 }
172
173 /*
174 * **************
175 * virtual area
176 * **************
177 */
178 mraa::Result
write(std::string msg)179 SSD1327::write(std::string msg)
180 {
181 mraa::Result error = mraa::SUCCESS;
182
183 setVerticalMode();
184 for (std::string::size_type i = 0; i < msg.size(); ++i) {
185 writeChar(msg[i]);
186 }
187
188 return error;
189 }
190
191 mraa::Result
setCursor(int row,int column)192 SSD1327::setCursor(int row, int column)
193 {
194 mraa::Result error = mraa::SUCCESS;
195
196 // Column Address
197 m_i2c_lcd_control.writeReg(LCD_CMD, 0x15); /* Set Column Address */
198 usleep(CMD_SLEEP);
199 m_i2c_lcd_control.writeReg(LCD_CMD, 0x08 + (column * 4)); /* Start Column:
200 Start from 8 */
201 usleep(CMD_SLEEP);
202 m_i2c_lcd_control.writeReg(LCD_CMD, 0x37); /* End Column */
203 usleep(CMD_SLEEP);
204 // Row Address
205 m_i2c_lcd_control.writeReg(LCD_CMD, 0x75); /* Set Row Address */
206 usleep(CMD_SLEEP);
207 m_i2c_lcd_control.writeReg(LCD_CMD, 0x00 + (row * 8)); /* Start Row*/
208 usleep(CMD_SLEEP);
209 m_i2c_lcd_control.writeReg(LCD_CMD, 0x07 + (row * 8)); /* End Row*/
210 usleep(CMD_SLEEP);
211
212 return error;
213 }
214
215 mraa::Result
clear()216 SSD1327::clear()
217 {
218 mraa::Result error = mraa::SUCCESS;
219 uint8_t columnIdx, rowIdx;
220
221 for (rowIdx = 0; rowIdx < 12; rowIdx++) {
222 // clear all columns
223 for (columnIdx = 0; columnIdx < 12; columnIdx++) {
224 writeChar(' ');
225 }
226 }
227
228 return mraa::SUCCESS;
229 }
230
231 mraa::Result
home()232 SSD1327::home()
233 {
234 return setCursor(0, 0);
235 }
236
237 void
setGrayLevel(uint8_t level)238 SSD1327::setGrayLevel(uint8_t level)
239 {
240 grayHigh = (level << 4) & 0xF0;
241 grayLow = level & 0x0F;
242 }
243
244 /*
245 * **************
246 * private area
247 * **************
248 */
249 mraa::Result
writeChar(uint8_t value)250 SSD1327::writeChar(uint8_t value)
251 {
252 mraa::Result rv = mraa::SUCCESS;
253 if (value < 0x20 || value > 0x7F) {
254 value = 0x20; // space
255 }
256
257 for (uint8_t row = 0; row < 8; row = row + 2) {
258 for (uint8_t col = 0; col < 8; col++) {
259 uint8_t data = 0x0;
260
261 uint8_t bitOne = ((BasicFont[value - 32][row]) >> col) & 0x1;
262 uint8_t bitTwo = ((BasicFont[value - 32][row + 1]) >> col) & 0x1;
263
264 data |= (bitOne) ? grayHigh : 0x00;
265 data |= (bitTwo) ? grayLow : 0x00;
266
267 rv = m_i2c_lcd_control.writeReg(LCD_DATA, data);
268 usleep(CMD_SLEEP - 2000);
269 }
270 }
271 return rv;
272 }
273
274 mraa::Result
setNormalDisplay()275 SSD1327::setNormalDisplay()
276 {
277 return m_i2c_lcd_control.writeReg(LCD_CMD,
278 DISPLAY_CMD_SET_NORMAL); // set to normal display '1' is ON
279 }
280
281 mraa::Result
setHorizontalMode()282 SSD1327::setHorizontalMode()
283 {
284 mraa::Result rv = mraa::SUCCESS;
285 rv = m_i2c_lcd_control.writeReg(LCD_CMD, 0xA0); // remap to
286 usleep(CMD_SLEEP);
287 rv = m_i2c_lcd_control.writeReg(LCD_CMD, 0x42); // horizontal mode
288 usleep(CMD_SLEEP);
289
290 // Row Address
291 rv = m_i2c_lcd_control.writeReg(LCD_CMD, 0x75); // Set Row Address
292 usleep(CMD_SLEEP);
293 rv = m_i2c_lcd_control.writeReg(LCD_CMD, 0x00); // Start 0
294 usleep(CMD_SLEEP);
295 rv = m_i2c_lcd_control.writeReg(LCD_CMD, 0x5f); // End 95
296 usleep(CMD_SLEEP);
297
298 // Column Address
299 rv = m_i2c_lcd_control.writeReg(LCD_CMD, 0x15); // Set Column Address
300 usleep(CMD_SLEEP);
301 rv = m_i2c_lcd_control.writeReg(LCD_CMD, 0x08); // Start from 8th Column of driver
302 // IC. This is 0th Column for OLED
303 usleep(CMD_SLEEP);
304 rv = m_i2c_lcd_control.writeReg(LCD_CMD, 0x37); // End at (8 + 47)th column. Each
305 // Column has 2 pixels(or segments)
306 usleep(CMD_SLEEP);
307 return rv;
308 }
309
310 mraa::Result
setVerticalMode()311 SSD1327::setVerticalMode()
312 {
313 mraa::Result rv = mraa::SUCCESS;
314 rv = m_i2c_lcd_control.writeReg(LCD_CMD, 0xA0); // remap to
315 usleep(CMD_SLEEP);
316 rv = m_i2c_lcd_control.writeReg(LCD_CMD, 0x46); // Vertical mode
317 usleep(CMD_SLEEP);
318 return rv;
319 }
320