Home | History | Annotate | Download | only in lcd
      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