Using HD44780 on Raspberry Pi – part 7: 40×4 and I2C

We have direct mode, buffered mode, GPIO access. What is missing ? I2C for twin-lcd. Lets get to work.

Download source

Previous parts

Wiring

We will go with old i2c wiring (used here) and just add second enable line to pin 6.

LCD                                           PCF8574
13 -------- GND                     GND ----- A0   Vcc ---- +5V 
14 -------- +5V                     GND ----- A1   SDA ---- SDA on RPi
12 --/\/\ [potentiometer]           GND ----- A2   SCL ---- SCL on RPi
       \--- GND                    LCD4 ----- P0   INT 
11 [RS]---- P4                     LCD3 ----- P1   P7
10 -------- GND                    LCD2 ----- P2   P6 ----- LCD15
 9 [E]----- P5                     LCD1 ----- P3   P5 ----- LCD9
15 [E2] --- P6                      GND ----- GND  P4 ----- LCD11
 4 [DB4]--- P0
 3 [DB5]--- P1
 2 [DB6]--- P2
 1 [DB7]--- P3
17 --/\/\ [potentiometer]
       \--- +5V
18 -------- GND

And thats where I had strange problems. My pcf wasn’t detected until I plugged LedA (pin 17)  straight to +5V bypassing potentiometer. It gave me strong background light but it was only way to make it work.

I2C driver

We will start by changing pins array, open i2c.py and replace self.pins with:

self.pins = {
    'RS': 4,
    'E': 5,
    'E2': None,
    'DB4': 0,
    'DB5': 1,
    'DB6': 2,
    'DB7': 3
}

Next change init by adding null check, new init:


    def init(self):
        """recalculate pins to values"""
        pins = {}
        for k in self.pins:
            if self.pins[k] is not None:
                pins[k] = int(pow(2, self.pins[k]))
        self.pins = pins

Time to see what is going on, create new demo function in lcd_direct.py:


def main_test_4():
    """demo 4 - lcd 40x4 by i2c"""
    drv = I2C(0x3a, 1)
    drv.pins['E2'] = 6
    lcd_1 = lcd.CharLCD(40, 4, drv, 0, 0)
    lcd_1.init()
    lcd_1.write('-First blarg1 !')
    lcd_1.write('-Second blarg2 !', 0, 1)
    lcd_1.write('-Third blarg3 !', 0, 2)
    lcd_1.write('-Fourth blarg4 !', 0, 3)
    lcd_1.write('12345678901234567890', 15, 1)

Run it… and crash !

Quick check and we need to move:

self.driver.init()

in lcd.py from _init to the beginning of init. We were doing double init with twin-lcd, and that was bad, very bad.

Re-run demo and we have something on screen:) And of course same problem as previous, wrong line addresses and enable signals.

Back to i2c. We need to send proper E line, change send function to:


    def send(self, enable=0):
        """Send E signal"""
        if enable == 0:
            pin = self.pins['E']
        elif enable == 1:
            pin = self.pins['E2']

        if pin is None:
            raise IndexError("Wrong enable index")
        
        self.write(self.char_buffer | pin)
        time.sleep(0.005)
        self.write(self.char_buffer & (0xFF - pin))

Lets move “up” a little. Function send is called from prepare_send. Go there and add enable=0 as function parameter and add enable to send call.


    def prepare_send(self, char, enable=0):
        """
        Prepares data for send and call send
            char: char to write
            enable: line to use
        """
        self.char_buffer = char
        self.send(enable)

Move “up” again, we have two functions, cmd and char, that calls prepare_send. You know what to do: add enable.


    def cmd(self, char, enable=0):
        """
        Send command to lcd
        Args:
            char: hex command to write
        """
        if self.mode == 8:
            self.prepare_send(char & 0x0F, enable)
        else:
            self.prepare_send(char >> 4, enable)
            self.prepare_send(char & 0x0F, enable)

    def char(self, char, enable=0):
        """
        Send char
        Args:
            char: char to swrite
            enable: enable line
        """
        char = ord(char)
        if self.mode == 8:
            self.prepare_send(self.pins['RS'] | (char & 0x0F), enable)
        else:
            self.prepare_send(self.pins['RS'] | (char >> 4), enable)
            self.prepare_send(self.pins['RS'] | (char & 0x0F), enable)

Run demo now. It works !

Stop! Jenkins time!

Not bad, decreased number of pylint errors because function in i2c.py match declaration in parent class. But increased number of cpd (code duplication) due to demo code.

Summary

This time we have:

  • add support for twin-lcds via I2C bus

Download source

Previous parts

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s