Rod Coleman / I2CTextLCD

I2CTextLCD.cpp

Committer:
RodColeman
Date:
2013-10-15
Revision:
9:16c12a5da0ac
Parent:
8:4816fdd57607

File content as of revision 9:16c12a5da0ac:

/* mbed I2CTextLCD Library
 * Copyright (c) 2007-2009 sford
 * Copyright (c) 2010 Wim De Roeve  changed to work with I2C PCF8575
 * Released under the MIT License: http://mbed.org/license/mit
 */

#include "I2CTextLCD.h"
#include "mbed.h"
#include "error.h"

using namespace mbed;

I2CTextLCD::I2CTextLCD(PinName sda, PinName scl, int i2cAddress , int columns, int rows,
                       bool backlight) : _i2c(sda, scl) {

    _i2cAddress = i2cAddress;
    _columns = columns;
    _rows = rows;
    _backlight=backlight;
    _i2c.frequency(70000); //  RC:2011-12-1 put this back in

    // Winstar 20x4 WH2004-NYG- needs 40ms after VDD> 4,5V
    //RC:2011-11-23: Newhaven 20x4 OLED data sheet method
    wait(0.055);
    init8574A();         // I2C chip PCF85774A init - E high - E falls with 0x2 on the D-nibble (set 4-bit mode command)
    writeCommand(0x2);   // 4-bit mode
    wait(0.05);
    writeCommand(0x2);   // 4-bit mode
    wait(0.05);
    writeCommand(0x2A);  // 2012-6-22 RC: Russian font Table. was 0x28. display OFF, "Function Set". Newhaven say 0x08, but this loses 2 rows!
    wait(0.05); 
    writeCommand(0x1);  // display clear
    wait(0.05);
    writeCommand(0x6);  // entry mode set
    wait(0.05); 
    writeCommand(0x2);  // 4-bit mode
    wait(0.05);                  
    writeCommand(0x0C); // ON-OFF ctrl: turns display ON, no cursor. Use 0x0E for cursor ON.
    /* 0x28 also works for Winstar WEH002004ALPP5N00000 OLED display. 0x29= westEuro fon table, 0x2A = UK/Russian*/
    wait(0.015);        // Wait 15ms to ensure powered up
}

int I2CTextLCD::_putc(int value) {
    if (value == '\n') {
        newline();
    } 
    else {
        writeData(value);
    }
    return value;
}

int I2CTextLCD::_getc() {
    return 0;
}

/* void I2CTextLCD::backlight(bool status) {
    _backlight=status;
    if (_backlight)
        writeI2CByte(BACKLIGHT_ON | E1_ON);
    else
        writeI2CByte(E1_ON);
}
*/

void I2CTextLCD::newline() {
    _column = 0;
    _row++;
    if (_row >= _rows) {
        _row = 0;
    }
    locate(_column, _row);
}

void I2CTextLCD::locate(int column, int row) {
    if (column < 0 || column >= _columns || row < 0 || row >= _rows) {
        error("locate(%d,%d) out of range on %dx%d display", column, row, _columns, _rows);
        return;
    }
    _row = row;
    _column = column;
    int address = 0x80;
    if (row==0){
    address = 0x80+_column;
    }
    else if (row==1){
    address= 0xc0+_column;
    }
    else if (row==2){
    address=0x94+_column;
    }
    else if(row==3){
    address=0xd4+_column;
    }
    /*
    int address = 0x80 + (_row * 40) + _column; // memory starts at 0x00, and is 40 chars long per row
    Set bit 7 also, to signify  ADDRESS SET mode.
     // pc_LCD.traceOut("locate %dx%d\r\n", column, row);
     */
    writeCommand(address);  // must set bit 7 to indicate address SET command
    wait(0.004);      // takes 1.5ms on Winstar LCD 20x4
}

void I2CTextLCD::cls() {
    writeCommand(0x01); // Clear Display
    wait(0.01f);     // This command takes 1.64 ms (LCD), 6.2ms for Winstar OLED
    locate(0, 0);
}

void I2CTextLCD::reset() {
    cls();
}
void I2CTextLCD::init8574A(void) {  // This puts the first command on the bus with E high
                                    // to prevent E going LOW at init with undef data lines, WS0010 does not like.
        char cmd[2]; 
        cmd[0]=(0x2)<<2;                 // lower nibble
        cmd[0]=cmd[0] & 0x3c; // 3C = 0011 1100
        //RS = 0 for commands - and for init (only), we start with E high
        cmd[0]=cmd[0]|0x02; //E=1
        _i2c.write( _i2cAddress, cmd,1); 
        cmd[0]=cmd[0]&0x3d; //E=0, RS preserved in bit 0
        _i2c.write( _i2cAddress, cmd,1); 
        wait_us(1);
    }
void I2CTextLCD::writeByte(int c, bool rs) {  // This is the actual I2C transfer of the display data:
        char cmd[2]; 
        cmd[0]=c>>2;                  // upper nibble
        cmd[0]=cmd[0] & 0x3c;         // mask out bits other than 5:2 for data (RS and E are enabled separately, below:)
        cmd[1]=c<<2;                 // lower nibble
        cmd[1]=cmd[1] & 0x3c;        // 3C = 0011 1100
        if (rs) {
            cmd[0]=cmd[0] | 0x01;        // RS selects display DATA or a COMMAND. It's on bit 0:
            cmd[1]=cmd[1] | 0x01;
        }
        cmd[0]=cmd[0]|0x02; //E=1
        _i2c.write( _i2cAddress, cmd,1); 
        //wait_us(1); **  delays between nibbles not needed. At 70kHz, the time for the I2C command writes is 114us per byte
        cmd[0]=cmd[0]&0x3d; //E=0, RS preserved in bit 0. Data latched on fall of E (tS(d) = 40ns; tH(d) = 20ns)
        _i2c.write( _i2cAddress, cmd,1); 
        cmd[0]=cmd[1];         // prepare lower nibble
        cmd[0]=cmd[0]|0x02;    //E=1
        _i2c.write( _i2cAddress, cmd,1); 
        cmd[0]=cmd[0]&0x3d;    //E=0, RS preserved in bit 0. this preserves E low beween cycles.
        _i2c.write( _i2cAddress, cmd,1);
        // ****** RECOVERY TIME:
        wait_us(300);         // specified max. recovery time for all operations, except cls(), is 600us
    }

void I2CTextLCD::writeCommand(int command) {
    // RS = 0;
    writeByte(command,false);
}

void I2CTextLCD::writeData(int data) {
    //RS = 1
    writeByte(data,true);

    _column++;
    if (_column >= _columns) {
        newline();
    }
}