Home | History | Annotate | Download | only in lcd
      1 /*
      2  * Author: Marc Graham <marc (at) m2ag.net>
      3  * Copyright (c) 2015 Intel Corporation
      4  *
      5  * Adapted from ssd1308 library.
      6  * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha (at) intel.com>
      7  * Copyright (c) 2014 Intel Corporation.
      8  *
      9  * Permission is hereby granted, free of charge, to any person obtaining
     10  * a copy of this software and associated documentation files (the
     11  * "Software"), to deal in the Software without restriction, including
     12  * without limitation the rights to use, copy, modify, merge, publish,
     13  * distribute, sublicense, and/or sell copies of the Software, and to
     14  * permit persons to whom the Software is furnished to do so, subject to
     15  * the following conditions:
     16  *
     17  * The above copyright notice and this permission notice shall be
     18  * included in all copies or substantial portions of the Software.
     19  *
     20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     24  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     25  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     26  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     27  */
     28 
     29 #include <string>
     30 #include <unistd.h>
     31 
     32 #include "hd44780_bits.h"
     33 #include "ssd1306.h"
     34 
     35 using namespace upm;
     36 
     37 SSD1306::SSD1306(int bus_in, int addr_in) : m_i2c_lcd_control(bus_in)
     38 {
     39     int vccstate = SSD1306_SWITCHCAPVCC;
     40     _vccstate = vccstate;
     41 
     42     int LCD_CMD = 0x00;
     43 
     44     m_lcd_control_address = addr_in;
     45     m_name = "SSD1306";
     46 
     47     mraa::Result error = m_i2c_lcd_control.address(m_lcd_control_address);
     48 
     49     if (error != mraa::SUCCESS) {
     50         throw std::runtime_error(std::string(__FUNCTION__) +
     51                                 ": mraa_i2c_address() failed");
     52         return;
     53     }
     54 
     55     error = m_i2c_lcd_control.frequency(mraa::I2C_FAST);
     56 
     57     if (error != mraa::SUCCESS) {
     58         throw std::invalid_argument(std::string(__FUNCTION__) +
     59                                 ": mraa_i2c_frequency(MRAA_I2C_FAST) failed");
     60         return;
     61     }
     62 
     63     m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_OFF); // display off
     64     usleep(4500);
     65     //ADD 1306 stuff
     66     // Init sequence for 128x64 OLED module                 // 0xAE
     67     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETDISPLAYCLOCKDIV);            // 0xD5
     68     m_i2c_lcd_control.writeReg(LCD_CMD, 0x80);                                  // the suggested ratio 0x80
     69     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETMULTIPLEX);                  // 0xA8
     70     m_i2c_lcd_control.writeReg(LCD_CMD, 0x3F);
     71     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETDISPLAYOFFSET);              // 0xD3
     72     m_i2c_lcd_control.writeReg(LCD_CMD, 0x0);                                   // no offset
     73     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETSTARTLINE | 0x0);            // line #0
     74     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_CHARGEPUMP);                    // 0x8D
     75     if (vccstate == SSD1306_EXTERNALVCC) {
     76         m_i2c_lcd_control.writeReg(LCD_CMD, 0x10);
     77     } else {
     78         m_i2c_lcd_control.writeReg(LCD_CMD,0x14);
     79     }
     80     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_MEMORYMODE);                    // 0x20
     81     m_i2c_lcd_control.writeReg(LCD_CMD, 0x00);                                  // 0x0 act like ks0108
     82     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SEGREMAP | 0x1);
     83     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_COMSCANDEC);
     84     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETCOMPINS);                    // 0xDA
     85     m_i2c_lcd_control.writeReg(LCD_CMD, 0x12);
     86     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETCONTRAST);                   // 0x81
     87     if (vccstate == SSD1306_EXTERNALVCC) {
     88         m_i2c_lcd_control.writeReg(LCD_CMD, 0x9F);
     89     } else {
     90         m_i2c_lcd_control.writeReg(LCD_CMD, 0xCF);
     91     }
     92     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETPRECHARGE);                  // 0xd9
     93     if (vccstate == SSD1306_EXTERNALVCC) {
     94       m_i2c_lcd_control.writeReg(LCD_CMD, 0x22);
     95     } else {
     96       m_i2c_lcd_control.writeReg(LCD_CMD,0xF1);
     97     }
     98     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETVCOMDETECT);                 // 0xDB
     99     m_i2c_lcd_control.writeReg(LCD_CMD, 0x40);
    100     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_DISPLAYALLON_RESUME);           // 0xA4
    101     m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_SET_NORMAL_1306);                 // 0xA6
    102 
    103     //END 1306 Stuff
    104     m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_ON); // display on
    105     usleep(4500);
    106     setNormalDisplay(); // set to normal display '1' is ON
    107 
    108     clear();
    109     setAddressingMode(PAGE);
    110 }
    111 
    112 SSD1306::~SSD1306()
    113 {
    114 }
    115 
    116 mraa::Result
    117 SSD1306::draw(uint8_t* data, int bytes)
    118 {
    119     mraa::Result error = mraa::SUCCESS;
    120 
    121     setAddressingMode(HORIZONTAL);
    122     for (int idx = 0; idx < bytes; idx++) {
    123         m_i2c_lcd_control.writeReg(LCD_DATA, data[idx]);
    124     }
    125 
    126     return error;
    127 }
    128 
    129 /*
    130  * **************
    131  *  virtual area
    132  * **************
    133  */
    134 mraa::Result
    135 SSD1306::write(std::string msg)
    136 {
    137     mraa::Result error = mraa::SUCCESS;
    138 
    139     setAddressingMode(PAGE);
    140     for (std::string::size_type i = 0; i < msg.size(); ++i) {
    141         writeChar(msg[i]);
    142     }
    143 
    144     return error;
    145 }
    146 
    147 mraa::Result
    148 SSD1306::setCursor(int row, int column)
    149 {
    150     mraa::Result error = mraa::SUCCESS;
    151 
    152     error = m_i2c_lcd_control.writeReg(LCD_CMD, BASE_PAGE_START_ADDR + row); // set page address
    153     error = m_i2c_lcd_control.writeReg(LCD_CMD,
    154                                        BASE_LOW_COLUMN_ADDR + (8 * column & 0x0F)); // set column
    155                                                                                     // lower address
    156     error = m_i2c_lcd_control.writeReg(LCD_CMD,
    157                                        BASE_HIGH_COLUMN_ADDR +
    158                                        ((8 * column >> 4) & 0x0F)); // set column higher address
    159 
    160     return error;
    161 }
    162 
    163 mraa::Result
    164 SSD1306::clear()
    165 {
    166     mraa::Result error = mraa::SUCCESS;
    167     uint8_t columnIdx, rowIdx;
    168 
    169     m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_OFF); // display off
    170     for (rowIdx = 0; rowIdx < 8; rowIdx++) {
    171         setCursor(rowIdx, 0);
    172 
    173         // clear all columns
    174         for (columnIdx = 0; columnIdx < 16; columnIdx++) {
    175             writeChar(' ');
    176         }
    177     }
    178     m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_ON); // display on
    179     home();
    180 
    181     return error;
    182 }
    183 
    184 mraa::Result
    185 SSD1306::home()
    186 {
    187     return setCursor(0, 0);
    188 }
    189 
    190 /*
    191  * **************
    192  *  private area
    193  * **************
    194  */
    195 mraa::Result
    196 SSD1306::writeChar(uint8_t value)
    197 {
    198     mraa::Result rv;
    199     if (value < 0x20 || value > 0x7F) {
    200         value = 0x20; // space
    201     }
    202 
    203     for (uint8_t idx = 0; idx < 8; idx++) {
    204         rv = m_i2c_lcd_control.writeReg(LCD_DATA, BasicFont[value - 32][idx]);
    205     }
    206 
    207     return rv;
    208 }
    209 
    210 mraa::Result
    211 SSD1306::setNormalDisplay()
    212 {
    213     return m_i2c_lcd_control.writeReg(LCD_CMD,
    214                                       DISPLAY_CMD_SET_NORMAL_1306); // set to normal display '1' is
    215                                                                     // ON
    216 }
    217 
    218 mraa::Result
    219 SSD1306::setAddressingMode(displayAddressingMode mode)
    220 {
    221     mraa::Result rv;
    222     rv =m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_MEM_ADDR_MODE); // set addressing mode
    223     rv =m_i2c_lcd_control.writeReg(LCD_CMD, mode);                      // set page addressing mode
    224     return rv;
    225 }
    226 
    227 
    228 mraa::Result
    229 SSD1306::invert(bool i)
    230 {
    231     mraa::Result rv;
    232     if(i){
    233         rv = m_i2c_lcd_control.writeReg(LCD_CMD,  DISPLAY_CMD_SET_INVERT_1306);
    234     } else {
    235         rv = m_i2c_lcd_control.writeReg(LCD_CMD,  DISPLAY_CMD_SET_NORMAL_1306);
    236     }
    237     return rv;
    238 }
    239 
    240 
    241 void SSD1306::startscrollright(uint8_t start, uint8_t stop){
    242     m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_RIGHT_HORIZONTAL_SCROLL);
    243     m_i2c_lcd_control.writeReg(LCD_CMD,0X00);
    244     m_i2c_lcd_control.writeReg(LCD_CMD,start);
    245     m_i2c_lcd_control.writeReg(LCD_CMD,0X00);
    246     m_i2c_lcd_control.writeReg(LCD_CMD,stop);
    247     m_i2c_lcd_control.writeReg(LCD_CMD,0X00);
    248     m_i2c_lcd_control.writeReg(LCD_CMD,0XFF);
    249     m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_ACTIVATE_SCROLL);
    250 }
    251 
    252 
    253 void SSD1306::startscrollleft(uint8_t start, uint8_t stop){
    254     m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_LEFT_HORIZONTAL_SCROLL);
    255     m_i2c_lcd_control.writeReg(LCD_CMD,0X00);
    256     m_i2c_lcd_control.writeReg(LCD_CMD,start);
    257     m_i2c_lcd_control.writeReg(LCD_CMD,0X00);
    258     m_i2c_lcd_control.writeReg(LCD_CMD,stop);
    259     m_i2c_lcd_control.writeReg(LCD_CMD,0X00);
    260     m_i2c_lcd_control.writeReg(LCD_CMD,0XFF);
    261     m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_ACTIVATE_SCROLL);
    262 }
    263 
    264 void SSD1306::startscrolldiagright(uint8_t start, uint8_t stop){
    265     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SET_VERTICAL_SCROLL_AREA);
    266     m_i2c_lcd_control.writeReg(LCD_CMD, 0X00);
    267     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_LCDHEIGHT);
    268     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
    269     m_i2c_lcd_control.writeReg(LCD_CMD, 0X00);
    270     m_i2c_lcd_control.writeReg(LCD_CMD, start);
    271     m_i2c_lcd_control.writeReg(LCD_CMD, 0X00);
    272     m_i2c_lcd_control.writeReg(LCD_CMD, stop);
    273     m_i2c_lcd_control.writeReg(LCD_CMD, 0X01);
    274     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_ACTIVATE_SCROLL);
    275 }
    276 
    277 void SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop){
    278     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SET_VERTICAL_SCROLL_AREA);
    279     m_i2c_lcd_control.writeReg(LCD_CMD, 0X00);
    280     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_LCDHEIGHT);
    281     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
    282     m_i2c_lcd_control.writeReg(LCD_CMD, 0X00);
    283     m_i2c_lcd_control.writeReg(LCD_CMD, start);
    284     m_i2c_lcd_control.writeReg(LCD_CMD, 0X00);
    285     m_i2c_lcd_control.writeReg(LCD_CMD, stop);
    286     m_i2c_lcd_control.writeReg(LCD_CMD, 0X01);
    287     m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_ACTIVATE_SCROLL);
    288 }
    289 
    290 void SSD1306::stopscroll(void){
    291     m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_DEACTIVATE_SCROLL);
    292 }
    293 
    294 // Dim the display
    295 // dim = true: display is dimmed
    296 // dim = false: display is normal
    297 void SSD1306::dim(bool dim) {
    298     uint8_t contrast;
    299 
    300     if (dim) {
    301     contrast = 0; // Dimmed display
    302     } else {
    303     if (_vccstate == SSD1306_EXTERNALVCC) {
    304       contrast = 0x9F;
    305     } else {
    306       contrast = 0xCF;
    307     }
    308     }
    309     // the range of contrast to too small to be really useful
    310     // it is useful to dim the display
    311     m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_SETCONTRAST);
    312     m_i2c_lcd_control.writeReg(LCD_CMD,contrast);
    313 }
    314