--- lcdproc-0.5.6/server/drivers/hd44780-i2c.c 2010-12-27 06:32:57.000000000 -0700 +++ RPi-OLED-Display-SSD1311/hd44780-i2c.c 2015-07-09 22:52:19.193298735 -0600 @@ -12,40 +12,6 @@ * 1998 Richard Rognlie * 1997 Matthias Prinke * - * The connections are: - * PCF8574AP LCD - * P0 (4) D4 (11) - * P1 (5) D5 (12) - * P2 (6) D6 (13) - * P3 (7) D7 (14) - * P4 (9) RS (4) - * P5 (10) RW (5) - * P6 (11) EN (6) - * - * Backlight - * P7 (12) /backlight (optional, active-low) - * - * Configuration: - * device=/dev/i2c-0 # the device file of the i2c bus - * port=0x20 # the i2c address of the i2c port expander - * - * Attention: Bit 8 of the address given in port is special: - * It tells the driver to treat the device as PCA9554 or similar, - * a device that needs a 2-byte command, and it will be stripped - * off the address. - * So we have: - * port=0x20..0x27 PCF8574 with A[012]=0..7 - * port=0x38..0x3f PCF8574A with A[012]=0..7 - * port=0xa0..0xa7 PCA9554 with A[012]=0..7 - * port=0xa0..0xa7 PCA9554A with A[012]=0..7 - * - * When using this driver, DON'T load the i2c chip module (e.g. pcf8574), - * you only need the i2c bus driver module! - * - * - * Based mostly on the hd44780-4bit module, see there for a complete history. - * Suggestions for PCA9554 support from Tonu Samuel . - * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. */ @@ -54,17 +20,26 @@ #include "hd44780-low.h" #include "report.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include #include #include #include #include #include + +#ifdef HAVE_DEV_IICBUS_IIC_H +#include +#else /* HAVE_LINUX_I2C_DEV_H */ #include /* I2C_SLAVE is missing in linux/i2c-dev.h from kernel headers of 2.4.x kernels */ #ifndef I2C_SLAVE #define I2C_SLAVE 0x0703 /* Change slave address */ #endif +#endif + // Generally, any function that accesses the LCD control lines needs to be // implemented separately for each HW design. This is typically (but not @@ -76,9 +51,9 @@ void i2c_HD44780_backlight(PrivateData *p, unsigned char state); void i2c_HD44780_close(PrivateData *p); -#define RS 0x10 -#define RW 0x20 -#define EN 0x40 +//#define RS 0x10 +//#define RW 0x20 +//#define EN 0x40 #define BL 0x80 // note that the above bits are all meant for the data port of PCF8574 @@ -86,21 +61,36 @@ #define I2C_PCAX_MASK 0x80 static void -i2c_out(PrivateData *p, unsigned char val) +i2c_out(PrivateData *p, unsigned char val[2]) { - __u8 data[2]; +// char data[2]; int datalen; static int no_more_errormsgs=0; - if (p->port & I2C_PCAX_MASK) { // we have a PCA9554 or similar, that needs a 2-byte command - data[0]=1; // command: read/write output port register - data[1]=val; - datalen=2; - } else { // we have a PCF8574 or similar, that needs a 1-byte command - data[0]=val; - datalen=1; - } - if (write(p->fd,data,datalen) != datalen) { - p->hd44780_functions->drv_report(no_more_errormsgs?RPT_DEBUG:RPT_ERR, "HD44780: I2C: i2c write data %u to address %u failed: %s", +#ifdef HAVE_DEV_IICBUS_IIC_H + struct iiccmd cmd; + bzero(&cmd, sizeof(cmd)); +#endif + +// if (p->port & I2C_PCAX_MASK) { // we have a PCA9554 or similar, that needs a 2-byte command +// data[0]=1; // command: read/write output port register +// data[1]=val; + datalen=2; +// } else { // we have a PCF8574 or similar, that needs a 1-byte command +// data[0]=val; +// datalen=1; +// } + +#ifdef HAVE_DEV_IICBUS_IIC_H + cmd.slave = (p->port & I2C_ADDR_MASK) << 1; + cmd.last = 1; + cmd.count = datalen; + cmd.buf = val; + + if (ioctl(p->fd, I2CWRITE, &cmd) < 0) { +#else /* HAVE_LINUX_I2C_DEV_H */ + if (write(p->fd,val,datalen) != datalen) { +#endif + p->hd44780_functions->drv_report(no_more_errormsgs?RPT_DEBUG:RPT_ERR, "HD44780: I2C: i2c write data %u to address 0x%02X failed: %s", val, p->port & I2C_ADDR_MASK, strerror(errno)); no_more_errormsgs=1; } @@ -121,8 +111,14 @@ PrivateData *p = (PrivateData*) drvthis->private_data; HD44780_functions *hd44780_functions = p->hd44780_functions; - int enableLines = EN; +// int enableLines = EN; char device[256] = DEFAULT_DEVICE; +#ifdef HAVE_DEV_IICBUS_IIC_H + struct iiccmd cmd; + bzero(&cmd, sizeof(cmd)); +#endif + +//###?? p->backlight_bit = BL; p->backlight_bit = BL; /* READ CONFIG FILE */ @@ -130,7 +126,7 @@ /* Get serial device to use */ strncpy(device, drvthis->config_get_string(drvthis->name, "Device", 0, DEFAULT_DEVICE), sizeof(device)); device[sizeof(device)-1] = '\0'; - report(RPT_INFO,"HD44780: I2C: Using device '%s' and address %u for a %s", + report(RPT_INFO,"HD44780: I2C: Using device '%s' and address 0x%02X for a %s", device, p->port & I2C_ADDR_MASK, (p->port & I2C_PCAX_MASK) ? "PCA9554(A)" : "PCF8574(A)"); // Open the I2C device @@ -141,89 +137,125 @@ } // Set I2C address +#ifdef HAVE_DEV_IICBUS_IIC_H + cmd.slave = (p->port & I2C_ADDR_MASK) << 1; + cmd.last = 0; + cmd.count = 0; + if (ioctl(p->fd, I2CRSTCARD, &cmd) < 0) { + report(RPT_ERR, "HD44780: I2C: reset bus failed: %s", strerror(errno)); + return -1; + } + if (ioctl(p->fd, I2CSTART, &cmd) < 0) { + report(RPT_ERR, "HD44780: I2C: set address to 0x%02X: %s", p->port & I2C_ADDR_MASK, strerror(errno)); + return -1; + } +#else /* HAVE_LINUX_I2C_DEV_H */ if (ioctl(p->fd,I2C_SLAVE, p->port & I2C_ADDR_MASK) < 0) { report(RPT_ERR, "HD44780: I2C: set address to '%i': %s", p->port & I2C_ADDR_MASK, strerror(errno)); return(-1); } - - - if (p->port & I2C_PCAX_MASK) { // we have a PCA9554 or similar, that needs special config - __u8 data[2]; - data[0] = 2; // command: set polarity inversion - data[1] = 0; // -> no polarity inversion - if (write(p->fd,data,2) != 2) { - report(RPT_ERR, "HD44780: I2C: i2c set polarity inversion failed: %s", strerror(errno)); - } - data[0] = 3; // command: set output direction - data[1] = 0; // -> all pins are outputs - if (write(p->fd,data,2) != 2) { - report(RPT_ERR, "HD44780: I2C: i2c set output direction failed: %s", strerror(errno)); - } - } - +#endif hd44780_functions->senddata = i2c_HD44780_senddata; hd44780_functions->backlight = i2c_HD44780_backlight; hd44780_functions->close = i2c_HD44780_close; + /* Display init */ - // powerup the lcd now - /* We'll now send 0x03 a couple of times, - * which is in fact (FUNCSET | IF_8BIT) >> 4 */ - i2c_out(p, 0x03); - if (p->delayBus) - hd44780_functions->uPause(p, 1); - - i2c_out(p, enableLines | 0x03); - if (p->delayBus) - hd44780_functions->uPause(p, 1); - i2c_out(p, 0x03); - hd44780_functions->uPause(p, 15000); - - i2c_out(p, enableLines | 0x03); - if (p->delayBus) - hd44780_functions->uPause(p, 1); - i2c_out(p, 0x03); - hd44780_functions->uPause(p, 5000); - - i2c_out(p, enableLines | 0x03); - if (p->delayBus) - hd44780_functions->uPause(p, 1); - i2c_out(p, 0x03); - hd44780_functions->uPause(p, 100); - - i2c_out(p, enableLines | 0x03); - if (p->delayBus) - hd44780_functions->uPause(p, 1); - i2c_out(p, 0x03); - hd44780_functions->uPause(p, 100); - - // now in 8-bit mode... set 4-bit mode - i2c_out(p, 0x02); - if (p->delayBus) - hd44780_functions->uPause(p, 1); - - i2c_out(p, enableLines | 0x02); - if (p->delayBus) - hd44780_functions->uPause(p, 1); - i2c_out(p, 0x02); - hd44780_functions->uPause(p, 100); - - // Set up two-line, small character (5x8) mode - hd44780_functions->senddata(p, 0, RS_INSTR, FUNCSET | IF_4BIT | TWOLINE | SMALLCHAR); - hd44780_functions->uPause(p, 40); - - common_init(p, IF_4BIT); + unsigned char data[2]; + data[0] = 0x80; + i2c_out(p, data); + + data[1] = 0x2A; // **** Set "RE"=1<--->00101010B + i2c_out(p, data); + data[1] = 0x71; //# Function Selection A [71h] (IS = X, RE = 1, SD=0;, 2bajty + i2c_out(p, data); + data[1] = 0x5C; // 0x5C set Vdd + i2c_out(p, data); + data[1] = 0x28; + i2c_out(p, data); + + data[1] = 0x08; // **** Set Sleep Mode On + i2c_out(p, data); + data[1] = 0x2A; // **** Set "RE"=1 00101010B + i2c_out(p, data); + data[1] = 0x79; // **** Set "SD"=1 01111001B + i2c_out(p, data); + + data[1] = 0xD5; //# Set Display Clock Divide Ratio/ Oscillator Frequency (D5h + i2c_out(p, data); + data[1] = 0x70; + i2c_out(p, data); + data[1] = 0x78; // **** Set "SD"=0 + i2c_out(p, data); + + data[1] = 0x08; // **** Set 5-dot, 3 or 4 line(0x09;, 1 or 2 line(0x08; + i2c_out(p, data); + + data[1] = 0x06; // **** Set Com31-->Com0 Seg0-->Seg99 + i2c_out(p, data); + + //**** Set OLED Characterization + data[1] = 0x2A; // **** Set "RE"=1 + i2c_out(p, data); + data[1] = 0x79; // **** Set "SD"=1 + i2c_out(p, data); + + // **** CGROM/CGRAM Management *** // + data[1] = 0x72; // **** Set ROM + i2c_out(p, data); + data[1] = 0x00; // **** Set ROM A and 8 CGRAM + i2c_out(p, data); + + data[1] = 0xDA; // **** Set Seg Pins HW Config + i2c_out(p, data); + data[1] = 0x10; + i2c_out(p, data); + + //data[1] = 0x81; // **** Set Contrast + //i2c_out(p, data); + //data[1] = 0x50; + //i2c_out(p, data); + + data[1] = 0xDB; // **** Set VCOM deselect level + i2c_out(p, data); + data[1] = 0x30; // **** VCC x 0.83 + i2c_out(p, data); + + data[1] = 0xDC; // **** Set gpio - turn EN for 15V generator on. + i2c_out(p, data); + data[1] = 0x03; + i2c_out(p, data); + + data[1] = 0x78; // **** Exiting Set OLED Characterization + i2c_out(p, data); + data[1] = 0x28; + i2c_out(p, data); + data[1] = 0x2A; + i2c_out(p, data); + data[1] = 0x6; // **** Set Entry Mode + i2c_out(p, data); + data[1] = 0x08; + i2c_out(p, data); + data[1] = 0x28; // **** Set "IS"=0 , "RE" =0 //28 + i2c_out(p, data); + i2c_out(p, data); + data[1] = 0x01; + i2c_out(p, data); + data[1] = 0x80; // **** Set DDRAM Address to 0x80 (line 1 start; + i2c_out(p, data); + + //sleep 0.1s; + data[1] = 0x0C; // **** Turn on Display + i2c_out(p, data); return 0; } - -/** - * Close the device. - * \param p Pointer to driver's private data structure. - */ void i2c_HD44780_close(PrivateData *p) { if (p->fd >= 0) { +#ifdef HAVE_DEV_IICBUS_IIC_H + ioctl(p->fd, I2CSTOP); +#endif close(p->fd); } } @@ -239,34 +271,13 @@ void i2c_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch) { - unsigned char enableLines = 0, portControl = 0; - unsigned char h = (ch >> 4) & 0x0f; // high and low nibbles - unsigned char l = ch & 0x0f; - + unsigned char data[2]; if (flags == RS_INSTR) - portControl = 0; - else //if (flags == RS_DATA) - portControl = RS; - - portControl |= p->backlight_bit; - - enableLines = EN; - - i2c_out(p, portControl | h); - if (p->delayBus) - p->hd44780_functions->uPause(p, 1); - i2c_out(p, enableLines | portControl | h); - if (p->delayBus) - p->hd44780_functions->uPause(p, 1); - i2c_out(p, portControl | h); - - i2c_out(p, portControl | l); - if (p->delayBus) - p->hd44780_functions->uPause(p, 1); - i2c_out(p, enableLines | portControl | l); - if (p->delayBus) - p->hd44780_functions->uPause(p, 1); - i2c_out(p, portControl | l); + data[0] = 0x80; + else + data[0] = 0x40; + data[1] = ch; + i2c_out(p, data); } @@ -277,7 +288,35 @@ */ void i2c_HD44780_backlight(PrivateData *p, unsigned char state) { - p->backlight_bit = ((!p->have_backlight||state) ? 0 : BL); - i2c_out(p, p->backlight_bit); +// printf("Backlight %d",state); + unsigned char data[2]; + + data[0] = 0x80; + data[1] = 0x2A; + i2c_out(p, data); + +// data[0] = 0x80; + data[1] = 0x79; + i2c_out(p, data); + +// data[0] = 0x80; + data[1] = 0x81; + i2c_out(p, data); + +// data[0] = 0x80; + if (state) + data[1] = 240; + else + data[1] = 50; + i2c_out(p, data); + +// data[0] = 0x80; + data[1] = 0x78; + i2c_out(p, data); + +// data[0] = 0x80; + data[1] = 0x28; + i2c_out(p, data); + }