HD44780 I2C pin configuration

Help
dsbaars
2012-08-25
1 day ago
  • dsbaars
    dsbaars
    2012-08-25

    Hi,
    I discovered that there are some differences is the I2C backpacks for the HD44780 displays, especially in the pins used for RS/RW/EN and Backlight.

    I have some programming experience so I got mine to work by changing #define's hd44780-i2c.c to:
    #define RS      0x40
    #define RW      0x20
    #define EN      0x10
    #define BL      0x80

    (RS and EN were switched)

    I am not experienced enough to add code to make this configurable in LCDd.conf and submit a patch. Maybe someone else can do this? I'm willing to assist anywhere where I can for making this possible.

     
  • Markus Dolze
    Markus Dolze
    2012-09-01

    The hd44780-i2c driver is designed to work with the schematic described at http://lcdproc.sourceforge.net/docs/current-user.html#hd44780-i2c.

    As you figured out, any pin usage different from the one described there has to be configured in the source code.

    Currently there are no plans to make this configurable.

     
  • Gai-jin
    Gai-jin
    2013-01-15

    Looking at the layout of the backpack board attached to my lcd, it appears the connections are totally different from those depicted in the schematic.  How would the hd44780-i2c driver need to be modified to work with this layout?

    LCD     CHIP
    RS          P0
    RW         P1
    E             P2
    D4          P4
    D5          P5
    D6          P6
    D7          P7
    
     
  • Markus Dolze
    Markus Dolze
    2013-01-17

    Something like this may work. As this forum does not allow to attach files, here comes a small patch a text.

    Index: server/drivers/hd44780-i2c.c
    ===================================================================
    RCS file: /cvsroot/lcdproc/lcdproc/server/drivers/hd44780-i2c.c,v
    retrieving revision 1.14
    diff -u -r1.14 hd44780-i2c.c
    --- server/drivers/hd44780-i2c.c 30 Oct 2010 18:04:21 -0000      1.14
    +++ server/drivers/hd44780-i2c.c 17 Jan 2013 21:06:06 -0000
    @@ -76,10 +76,10 @@
     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 BL      0x80
    +#define RS      0x01  // P0
    +#define RW      0x02  // P1
    +#define EN      0x04  // P2
    +#define BL      0x00  // no backlight
     // note that the above bits are all meant for the data port of PCF8574
    
     #define I2C_ADDR_MASK 0x7f
    @@ -240,8 +240,8 @@
     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 h = ch & 0xf0;     // high and low nibbles
    +        unsigned char l = (ch & 0x0f) << 4;
    
             if (flags == RS_INSTR)
                     portControl = 0;
    
     
  • Gai-jin
    Gai-jin
    2013-01-18

    Thanks!  I'll give that a shot and post back whether it works.  

     
  • Gai-jin
    Gai-jin
    2013-01-19

    That definitely got me closer to a working lcd.  I'm now getting the welcome message when LCDd starts, and the goodbye message when it stops.  Unfortunately, in between those two I am getting dark rectangles, and the occasional blink or garbage.  Since the welcome and goodbye messages are displaying correctly, does that mean that everything is working right with LCDproc?  Or is it still possible I've got something wrong at this level?

     
  • Gai-jin
    Gai-jin
    2013-01-21

    Disregard that previous post.  I don't see any way to edit or delete it, or I would.  With a couple of minor adjustments in the python and config files I was using, that modified driver is working perfectly.  Thank you!

     
  • Gai-jin
    Gai-jin
    2013-01-25

    Okay, I'm still having issues with this.  I can get the LCD working, displaying the expected data, but the backlight turns off.  I've tried a few variations, but nothing I've tried gets the right data to show up on the screen and the backlight to stay on.

    I modified the hd44780-i2c.c file based on the patch above, but had to make a couple of changes.  I changed the value of BL, and of Default_Device, as shown below:

    #define BL 0x80
    #define DEFAULT_DEVICE "/dev/i2c-1"

    With these settings in the driver section of LCDd.conf:

    [hd44780]
    ConnectionType=i2c
    Device=/dev/i2c-1
    Port=0x27
    Backlight=yes
    Size=16x2
    DelayBus=false
    DelayMult=1
    Keypad=no
    

    Using those, I get data to display correctly on the LCD.  if I change the backlight setting in LCDd.conf to backlight=no, the backlight will still turn off, but I get only rectangles on the LCD, no data.

    How can I get the display working and keep the backlight on by default?

     
  • Markus Dolze
    Markus Dolze
    2013-01-25

    define BL 0x80

    is likely to case trouble with your circuit as this is P7 , which is a D7 pin on your display.

    To answer this I need to know the circuit you are using for driving the backlight and how it is connected to the I2C chip.

     
  • Gai-jin
    Gai-jin
    2013-01-25

    Sainsmart doesn't make a schematic available, but I've found several people suggesting that it's a knockoff of this I2c backpack board:
    http://www.dfrobot.com/image/data/DFR0175/I2C%20LCD%20Backpack%20schematic.pdf

    I checked continuity between the pins of the chip and those of the lcd with a multimeter to confirm that the connections I listed in the earlier post  are correct:

    LCD     CHIP
    RS          P0
    RW         P1
    E             P2
    D4          P4
    D5          P5
    D6          P6
    D7          P7
    

    I couldn't find anything that was connected to P3, but I don't have access to the back side of the backpack board, so it may have something on the underside.

    I had tried using BL=0x00, and also tried BL=0x08, and just got garbage on the display with those settings.  I was surprised that setting BL to 0x80 worked, but that was the only configuration I found that actually resulted in the welcome message, and subsequent data sent from a python script, appearing on the display.  Of course, when I set backlight=no in LCDd.conf with BL still set to 0x80, I no longer got data to show up on the screen.  I wonder if when I had set backlight=yes, I was getting some data on the screen because whatever was trying to be sent to the backlight happened to match what was needed on that 4th bit to display a character… Probably not very likely I guess.

     
  • Looking at that schematic P3 is connected to the base of the back light transistor via signal named BT. If this is true for your board the code should be using:

    #define BL 0x08
    

    It looks like there is a bug in the back light function:

    void i2c_HD44780_backlight(PrivateData *p, unsigned char state)
    {
        p->backlight_bit = ((!p->have_backlight||state) ? 0 : BL);
        i2c_out(p, p->backlight_bit);
    }
    
    p->have_backlight
    

    is set to 1 for true,

    state
    

    is set to 1 for on and the output must be logic high for on so the logic to set the back light bit should read:

        p->backlight_bit = ((p->have_backlight && state) ? BL : 0);
    
     
  • Markus Dolze
    Markus Dolze
    2013-01-26

    p->backlight_bit = ((!p->have_backlight||state) ? 0 : BL);

    It's not a bug, but on intention. This code is supposed to drive a PNP transistor as in Figure 5.6. HD44780: Backlight Wiring.

    As this particular circuit uses a NPN transistor the code from emtejay' comment should work.

     
  • Gai-jin
    Gai-jin
    2013-01-27

    Thanks.  I made the changes emteejay suggested, and after compiling and copying the new version over the old, I shut my raspberry pi down and brought it back up to try again. 
    I watched it boot up, and saw that the welcome message was displayed and the backlight did stay on.  Wonderful!  Then I enabled the autostart script that will send data to the lcd, shut it down to move it, and when it came back up, I'm getting garbage characters on the screen again.  The backlight IS staying on now, but I get apparently random characters and symbols on the screen.

    I tried disabling the startup script and rebooting, and even tried re-copying the new driver file over the existing, just to be sure it hadn't gotten reverted back somehow.  I don't get why it would have appeared to work perfectly the first time, and then not work after that.  Still, no luck.  I am away from home now, so I haven't been able to spend much time troubleshooting it.  I'll have to fiddle with it more tonight or tomorrow. 

    Thanks again for the help, both of you.

     
  • Bug or not?

    Isn't the required logic have_backlight && state?

    To invert the output just swap the bit definitions:

    p->backlight_bit = ((p->have_backlight && state) ? 0 : BL);
    
     
  • Markus Dolze
    Markus Dolze
    2013-01-27

    I spotted two problems which I overlooked:

    1. The initialization routine does use i2c_out directly. Therefore just modifying i2c_HD44780_senddata was not enough.
    2. The lower nibble calculation did not work as expected.

    Here is a complete new version, including the backlight code.

    Index: server/drivers/hd44780-i2c.c
    ===================================================================
    RCS file: /cvsroot/lcdproc/lcdproc/server/drivers/hd44780-i2c.c,v
    retrieving revision 1.14
    diff -u -r1.14 hd44780-i2c.c
    --- server/drivers/hd44780-i2c.c    30 Oct 2010 18:04:21 -0000  1.14
    +++ server/drivers/hd44780-i2c.c    27 Jan 2013 14:39:31 -0000
    @@ -76,10 +85,10 @@
     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 BL 0x80
    +#define RS 0x01
    +#define RW 0x02
    +#define EN 0x04
    +#define BL 0x08
     // note that the above bits are all meant for the data port of PCF8574
     #define I2C_ADDR_MASK 0x7f
    @@ -168,43 +214,43 @@
        // 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);
    +   i2c_out(p, 0x30);
        if (p->delayBus)
            hd44780_functions->uPause(p, 1);
    -   i2c_out(p, enableLines | 0x03);
    +   i2c_out(p, enableLines | 0x30);
        if (p->delayBus)
            hd44780_functions->uPause(p, 1);
    -   i2c_out(p, 0x03);
    +   i2c_out(p, 0x30);
        hd44780_functions->uPause(p, 15000);
    -   i2c_out(p, enableLines | 0x03);
    +   i2c_out(p, enableLines | 0x30);
        if (p->delayBus)
            hd44780_functions->uPause(p, 1);
    -   i2c_out(p, 0x03);
    +   i2c_out(p, 0x30);
        hd44780_functions->uPause(p, 5000);
    -   i2c_out(p, enableLines | 0x03);
    +   i2c_out(p, enableLines | 0x30);
        if (p->delayBus)
            hd44780_functions->uPause(p, 1);
    -   i2c_out(p, 0x03);
    +   i2c_out(p, 0x30);
        hd44780_functions->uPause(p, 100);
    -   i2c_out(p, enableLines | 0x03);
    +   i2c_out(p, enableLines | 0x30);
        if (p->delayBus)
            hd44780_functions->uPause(p, 1);
    -   i2c_out(p, 0x03);
    +   i2c_out(p, 0x30);
        hd44780_functions->uPause(p, 100);
        // now in 8-bit mode...  set 4-bit mode
    -   i2c_out(p, 0x02);
    +   i2c_out(p, 0x20);
        if (p->delayBus)
            hd44780_functions->uPause(p, 1);
    -   i2c_out(p, enableLines | 0x02);
    +   i2c_out(p, enableLines | 0x20);
        if (p->delayBus)
            hd44780_functions->uPause(p, 1);
    -   i2c_out(p, 0x02);
    +   i2c_out(p, 0x20);
        hd44780_functions->uPause(p, 100);
        // Set up two-line, small character (5x8) mode
    @@ -240,8 +284,8 @@
     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 h = ch & 0xf0; // high and low nibbles
    +   unsigned char l = (ch << 4) & 0xf0;
        if (flags == RS_INSTR)
            portControl = 0;
    @@ -277,7 +321,7 @@
      */
     void i2c_HD44780_backlight(PrivateData *p, unsigned char state)
     {
    -   p->backlight_bit = ((!p->have_backlight||state) ? 0 : BL);
    +   p->backlight_bit = ((p->have_backlight && state) ? BL : 0);
        i2c_out(p, p->backlight_bit);
     }
    
     
    • Rhys Williams
      Rhys Williams
      2015-08-10

      I would like to prepare a patch too allow the selection of the I2C pinout configuration, as above, which is used here:

      http://dx.com/p/lcd1602-adapter-board-w-iic-i2c-interface-black-works-with-official-arduino-boards-216865

      I see three possible ways of doing this, in order of complexity.

      1. Have another version of the i2c module that changes the pinouts as above.
      2. add configuration options to specify which pins the d4-d7 and the control lines correspond too.
        This could be done changing the #defines to integers, with a H/L or L/H config switch that would >> 4 or << 4 the values as appropriate on init.
        do any of the other drivers do this kind of thing?
      3. define the data and control pins in the config file, defaulting to the current set up.

      Which solution would be accepted into the code base

      1. would be the easiest to implement - just unsure in what to call it?

      Thanks
      Rhys

       
      • Ralf Schaefer
        Ralf Schaefer
        2015-08-10

        I think a possibility to specifc the pins would be the most versatile solution. You can look into hd44780-rpi.c where such a think is done for the rasberry GPIO pins. I think this should look very similar for both (and more/other) drivers

         
        • Rhys Williams
          Rhys Williams
          2015-08-13

          I have a working version using a conf file to specify the pins. shall i post a diff to here, or is it better post to the maiłing list?

          I solved the backlight issue using a config setting:
          BacklightInvert: true

          its is currently in bitbucket, i can post it to github if someone would like to test it!

           
          • Rhys Williams
            Rhys Williams
            1 day ago

            Here is an update to lcdproc i2c to allow the pin configurations to be specified via
            LCDd.conf.

            I have put up on github:
            https://github.com/wilberforce/lcdproc

            here is an example config:

            Hitachi HD44780 driver

            [HD44780]
            ConnectionType=i2c
            Device=/dev/i2c-pi
            Port=0x27
            Backlight=yes
            Size=20x4
            DelayBus=false
            DelayMult=1
            Keypad=no
            Speed=0
            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

            EOF

            I have sent to the lcdproc mailing list, however have not had confirmation on acceptance of the patch.

            <hd44780-i2c.c.patch>
            <hd44780-low.h.patch>
            <hd44780.docbook.patch>

             
  • Gai-jin
    Gai-jin
    2013-01-27

    That seems to be working perfectly.  I've rebooted a couple of times, enabled the startup script, and I've got good data showing on the display, and the backlight is staying on.  Thanks!

     
  • Ralf Schaefer
    Ralf Schaefer
    2015-08-10

    More fun with the backlight

    Possible configuration options are: off | open | on.
    But in server/drivers/hd44780.c line 171 we have
    p->have_backlight = drvthis->config_get_bool(drvthis->name, "backlight", 0, 0);
    meaning we test for on/off only, not for open.

    The result is that when open is set, the driver thinks there is no backlight and the backlight command does not work (initial backlight setting on startup works however, if patches above were applied).

    I see two solutions:
    1. either extend config_get_bool() - it takes a few more values already anyway
    2. use another default. This will disable backlight only when explicitely "off" was specified. The diff looks like:

    hd44780.c.orig 2015-08-10 18:29:58.793086093 +0000
    --- hd44780.c 2015-08-10 18:27:39.135758137 +0000
    ***
    170,172 *
    p->have_keypad = drvthis->config_get_bool(drvthis->name, "keypad", 0, 0);
    ! p->have_backlight = drvthis->config_get_bool(drvthis->name, "backlight", 0, 0);
    p->have_output = drvthis->config_get_bool(drvthis->name, "outputport", 0, 0);
    --- 170,172 ----
    p->have_keypad = drvthis->config_get_bool(drvthis->name, "keypad", 0, 0);
    ! p->have_backlight = drvthis->config_get_bool(drvthis->name, "backlight", 0, 1);
    p->have_output = drvthis->config_get_bool(drvthis->name, "outputport", 0, 0);
    **

     
    Last edit: Ralf Schaefer 2015-08-10