Quantcast
Channel: Blogs at All About Circuits
Viewing all articles
Browse latest Browse all 742

Part 4: Omega2 - I2C Example

$
0
0
Using the I2C library to control 2x16 LCD Module, and other things

The Onion2 Maker Kit came with a backlit 2x16 LCD module with I2C interface.

[​IMG]


[​IMG]


The I2C LCD Example is completely documented here. I will simply summarize the steps required to get this up and running.

The LCD module requires four connections to the Expansion Dock. You will note that this reduces the number of GPIO pins as compared to the normal parallel interface to the Hitachi HD44780 LCD Controller.

GND
Vcc
SDA
SCL

Getting Started

From the Linux Terminal, enter:
opkg update
opkg install python-light pyOnionI2C


Note that you only have to do this once on your workstation PC.
Next, you will create a Python library file called lcdDriver.py with the following code:

Code (Text):
  1. # lcdDriver.py
  2. from OmegaExpansion import onionI2C
  3. import time
  4.  
  5. # sleep durations
  6. writeSleep = 0.0001 # 100 us
  7. initSleep = 0.2
  8.  
  9. ## LCD Display commands
  10. # commands
  11. LCD_CLEARDISPLAY = 0x01
  12. LCD_RETURNHOME = 0x02
  13. LCD_ENTRYMODESET = 0x04
  14. LCD_DISPLAYCONTROL = 0x08
  15. LCD_CURSORSHIFT = 0x10
  16. LCD_FUNCTIONSET = 0x20
  17. LCD_SETCGRAMADDR = 0x40
  18. LCD_SETDDRAMADDR = 0x80
  19.  
  20. LCD_LINE1 = 0x80
  21. LCD_LINE2 = 0xC0
  22. LCD_LINE3 = 0x94
  23. LCD_LINE4 = 0xD4
  24.  
  25. # flags for display entry mode
  26. LCD_ENTRYRIGHT = 0x00
  27. LCD_ENTRYLEFT = 0x02
  28. LCD_ENTRYSHIFTINCREMENT = 0x01
  29. LCD_ENTRYSHIFTDECREMENT = 0x00
  30.  
  31. # flags for display on/off control
  32. LCD_DISPLAYON = 0x04
  33. LCD_DISPLAYOFF = 0x00
  34. LCD_CURSORON = 0x02
  35. LCD_CURSOROFF = 0x00
  36. LCD_BLINKON = 0x01
  37. LCD_BLINKOFF = 0x00
  38.  
  39. # flags for display/cursor shift
  40. LCD_DISPLAYMOVE = 0x08
  41. LCD_CURSORMOVE = 0x00
  42. LCD_MOVERIGHT = 0x04
  43. LCD_MOVELEFT = 0x00
  44.  
  45. # flags for function set
  46. LCD_8BITMODE = 0x10
  47. LCD_4BITMODE = 0x00
  48. LCD_2LINE = 0x08
  49. LCD_1LINE = 0x00
  50. LCD_5x10DOTS = 0x04
  51. LCD_5x8DOTS = 0x00
  52.  
  53. # flags for backlight control
  54. LCD_BACKLIGHT = 0x08
  55. LCD_NOBACKLIGHT = 0x00
  56.  
  57. En = 0b00000100 # Enable bit
  58. Rw = 0b00000010 # Read/Write bit
  59. Rs = 0b00000001 # Register select bit
  60.  
  61. class Lcd:
  62.   # initializes objects and lcd
  63.   def __init__(self,address, port=0):
  64.     # i2c device parameters
  65.     self.address = address
  66.     self.i2c = onionI2C.OnionI2C(port)
  67.  
  68.     # lcd defaults
  69.     self.lcdbacklight = LCD_BACKLIGHT #default status
  70.     self.line1= "";
  71.     self.line2= "";
  72.     self.line3= "";
  73.     self.line4= "";
  74.  
  75.     self.lcdWrite(0x03)
  76.     self.lcdWrite(0x03)
  77.     self.lcdWrite(0x03)
  78.     self.lcdWrite(0x02)
  79.  
  80.     self.lcdWrite(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
  81.     self.lcdWrite(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
  82.     self.lcdWrite(LCD_CLEARDISPLAY)
  83.     self.lcdWrite(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
  84.     time.sleep(initSleep)
  85.  
  86. # function to write byte to the screen via I2C
  87. def writeBytesToLcd(self, cmd):
  88.   self.i2c.write(self.address, [cmd])
  89.   time.sleep(writeSleep)
  90.  
  91. # creates an EN pulse (using I2C) to latch previously sent command
  92. def lcdStrobe(self, data):
  93.   self.writeBytesToLcd(data | En | self.lcdbacklight)
  94.   time.sleep(writeSleep)
  95.   self.writeBytesToLcd(((data & ~ En) | self.lcdbacklight))
  96.   time.sleep(writeSleep)
  97.  
  98. def lcdWriteFourBits(self, data):
  99.   # write four data bits along with backlight state to the screen
  100.   self.writeBytesToLcd(data | self.lcdbacklight)
  101.   # perform strobe to latch the data we just sent
  102.   self.lcdStrobe(data)
  103.  
  104. # function to write an 8-bit command to lcd
  105. def lcdWrite(self, cmd, mode=0):
  106.   # due to how the I2C backpack expects data, we need to send the top four and bottom four bits of the command separately
  107.   self.lcdWriteFourBits(mode | (cmd & 0xF0))
  108.   self.lcdWriteFourBits(mode | ((cmd << 4) & 0xF0))
  109.  
  110. # function to display a string on the screen
  111. def lcdDisplayString(self, string, line):
  112.   if line == 1:
  113.     self.line1 = string;
  114.     self.lcdWrite(LCD_LINE1)
  115.   if line == 2:
  116.     self.line2 = string;
  117.     self.lcdWrite(LCD_LINE2)
  118.   if line == 3:
  119.     self.line3 = string;
  120.     self.lcdWrite(LCD_LINE3)
  121.   if line == 4:
  122.     self.line4 = string;
  123.     self.lcdWrite(LCD_LINE4)
  124.  
  125.   for char in string:
  126.     self.lcdWrite(ord(char), Rs)
  127.  
  128. # function to display multiple lines on the screen
  129. def lcdDisplayStringList(self, strings):
  130.   for x in range(0, min(len(strings), 4)):
  131.     self.lcdDisplayString(strings[x], x+1)
  132.  
  133. # clear lcd and set to home
  134. def lcdClear(self):
  135.   self.lcdWrite(LCD_CLEARDISPLAY)
  136.   self.lcdWrite(LCD_RETURNHOME)
  137.  
  138. # write the current lines to the screen
  139. def refresh(self):
  140.   self.lcdDisplayString(self.line1,1)
  141.   self.lcdDisplayString(self.line2,2)
  142.   self.lcdDisplayString(self.line3,3)
  143.   self.lcdDisplayString(self.line4,4)
  144.  
  145. # turn on the backlight
  146. def backlightOn(self):
  147.   self.lcdbacklight = LCD_BACKLIGHT
  148.   self.refresh()
  149.  
  150. # turn off the backlight
  151. def backlightOff(self):
  152.   self.lcdbacklight = LCD_NOBACKLIGHT
  153.   self.refresh()
  154.  

With this file saved in your /root directory, you are now ready to create your test program.

Code (Text):
  1. # I2C LCD test program
  2.  
  3. # software delay function
  4. def delay(d):
  5.   while d > 0:
  6.     d -= 1
  7.  
  8. import onionGpio
  9. import lcdDriver
  10.  
  11. # initialize LCD
  12. lcdAddress = 0x3F
  13. lcd = lcdDriver.Lcd(lcdAddress)
  14. lcd.backlightOn()
  15.  
  16. gpio0 = onioGpio.OnionGpio(0)
  17. gpio0.setOutputDirection(0)
  18. value = 0
  19. n = 0
  20. lcd.lcdDisplayString("Hello",1)   # display on line 1
  21. lcd.lcdDisplayString("World",2)   # display on line 2
  22. delay(1000000)
  23.  
  24. while 1:
  25.   gpio0.setValue(value)
  26.   lcd.lcdDisplayStringList(["Hello AAC", "n = " + str(n)])
  27.   value = 1 - value
  28.   n += 1
  29.   delay(200000)
  30.  
  31. # end of main loop


Time Functions

You may notice in the code above a software delay function was created. This can also be accomplished using the time module as shown in the modified code below:
Code (Text):
  1. # I2C LCD test program using time
  2.  
  3. import onionGpio
  4. import lcdDriver
  5. import time
  6.  
  7. # initialize LCD
  8. lcdAddress = 0x3F
  9. lcd = lcdDriver.Lcd(lcdAddress)
  10. lcd.backlightOn()
  11.  
  12. gpio0 = onioGpio.OnionGpio(0)
  13. gpio0.setOutputDirection(0)
  14. value = 0
  15. n = 0
  16. lcd.lcdDisplayString("Hello",1)   # display on line 1
  17. lcd.lcdDisplayString("World",2)   # display on line 2
  18. time.sleep(5)   # wait for 5 seconds
  19.  
  20. while 1:
  21.   gpio0.setValue(value)
  22.   lcd.lcdDisplayStringList(["Hello AAC", "n = " + str(n)])
  23.   value = 1 - value
  24.   n += 1
  25.   time.sleep(1)   # delay for 1 second
  26.  
  27. # end of main loop


GPIO

One of the first software tests on a new MCU is to measure how fast one can toggle a GPIO pin. For this, we can run this simple code:
Code (Text):
  1. # GPIO toggle test
  2. import onionGpio
  3.  
  4. gpio0 = onioGpio.OnionGpio(0)
  5. gpio0.setOutputDirection(0)
  6.  
  7. while 1:
  8.   gpio0.setValue(1)
  9.   gpio0.setValue(0)
  10.  
  11. # end of while loop
I measured this with an oscilloscope to be period of about 5ms, i.e. a repetition rate of 200Hz. This is surprisingly and disappointingly slow.
There are two reasons for this slow speed.
  1. Python is an interpreted language, i.e., program script is not compiled into machine code.
  2. The GPIO functions are implemented as file transfer functions.

GPIO Side-track using time module

Let us briefly revisit our basic GPIO program. Here we add the time module in order to implement delays within the code. This program has been modified to flash the LED on GPIO0 once every second.
Code (Text):
  1. # GPIO toggle test
  2. import onionGpio
  3. import time
  4.  
  5. DELAY_500ms = 0.5
  6. gpio0 = onioGpio.OnionGpio(0)
  7. gpio0.setOutputDirection(0)
  8.  
  9. while 1:
  10.   gpio0.setValue(1)
  11.   time.sleep(DELAY_500ms)
  12.   gpio0.setValue(0)
  13.   time.sleep(DELAY_500ms)
  14. # end of while loop

FAST GPIO

A workable solution for fast GPIO is yet to come.
For the time being, you can execute the following commands from the Linux shell (command line):

fast-gpio set 0 1
fast-gpio set 0 0


... more to come, sometime later, maybe much later!!!
... if you have some ideas that you would like to see implemented, simply leave a comment below.

Viewing all articles
Browse latest Browse all 742

Trending Articles