1 /* 2 * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha (at) 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 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 145 SSD1327::~SSD1327() 146 { 147 } 148 149 mraa::Result 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 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 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 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 232 SSD1327::home() 233 { 234 return setCursor(0, 0); 235 } 236 237 void 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 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 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 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 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