16x2 I2C LCD Tutorials on C2

This wiki is based on the following magazine.
https://magazine.odroid.com/article/i2c-lcd-module-using-twi-1602-16x2-serial-lcd
Thank you for @Miltiadis Melissas

This tutorial has tested on Ubuntu 18.04 kernel 3.16 version.

Check your kernel and ubuntu version

odroid@odroid:~$ uname -r
3.16.65-39
odroid@odroid:~$ lsb_release -r
Release:	18.04
odroid@odroid:~$

Requirements

First, you’ll need to update ODROID-C2 to ensure all the latest packages are installed.

sudo apt update
sudo apt upgrade
sudo apt install i2c-tools python3-smbus

If you use python2, install “python-smbus” package instaed of “python3-smbus”

sudo apt install python-smbus

Wiring

Setting for I2C

Run the command below to automatically load the module when the system boots.

echo "aml_i2c" | sudo tee -a /etc/modules
echo "blacklist w1_gpio" | sudo tee -a /etc/modprobe.d/blacklist-odroid.conf

To use the i2c devices as user privilege, run this command.

sudo adduser odroid i2c

Reboot to apply all of the above settings.

sudo reboot

After reboot, you can see the below results with “lsmod” command.

odroid@odroid:~$ lsmod
Module                  Size  Used by
fuse                   90892  3
squashfs               32435  0
meson_gpiomem           4040  0
gxbb_wdt                3395  0
sch_fq_codel            7827  2
sx865x                  5179  0
aml_i2c                16735  0
ip_tables              17220  0
ipv6                  387537  24
autofs4                27592  2
odroid@odroid:~$

Check for connection

If the address shown below is not 0x27, you have to modify the variable “I2C_ADDR” to that address in python source code.

odroid@odroid:~$ sudo i2cdetect -y -r 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

Python software

import smbus
import time
 
# Define device parameters
I2C_ADDR = 0x27 # I2C device address, if any error, 
 # change this address to 0x3f
LCD_WIDTH = 16 # Maximum characters per line
 
# Define device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command
 
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line
 
LCD_BACKLIGHT = 0x08 # On
ENABLE = 0b00000100 # Enable bit
 
# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005
 
#Open I2C interface
bus = smbus.SMBus(1) # Open I2C interface for ODROID-C2
 
# Initialise display
def lcd_init():
    lcd_byte(0x33,LCD_CMD) # 110011 Initialise
    lcd_byte(0x32,LCD_CMD) # 110010 Initialise
    lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
    lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off 
    lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
    lcd_byte(0x01,LCD_CMD) # 000001 Clear display
    time.sleep(E_DELAY)
 
# Send byte to data pins 
 # (#bits = the data, #mode = 1 for data or 0 for command)
def lcd_byte(bits, mode):
    bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
    bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT
 
    bus.write_byte(I2C_ADDR, bits_high) # High bits
    lcd_toggle_enable(bits_high)
 
    bus.write_byte(I2C_ADDR, bits_low) # Low bits
    lcd_toggle_enable(bits_low)
 
# Toggle enable
def lcd_toggle_enable(bits):
    time.sleep(E_DELAY)
    bus.write_byte(I2C_ADDR, (bits | ENABLE))
    time.sleep(E_PULSE)
    bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
    time.sleep(E_DELAY)
 
# Send string to display
def lcd_string(message,line):
    message = message.ljust(LCD_WIDTH," ")
 
    lcd_byte(line, LCD_CMD)
 
    for i in range(LCD_WIDTH):
        lcd_byte(ord(message[i]),LCD_CHR)
 
# Main program block, # Initialize display
def main():
    lcd_init()
 
# Send text to I2C TWI 1602 16x2 Serial LCD Module Display
    while True:
 
        lcd_string("***ODROID-C2***",LCD_LINE_1)
        lcd_string("ODROID-magazine ",LCD_LINE_2)
 
        time.sleep(3)
 
        lcd_string("***HardKernel***",LCD_LINE_1)
        lcd_string("*hardkernel.com*",LCD_LINE_2)
 
        time.sleep(3)
 
# Handling keyboard interrupts and exception utility
if __name__ == '__main__':
 
    try:
        main()
    except KeyboardInterrupt:
        pass
    finally:
        lcd_byte(0x01, LCD_CMD)

Running the code

sudo python3 lcd16x2i2c.py