From 606e2913f06ef11a7e342c9a89287dbb28c74266 Mon Sep 17 00:00:00 2001 From: Rhys Williams Date: Sat, 23 Jul 2016 11:14:53 +1200 Subject: [PATCH] Update i2c driver to have pins defined via config file, rather than hardcoded --- docs/lcdproc-user/drivers/hd44780.docbook | 55 +++++++++ server/drivers/hd44780-i2c.c | 132 ++++++++++++++++------ server/drivers/hd44780-low.h | 15 +++ 3 files changed, 165 insertions(+), 37 deletions(-) diff --git a/docs/lcdproc-user/drivers/hd44780.docbook b/docs/lcdproc-user/drivers/hd44780.docbook index 324a82a..721e5fa 100644 --- a/docs/lcdproc-user/drivers/hd44780.docbook +++ b/docs/lcdproc-user/drivers/hd44780.docbook @@ -2516,6 +2516,61 @@ Size=40x2 DelayBus=false DelayMult=1 Keypad=no +#i2c_line_RS=0x10 +#i2c_line_RW=0x20 +#i2c_line_EN=0x40 +#i2c_line_BL=0x80 +#i2c_line_D4=0x01 +#i2c_line_D5=0x02 +#i2c_line_D6=0x04 +#i2c_line_D7=0x08 +# BacklightInvert=yes +# The Backlight Invert is used if a 0 turns the backlight on, and 1 turns it off, i.e. npn transistor +]]> + + + + +If your port expander has different wiring you can re-assign the pins in the config file + + + +HD44780: Configuration for I<superscript>2</superscript>C with port expander +Alternative Wiring + + + + + + +HD44780: Configuration for I<superscript>2</superscript>C with port expander +alternative config + + diff --git a/server/drivers/hd44780-i2c.c b/server/drivers/hd44780-i2c.c index 0a5e45e..8f19694 100644 --- a/server/drivers/hd44780-i2c.c +++ b/server/drivers/hd44780-i2c.c @@ -13,17 +13,38 @@ * 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) + * PCF8574AP Bit LCD + * P0 (4) 0x01 D4 (11) + * P1 (5) 0x02 D5 (12) + * P2 (6) 0x04 D6 (13) + * P3 (7) 0x08 D7 (14) + * P4 (9) 0x10 RS (4) + * P5 (10) 0x20 RW (5) + * P6 (11) 0x40 EN (6) + * P7 (12) 0x80 /backlight (optional, active-low) * - * Backlight - * P7 (12) /backlight (optional, active-low) + * Configuration: + \verbatim + alternative wiring example: + PCF8574AP: P0 P1 P2 P3 P4 P5 P6 P7 + | | | | | | | | + HD44780: RS RW EN BL D4 D5 D6 D7 + + in LCDd.conf we then need to define + i2c_line_RS=0x01 + i2c_line_RW=0x02 + i2c_line_EN=0x04 + i2c_line_BL=0x80 + i2c_line_D4=0x10 + i2c_line_D5=0x20 + i2c_line_D6=0x40 + i2c_line_D7=0x80 + Backlight=yes + BacklightInvert=yes + + The Backlight Invert is used if a 0 turns the backlight on, and 1 turns it off, i.e. npn transistor +\endverbatim + * * Configuration: * device=/dev/i2c-0 # the device file of the i2c bus @@ -89,6 +110,11 @@ void i2c_HD44780_close(PrivateData *p); #define RW 0x20 #define EN 0x40 #define BL 0x80 +#define D4 0x01 +#define D5 0x02 +#define D6 0x04 +#define D7 0x08 +#define BL_INVERT 0 // note that the above bits are all meant for the data port of PCF8574 #define I2C_ADDR_MASK 0x7f @@ -145,14 +171,34 @@ hd_init_i2c(Driver *drvthis) PrivateData *p = (PrivateData*) drvthis->private_data; HD44780_functions *hd44780_functions = p->hd44780_functions; - int enableLines = EN; - char device[256] = DEFAULT_DEVICE; + p->i2c_backlight_invert = drvthis->config_get_bool(drvthis->name, "BacklightInvert", 0, BL_INVERT); + p->i2c_line_RS = drvthis->config_get_int(drvthis->name, "i2c_line_RS", 0, RS); + p->i2c_line_RW = drvthis->config_get_int(drvthis->name, "i2c_line_RW", 0, RW); + p->i2c_line_EN = drvthis->config_get_int(drvthis->name, "i2c_line_EN", 0, EN); + p->i2c_line_BL = drvthis->config_get_int(drvthis->name, "i2c_line_BL", 0, BL); + p->i2c_line_D4 = drvthis->config_get_int(drvthis->name, "i2c_line_D4", 0, D4); + p->i2c_line_D5 = drvthis->config_get_int(drvthis->name, "i2c_line_D5", 0, D5); + p->i2c_line_D6 = drvthis->config_get_int(drvthis->name, "i2c_line_D6", 0, D6); + p->i2c_line_D7 = drvthis->config_get_int(drvthis->name, "i2c_line_D7", 0, D7); + + report(RPT_INFO, "HD44780: I2C: Init using D4 and D5, and or'd lines, invert", p->i2c_line_RS); + report(RPT_INFO, "HD44780: I2C: Pin RS mapped to 0x%02X", p->i2c_line_RS); + report(RPT_INFO, "HD44780: I2C: Pin RW mapped to 0x%02X", p->i2c_line_RW); + report(RPT_INFO, "HD44780: I2C: Pin EN mapped to 0x%02X", p->i2c_line_EN); + report(RPT_INFO, "HD44780: I2C: Pin BL mapped to 0x%02X", p->i2c_line_BL); + report(RPT_INFO, "HD44780: I2C: Pin D4 mapped to 0x%02X", p->i2c_line_D4); + report(RPT_INFO, "HD44780: I2C: Pin D5 mapped to 0x%02X", p->i2c_line_D5); + report(RPT_INFO, "HD44780: I2C: Pin D6 mapped to 0x%02X", p->i2c_line_D6); + report(RPT_INFO, "HD44780: I2C: Pin D7 mapped to 0x%02X", p->i2c_line_D7); + report(RPT_INFO, "HD44780: I2C: Invert Backlight %d", p->i2c_backlight_invert); + + 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 = p->i2c_line_BL; /* READ CONFIG FILE */ @@ -209,44 +255,49 @@ hd_init_i2c(Driver *drvthis) // 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); + * which is in fact (FUNCSET | IF_8BIT) >> 4 + */ + i2c_out(p, p->i2c_line_D4 | p->i2c_line_D5); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, enableLines | 0x03); + i2c_out(p, p->i2c_line_EN | p->i2c_line_D4 | p->i2c_line_D5); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, 0x03); + i2c_out(p, p->i2c_line_D4 | p->i2c_line_D5); hd44780_functions->uPause(p, 15000); - i2c_out(p, enableLines | 0x03); + i2c_out(p, p->i2c_line_EN | p->i2c_line_D4 | p->i2c_line_D5); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, 0x03); + i2c_out(p, p->i2c_line_D4 | p->i2c_line_D5); hd44780_functions->uPause(p, 5000); - i2c_out(p, enableLines | 0x03); + i2c_out(p, p->i2c_line_EN | p->i2c_line_D4 | p->i2c_line_D5); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, 0x03); + i2c_out(p, p->i2c_line_D4 | p->i2c_line_D5); hd44780_functions->uPause(p, 100); - i2c_out(p, enableLines | 0x03); + i2c_out(p, p->i2c_line_EN | p->i2c_line_D4 | p->i2c_line_D5); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, 0x03); + i2c_out(p, p->i2c_line_D4 | p->i2c_line_D5); hd44780_functions->uPause(p, 100); // now in 8-bit mode... set 4-bit mode - i2c_out(p, 0x02); + /* + OLD (FUNCSET | IF_4BIT) >> 4 0x02 + ALT (FUNCSET | IF_4BIT) 0x20 + */ + i2c_out(p, p->i2c_line_D5); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, enableLines | 0x02); + i2c_out(p, p->i2c_line_EN | p->i2c_line_D5); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, 0x02); + i2c_out(p, p->i2c_line_D5); hd44780_functions->uPause(p, 100); // Set up two-line, small character (5x8) mode @@ -279,23 +330,28 @@ i2c_HD44780_close(PrivateData *p) { 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 portControl = 0; + unsigned char h=0; + unsigned char l=0; + if( ch & 0x80 ) h |= p->i2c_line_D7; + if( ch & 0x40 ) h |= p->i2c_line_D6; + if( ch & 0x20 ) h |= p->i2c_line_D5; + if( ch & 0x10 ) h |= p->i2c_line_D4; + if( ch & 0x08 ) l |= p->i2c_line_D7; + if( ch & 0x04 ) l |= p->i2c_line_D6; + if( ch & 0x02 ) l |= p->i2c_line_D5; + if( ch & 0x01 ) l |= p->i2c_line_D4; if (flags == RS_INSTR) portControl = 0; else //if (flags == RS_DATA) - portControl = RS; + portControl = p->i2c_line_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); + i2c_out(p, p->i2c_line_EN | portControl | h); if (p->delayBus) p->hd44780_functions->uPause(p, 1); i2c_out(p, portControl | h); @@ -303,7 +359,7 @@ i2c_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flag i2c_out(p, portControl | l); if (p->delayBus) p->hd44780_functions->uPause(p, 1); - i2c_out(p, enableLines | portControl | l); + i2c_out(p, p->i2c_line_EN | portControl | l); if (p->delayBus) p->hd44780_functions->uPause(p, 1); i2c_out(p, portControl | l); @@ -317,7 +373,9 @@ i2c_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flag */ void i2c_HD44780_backlight(PrivateData *p, unsigned char state) { - p->backlight_bit = ((!p->have_backlight||state) ? 0 : BL); - + if ( p->i2c_backlight_invert == 0 ) + p->backlight_bit = ((!p->have_backlight||state) ? 0 : p->i2c_line_BL); + else // Inverted backlight - npn transistor + p->backlight_bit = ((p->have_backlight && state) ? p->i2c_line_BL : 0); i2c_out(p, p->backlight_bit); } diff --git a/server/drivers/hd44780-low.h b/server/drivers/hd44780-low.h index 47acf45..8b7bba6 100644 --- a/server/drivers/hd44780-low.h +++ b/server/drivers/hd44780-low.h @@ -155,6 +155,21 @@ typedef struct hd44780_private_data { int ftdi_line_backlight; #endif +#ifdef HAVE_I2C + /* libi2c-based connection types */ + + int i2c_backlight_invert; + int i2c_line_RS; + int i2c_line_RW; + int i2c_line_EN; + int i2c_line_BL; + int i2c_line_D4; + int i2c_line_D5; + int i2c_line_D6; + int i2c_line_D7; + +#endif + #ifdef WITH_ETHLCD int sock; /**< socket for TCP devices */ #endif