/* * Author: Marc Graham <marc@m2ag.net> * Copyright (c) 2015 Intel Corporation * * Adapted from ssd1308 library. * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com> * Copyright (c) 2014 Intel Corporation. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include <string> #include <unistd.h> #include "hd44780_bits.h" #include "ssd1306.h" using namespace upm; SSD1306::SSD1306(int bus_in, int addr_in) : m_i2c_lcd_control(bus_in) { int vccstate = SSD1306_SWITCHCAPVCC; _vccstate = vccstate; int LCD_CMD = 0x00; m_lcd_control_address = addr_in; m_name = "SSD1306"; mraa::Result error = m_i2c_lcd_control.address(m_lcd_control_address); if (error != mraa::SUCCESS) { throw std::runtime_error(std::string(__FUNCTION__) + ": mraa_i2c_address() failed"); return; } error = m_i2c_lcd_control.frequency(mraa::I2C_FAST); if (error != mraa::SUCCESS) { throw std::invalid_argument(std::string(__FUNCTION__) + ": mraa_i2c_frequency(MRAA_I2C_FAST) failed"); return; } m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_OFF); // display off usleep(4500); //ADD 1306 stuff // Init sequence for 128x64 OLED module // 0xAE m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 m_i2c_lcd_control.writeReg(LCD_CMD, 0x80); // the suggested ratio 0x80 m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETMULTIPLEX); // 0xA8 m_i2c_lcd_control.writeReg(LCD_CMD, 0x3F); m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETDISPLAYOFFSET); // 0xD3 m_i2c_lcd_control.writeReg(LCD_CMD, 0x0); // no offset m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETSTARTLINE | 0x0); // line #0 m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_CHARGEPUMP); // 0x8D if (vccstate == SSD1306_EXTERNALVCC) { m_i2c_lcd_control.writeReg(LCD_CMD, 0x10); } else { m_i2c_lcd_control.writeReg(LCD_CMD,0x14); } m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_MEMORYMODE); // 0x20 m_i2c_lcd_control.writeReg(LCD_CMD, 0x00); // 0x0 act like ks0108 m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SEGREMAP | 0x1); m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_COMSCANDEC); m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETCOMPINS); // 0xDA m_i2c_lcd_control.writeReg(LCD_CMD, 0x12); m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETCONTRAST); // 0x81 if (vccstate == SSD1306_EXTERNALVCC) { m_i2c_lcd_control.writeReg(LCD_CMD, 0x9F); } else { m_i2c_lcd_control.writeReg(LCD_CMD, 0xCF); } m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETPRECHARGE); // 0xd9 if (vccstate == SSD1306_EXTERNALVCC) { m_i2c_lcd_control.writeReg(LCD_CMD, 0x22); } else { m_i2c_lcd_control.writeReg(LCD_CMD,0xF1); } m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETVCOMDETECT); // 0xDB m_i2c_lcd_control.writeReg(LCD_CMD, 0x40); m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_DISPLAYALLON_RESUME); // 0xA4 m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_SET_NORMAL_1306); // 0xA6 //END 1306 Stuff m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_ON); // display on usleep(4500); setNormalDisplay(); // set to normal display '1' is ON clear(); setAddressingMode(PAGE); } SSD1306::~SSD1306() { } mraa::Result SSD1306::draw(uint8_t* data, int bytes) { mraa::Result error = mraa::SUCCESS; setAddressingMode(HORIZONTAL); for (int idx = 0; idx < bytes; idx++) { m_i2c_lcd_control.writeReg(LCD_DATA, data[idx]); } return error; } /* * ************** * virtual area * ************** */ mraa::Result SSD1306::write(std::string msg) { mraa::Result error = mraa::SUCCESS; setAddressingMode(PAGE); for (std::string::size_type i = 0; i < msg.size(); ++i) { writeChar(msg[i]); } return error; } mraa::Result SSD1306::setCursor(int row, int column) { mraa::Result error = mraa::SUCCESS; error = m_i2c_lcd_control.writeReg(LCD_CMD, BASE_PAGE_START_ADDR + row); // set page address error = m_i2c_lcd_control.writeReg(LCD_CMD, BASE_LOW_COLUMN_ADDR + (8 * column & 0x0F)); // set column // lower address error = m_i2c_lcd_control.writeReg(LCD_CMD, BASE_HIGH_COLUMN_ADDR + ((8 * column >> 4) & 0x0F)); // set column higher address return error; } mraa::Result SSD1306::clear() { mraa::Result error = mraa::SUCCESS; uint8_t columnIdx, rowIdx; m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_OFF); // display off for (rowIdx = 0; rowIdx < 8; rowIdx++) { setCursor(rowIdx, 0); // clear all columns for (columnIdx = 0; columnIdx < 16; columnIdx++) { writeChar(' '); } } m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_ON); // display on home(); return error; } mraa::Result SSD1306::home() { return setCursor(0, 0); } /* * ************** * private area * ************** */ mraa::Result SSD1306::writeChar(uint8_t value) { mraa::Result rv; if (value < 0x20 || value > 0x7F) { value = 0x20; // space } for (uint8_t idx = 0; idx < 8; idx++) { rv = m_i2c_lcd_control.writeReg(LCD_DATA, BasicFont[value - 32][idx]); } return rv; } mraa::Result SSD1306::setNormalDisplay() { return m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_SET_NORMAL_1306); // set to normal display '1' is // ON } mraa::Result SSD1306::setAddressingMode(displayAddressingMode mode) { mraa::Result rv; rv =m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_MEM_ADDR_MODE); // set addressing mode rv =m_i2c_lcd_control.writeReg(LCD_CMD, mode); // set page addressing mode return rv; } mraa::Result SSD1306::invert(bool i) { mraa::Result rv; if(i){ rv = m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_SET_INVERT_1306); } else { rv = m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_SET_NORMAL_1306); } return rv; } void SSD1306::startscrollright(uint8_t start, uint8_t stop){ m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_RIGHT_HORIZONTAL_SCROLL); m_i2c_lcd_control.writeReg(LCD_CMD,0X00); m_i2c_lcd_control.writeReg(LCD_CMD,start); m_i2c_lcd_control.writeReg(LCD_CMD,0X00); m_i2c_lcd_control.writeReg(LCD_CMD,stop); m_i2c_lcd_control.writeReg(LCD_CMD,0X00); m_i2c_lcd_control.writeReg(LCD_CMD,0XFF); m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_ACTIVATE_SCROLL); } void SSD1306::startscrollleft(uint8_t start, uint8_t stop){ m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_LEFT_HORIZONTAL_SCROLL); m_i2c_lcd_control.writeReg(LCD_CMD,0X00); m_i2c_lcd_control.writeReg(LCD_CMD,start); m_i2c_lcd_control.writeReg(LCD_CMD,0X00); m_i2c_lcd_control.writeReg(LCD_CMD,stop); m_i2c_lcd_control.writeReg(LCD_CMD,0X00); m_i2c_lcd_control.writeReg(LCD_CMD,0XFF); m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_ACTIVATE_SCROLL); } void SSD1306::startscrolldiagright(uint8_t start, uint8_t stop){ m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SET_VERTICAL_SCROLL_AREA); m_i2c_lcd_control.writeReg(LCD_CMD, 0X00); m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_LCDHEIGHT); m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL); m_i2c_lcd_control.writeReg(LCD_CMD, 0X00); m_i2c_lcd_control.writeReg(LCD_CMD, start); m_i2c_lcd_control.writeReg(LCD_CMD, 0X00); m_i2c_lcd_control.writeReg(LCD_CMD, stop); m_i2c_lcd_control.writeReg(LCD_CMD, 0X01); m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_ACTIVATE_SCROLL); } void SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop){ m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SET_VERTICAL_SCROLL_AREA); m_i2c_lcd_control.writeReg(LCD_CMD, 0X00); m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_LCDHEIGHT); m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL); m_i2c_lcd_control.writeReg(LCD_CMD, 0X00); m_i2c_lcd_control.writeReg(LCD_CMD, start); m_i2c_lcd_control.writeReg(LCD_CMD, 0X00); m_i2c_lcd_control.writeReg(LCD_CMD, stop); m_i2c_lcd_control.writeReg(LCD_CMD, 0X01); m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_ACTIVATE_SCROLL); } void SSD1306::stopscroll(void){ m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_DEACTIVATE_SCROLL); } // Dim the display // dim = true: display is dimmed // dim = false: display is normal void SSD1306::dim(bool dim) { uint8_t contrast; if (dim) { contrast = 0; // Dimmed display } else { if (_vccstate == SSD1306_EXTERNALVCC) { contrast = 0x9F; } else { contrast = 0xCF; } } // the range of contrast to too small to be really useful // it is useful to dim the display m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_SETCONTRAST); m_i2c_lcd_control.writeReg(LCD_CMD,contrast); }