foobar77
Posts: 11
Joined: Thu May 10, 2012 2:49 pm

OLED 16x2 HD44780 woes

Thu Jan 30, 2014 10:51 am

Hi,

I'm having issues with this (http://www.midasdisplays.com/pdf/MCOB21605G1V.pdf) screen. I've used LCD version of this screen before with an arduino, the oled version is nice as it requires less wires and less current and no faffing about with contrast.

This is supposed to be a drop in replacement for 44780 but I cannot get the thing to work reliably, im having issues with stuff getting to the screen out of order, garbled and even some times I start the code and lines 1 and 2 are the wrong way around. Sometimes there's complete garbage on the screen and the only way to resolve that is to reboot everything (as removing the 5v supply going to the screen locks up the pi... not always but more often than not).

My wiring from the LCD pins is:

1 GND
2 +5v
3 DNC
4 GPIO25
5 GND
6 GPIO24
7..10 DNC
11 GPIO23
12 GPIO17
13 GPIO27
14 GPIO22
15 DNC
16 DNC




I've tried various libs, the Adafruit CharLCD and others, here is the code I am currently using

Code: Select all

#!/usr/bin/python

import RPi.GPIO as GPIO
from time import sleep

class HD44780:

    def __init__(self, pin_rs=25, pin_e=24, pins_db=[23, 17, 27, 22]):

        self.pin_rs = pin_rs
        self.pin_e = pin_e
        self.pins_db = pins_db

        GPIO.setmode(GPIO.BCM)
        GPIO.setup(self.pin_e, GPIO.OUT)
        GPIO.setup(self.pin_rs, GPIO.OUT)
        for pin in self.pins_db:
            GPIO.setup(pin, GPIO.OUT)

        self.clear()

    def clear(self):
        """ Blank / Reset LCD """
        self.cmd(0x28); # 4bit mode
        self.cmd(0x01) # clear DDRAM
        self.cmd(0x0C) # display on, cursor off
        self.cmd(0x80) # cursor @ 0,0
        self.cmd(0x06) # entry mode

      def cmd(self, bits, char_mode=False):
        """ Send command to LCD """

        sleep(0.001)
        bits=bin(bits)[2:].zfill(8)

        GPIO.output(self.pin_rs, char_mode)

        for pin in self.pins_db:
            GPIO.output(pin, False)

        for i in range(4):
            if bits[i] == "1":
                GPIO.output(self.pins_db[::-1][i], True)

        GPIO.output(self.pin_e, True)
        GPIO.output(self.pin_e, False)

        for pin in self.pins_db:
            GPIO.output(pin, False)

        for i in range(4,8):
            if bits[i] == "1":
                GPIO.output(self.pins_db[::-1][i-4], True)

        GPIO.output(self.pin_e, True)
        GPIO.output(self.pin_e, False)

    def message(self, text1,text2):
        """ Send string to LCD. Newline wraps to second line"""

        text1 = text1.ljust(16, ' ');
        text2 = text2.ljust(16, ' ');

        self.cmd(0x80);

        for char in text1:
                self.cmd(ord(char),True)


        self.cmd(0xC0) # next line

        for char in text2:
                self.cmd(ord(char),True)
Can anyone see if I am doing something blatantly wrong or can anyone confirm that thy have managed to get one of these things working without issue?

podman99
Posts: 9
Joined: Mon Jan 13, 2014 9:14 am

Re: OLED 16x2 HD44780 woes

Thu Jan 30, 2014 10:56 am

Experiencing very similar issues http://www.raspberrypi.org/phpBB3/viewt ... 88#p496788 However, I have more wiring as I have not disconnected backlight (15/16).

I will follow and keep updated if I get anything back.
Keith Jasper
1stDNS Limited
Software Developement
http://www.1stdomains.co.uk
http://www.domains2register.co.uk
http://www.keithjasper.co.uk

danjperron
Posts: 3096
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: OLED 16x2 HD44780 woes

Sat Feb 01, 2014 4:24 am

I just explain to someone how to use the SPI with a 74HC595 instead. I just bought a LCD2002A to verify if it is possible and it is. I played with the display all evening and no problem at all.


This is the post about it.

http://www.raspberrypi.org/phpBB3/viewt ... 71#p497371

B.T.W. I prefer LCD display with serial interface.

Daniel

robertcx
Posts: 2
Joined: Sun Mar 02, 2014 11:49 am

Re: OLED 16x2 HD44780 woes

Sun Mar 02, 2014 12:01 pm

I have just been playing with a Winstar 16x2 OLED, and ran into the same problems (incorrect line order, complete garbage, etc), but only after running the Python script a few times. I was using a very similar Python script (pulled from the web) to what you have described, and it worked OK with all the HD44780 LCDs that I had. However, when I looked at the initialisation code, it was not actually following the HD448780 specification exactly, and therefore, it appears that the OLED driver (WS0010) is rather more fussy. I have attached my updated example driver, which appears to be bomb-proof with both OLEDs and LCDs.

Code: Select all

#!/usr/bin/python
#
# HD44780 LCD/OLED Test Script for
# Raspberry Pi
#
# Author : Robert Coward (based on driver by Matt Hawkins/)
# Site   : http://www.raspberrypi-spy.co.uk
# 
# Date   : 27/02/2014
#

# The wiring for the LCD is as follows:
# 1 : GND
# 2 : 5V
# 3 : Contrast (0-5V)*
# 4 : RS (Register Select)
# 5 : R/W (Read Write)       - GROUND THIS PIN
# 6 : Enable or Strobe
# 7 : Data Bit 0             - NOT USED
# 8 : Data Bit 1             - NOT USED
# 9 : Data Bit 2             - NOT USED
# 10: Data Bit 3             - NOT USED
# 11: Data Bit 4
# 12: Data Bit 5
# 13: Data Bit 6
# 14: Data Bit 7
# 15: LCD Backlight +5V**
# 16: LCD Backlight GND

#import
import RPi.GPIO as GPIO
import time

# Define GPIO to LCD mapping
LCD_RS = 7
LCD_E  = 8
LCD_D4 = 25 
LCD_D5 = 24
LCD_D6 = 23
LCD_D7 = 18

# Define some device constants
LCD_WIDTH = 16    # Maximum characters per line
LCD_CHR = True
LCD_CMD = False

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line 

# Timing constants for low level write operations
# NOTE: Enable cycle time must be at least 1 microsecond 
# NOTE2: Actually, these can be zero and the LCD will typically still work OK
EDEL_TAS =  0.00001      # Address setup time (TAS)
EDEL_PWEH = 0.00001      # Pulse width of enable (PWEH)
EDEL_TAH =  0.00001      # Address hold time (TAH)

# Timing constraints for initialisation steps - IMPORTANT!
# Note that post clear display must be at least 6.2ms for OLEDs, as opposed
# to only 1.4ms for HD44780 LCDs. This has caused confusion in the past.
DEL_INITMID = 0.01       # middle of initial write (min 4.1ms)
DEL_INITNEXT = 0.0002     # post ssecond initial write (min 100ns)
DEL_POSTCLEAR = 0.01       # post clear display step (busy, min 6.2ms)

# ==============================================================================
# LCD Initialisation to setup the two line display using the 4 bit interface

def lcd_init():
  # Configure the GPIO to drive the LCD display correctly
  GPIO.setmode(GPIO.BCM)       # Use BCM GPIO numbers

  # setup all output pins for driving LCD display
  GPIO.setup(LCD_E, GPIO.OUT)  # E
  GPIO.setup(LCD_RS, GPIO.OUT) # RS
  GPIO.setup(LCD_D4, GPIO.OUT) # DB4
  GPIO.setup(LCD_D5, GPIO.OUT) # DB5
  GPIO.setup(LCD_D6, GPIO.OUT) # DB6
  GPIO.setup(LCD_D7, GPIO.OUT) # DB7
  
  # Initialise display into 4 bit mode, using recommended delays
  lcd_byte(0x33,LCD_CMD, DEL_INITNEXT, DEL_INITMID)
  lcd_byte(0x32,LCD_CMD, DEL_INITNEXT)
  
  # Now perform remainder of display init in 4 bit mode - IMPORTANT!
  # These steps MUST be exactly as follows, as OLEDs in particular are rather fussy
  lcd_byte(0x28,LCD_CMD, DEL_INITNEXT)    # two lines and correct font
  lcd_byte(0x08,LCD_CMD, DEL_INITNEXT)    # display OFF, cursor/blink off
  lcd_byte(0x01,LCD_CMD, DEL_POSTCLEAR)    # clear display, waiting for longer delay
  lcd_byte(0x06,LCD_CMD, DEL_INITNEXT)    # entry mode set

  # extra steps required for OLED initialisation (no effect on LCD)
  lcd_byte(0x17,LCD_CMD, DEL_INITNEXT)    # character mode, power on

  # now turn on the display, ready for use - IMPORTANT!
  lcd_byte(0x0C,LCD_CMD, DEL_INITNEXT)    # display on, cursor/blink off

# ==============================================================================
# Outputs string o characters to the LCD display line, padding as required

def lcd_string(message):
  # Send string to display

  message = message.ljust(LCD_WIDTH," ")  

  for i in range(LCD_WIDTH):
    lcd_byte(ord(message[i]),LCD_CHR)

# ==============================================================================
# Low level routine to output a byte of data to the LCD display
# over the 4 bit interface. Two nybbles are sent, one after the other.
# The post_delay specifies optional delay to cover busy periods
# The mid_delay specifies optional delay between the 4  bit nibbles (special case)

def lcd_byte(byteVal, mode, post_delay = 0, mid_delay = 0):

  # convert incoming value into 8 bit array, padding as required
  bits = bin(byteVal)[2:].zfill(8)
  
  # generate an array of pin numbers to write out
  lcdPins = [LCD_D7, LCD_D6, LCD_D5, LCD_D4]

  # set mode = True  for character, False for command
  GPIO.output(LCD_RS, mode) # RS

  # Output the four High bits
  for i in range(4):
    GPIO.output(lcdPins[i], int(bits[i]))

  # Toggle 'Enable' pin, wrapping with minimum delays
  time.sleep(EDEL_TAS)    
  GPIO.output(LCD_E, True)  
  time.sleep(EDEL_PWEH)
  GPIO.output(LCD_E, False)  
  time.sleep(EDEL_TAH)      

  # Wait for extra mid delay if specified (special case)
  if mid_delay > 0:
    time.sleep(mid_delay)

  # Output the four Low bits
  for i in range(4,8):
    GPIO.output(lcdPins[i-4], int(bits[i]))

  # Toggle 'Enable' pin, wrapping with minimum delays
  time.sleep(EDEL_TAS)    
  GPIO.output(LCD_E, True)  
  time.sleep(EDEL_PWEH)
  GPIO.output(LCD_E, False)  
  time.sleep(EDEL_TAH)   

  # Wait for extra post delay if specified (covers busy period)
  if post_delay > 0:
    time.sleep(post_delay)

# ==============================================================================
# main routine which initialises the display and outputs text messages to it

def main():
  # Initialise GPIO port and display 
  lcd_init()

  # Send some text
  lcd_byte(LCD_LINE_1, LCD_CMD)
  lcd_string("Rasbperry Pi")
  lcd_byte(LCD_LINE_2, LCD_CMD)
  lcd_string("Model B")

  time.sleep(3) # 3 second delay

  # Send some more text
  lcd_byte(LCD_LINE_1, LCD_CMD)
  lcd_string("Raspberrypi-spy")
  lcd_byte(LCD_LINE_2, LCD_CMD)
  lcd_string(".co.uk")

  time.sleep(3) # 3 second delay

  # Send some more text
  lcd_byte(LCD_LINE_1, LCD_CMD)
  lcd_string("Modified by")
  lcd_byte(LCD_LINE_2, LCD_CMD)
  lcd_string("Robert Coward")

  time.sleep(3) # 3 second delay

  # Send some more text
  lcd_byte(LCD_LINE_1, LCD_CMD)
  lcd_string("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
  lcd_byte(LCD_LINE_2, LCD_CMD)
  lcd_string("1234567890!$%^&*()")

# ==============================================================================
# Ensure that the GPIO is cleaned up whichever way the program exits
# This avoids all those annoying "channel already in use" errors

if __name__ == '__main__':
  try:
    main()
  finally: GPIO.cleanup()

# ==============================================================================
# ==============================================================================
The main changes are:

1) You must power off the display during initialisation and then power it back on later. This is achieved by writing 0x08 to power off, and 0x0C to power back on. The original Python code was just writing 0x0C, which appears to cause the display to malfunction if repeatedly initialised in this manner.
2) The time delay required after the display clear is specified as 6.2ms, instead of just 1.4ms for a HD44780 display. My driver waits for 10ms to be on the safe side.
3) There is an extra initialisation step for the character/graphic mode and power control, set by writing 0x17 to the display; it has no effect on HD44780 LCDs. Though not usually required (because the OLED display powers on in the correct mode), it is necessary if the display has previously become misconfigured in this area (for example it it received a garbled command).

I have run a test where I continually cycle around initialisation and writing to the display, and it never goes wrong. Therefore, I think this updated driver is the solution you are looking for.

robertcx
Posts: 2
Joined: Sun Mar 02, 2014 11:49 am

Re: OLED 16x2 HD44780 woes

Sun Mar 02, 2014 6:01 pm

Paul Carpenter has kindly suggested a few improvements to this script, so I have reproduced the updated copy below:

Code: Select all

#!/usr/bin/python
#
# HD44780 LCD/OLED Test Script for
# Raspberry Pi
#
# Author : Robert Coward/Paul Carpenter (based on driver by Matt Hawkins/)
# Site   : http://www.raspberrypi-spy.co.uk
#          http://www.pcserviceslectronics.co.uk
#
# Date   : 02/03/2014
#

# The wiring for the LCD is as follows:
# 1 : GND
# 2 : 5V
# 3 : Contrast (0-5V)*
# 4 : RS (Register Select)
# 5 : R/W (Read Write)       - GROUND THIS PIN
# 6 : Enable or Strobe
# 7 : Data Bit 0             - NOT USED
# 8 : Data Bit 1             - NOT USED
# 9 : Data Bit 2             - NOT USED
# 10: Data Bit 3             - NOT USED
# 11: Data Bit 4
# 12: Data Bit 5
# 13: Data Bit 6
# 14: Data Bit 7
# 15: LCD Backlight +5V**
# 16: LCD Backlight GND

#import
import RPi.GPIO as GPIO
import time

# Define GPIO to LCD mapping (USES BCM MODE NUMBERING scheme)
LCD_RS = 7
LCD_E  = 8
LCD_D4 = 25
LCD_D5 = 24
LCD_D6 = 23
LCD_D7 = 18

# Generate an array of pin numbers to write out for the data lines
lcdPins = [LCD_D7, LCD_D6, LCD_D5, LCD_D4]

# Define some device constants
LCD_WIDTH = 16    # Maximum characters per line
LCD_CHR = True
LCD_CMD = False

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line

# Timing constants for low level write operations
# NOTE: Enable cycle time must be at least 1 microsecond
# NOTE2: Actually, these can be zero and the LCD will typically still work OK
EDEL_TAS =  0.00001      # Address setup time (TAS)
EDEL_PWEH = 0.00001      # Pulse width of enable (PWEH)
EDEL_TAH =  0.00001      # Address hold time (TAH)

# Timing constraints for initialisation steps - IMPORTANT!
# Note that post clear display must be at least 6.2ms for OLEDs, as opposed
# to only 1.4ms for HD44780 LCDs. This has caused confusion in the past.
DEL_INITMID = 0.01       # middle of initial write (min 4.1ms)
DEL_INITNEXT = 0.0002    # post second initial write (min 100ns)
DEL_POSTCLEAR = 0.01     # post clear display step (busy, min 6.2ms)

# ==============================================================================
# LCD Initialisation to setup the two line display using the 4 bit interface

def lcd_init():
  # Configure the GPIO to drive the LCD display correctly
  GPIO.setmode(GPIO.BCM)       # Use BCM GPIO numbers

  # setup all output pins for driving LCD display
  GPIO.setup(LCD_E, GPIO.OUT)  # E
  # PC - better safe starting state
  GPIO.output(LCD_E, 0)        # set low as idle state
  GPIO.setup(LCD_RS, GPIO.OUT) # RS
  # PC - more maintainable initialisation
  for val in lcdPins:          # enable DB7 to DB4
    GPIO.setup(val, GPIO.OUT)
    GPIO.output(val, 0)        # set low 
 
  # Initialise display into 4 bit mode, using recommended delays
  lcd_byte(0x33, LCD_CMD, DEL_INITNEXT, DEL_INITMID)
  lcd_byte(0x32, LCD_CMD, DEL_INITNEXT)
 
  # Now perform remainder of display init in 4 bit mode - IMPORTANT!
  # These steps MUST be exactly as follows, as OLEDs in particular are rather fussy
  lcd_byte(0x28, LCD_CMD, DEL_INITNEXT)    # two lines and correct font
  lcd_byte(0x08, LCD_CMD, DEL_INITNEXT)    # display OFF, cursor/blink off
  lcd_byte(0x01, LCD_CMD, DEL_POSTCLEAR)   # clear display, waiting for longer delay
  lcd_byte(0x06, LCD_CMD, DEL_INITNEXT)    # entry mode set

  # extra steps required for OLED initialisation (no effect on LCD)
  lcd_byte(0x17, LCD_CMD, DEL_INITNEXT)    # character mode, power on

  # now turn on the display, ready for use - IMPORTANT!
  lcd_byte(0x0C, LCD_CMD, DEL_INITNEXT)    # display on, cursor/blink off

# ==============================================================================
# Outputs string of characters to the LCD display line, padding as required
# NOTE: Incoming string MUST be a string of simple characters with no complex
# unicode types present, as otherwise incorrect encoding will occur.

def lcd_string(message):
  # Send string to display, padding with spaces if required
  message = message.ljust(LCD_WIDTH," ") 

  for i in range(LCD_WIDTH):
    # output a single byte value for the incoming character
    lcd_byte(ord(message[i]), LCD_CHR)

# ==============================================================================
# Low level routine to output a byte of data to the LCD display
# over the 4 bit interface. Two nybbles are sent, one after the other.
# The post_delay specifies optional delay to cover busy periods
# The mid_delay specifies optional delay between the 4 bit nibbles (special case)

def lcd_byte(byteVal, mode, post_delay = 0, mid_delay = 0):

  # convert incoming value into 8 bit array, padding as required
  bits = bin(byteVal)[2:].zfill(8)

  # set mode = True  for character, False for command
  GPIO.output(LCD_RS, mode) # RS

  # Output the four High bits
  for i in range(4):
    GPIO.output(lcdPins[i], int(bits[i]))

  # Toggle 'Enable' pin, wrapping with minimum delays
  time.sleep(EDEL_TAS)   
  GPIO.output(LCD_E, True) 
  time.sleep(EDEL_PWEH)
  GPIO.output(LCD_E, False) 
  time.sleep(EDEL_TAH)     

  # Wait for extra mid delay if specified (special case)
  if mid_delay > 0:
    time.sleep(mid_delay)

  # Output the four Low bits
  for i in range(4,8):
    GPIO.output(lcdPins[i-4], int(bits[i]))

  # Toggle 'Enable' pin, wrapping with minimum delays
  time.sleep(EDEL_TAS)   
  GPIO.output(LCD_E, True) 
  time.sleep(EDEL_PWEH)
  GPIO.output(LCD_E, False) 
  time.sleep(EDEL_TAH)   

  # Wait for extra post delay if specified (covers busy period)
  if post_delay > 0:
    time.sleep(post_delay)

# ==============================================================================
# main routine which initialises the display and outputs text messages to it

def main():
  # Initialise GPIO port and display
  lcd_init()

  # Send some text
  lcd_byte(LCD_LINE_1, LCD_CMD)
  lcd_string("Rasbperry Pi")
  lcd_byte(LCD_LINE_2, LCD_CMD)
  lcd_string("Model B")

  time.sleep(3) # 3 second delay

  # Send some more text
  lcd_byte(LCD_LINE_1, LCD_CMD)
  lcd_string("Raspberrypi-spy")
  lcd_byte(LCD_LINE_2, LCD_CMD)
  lcd_string(".co.uk")

  time.sleep(3) # 3 second delay

  # Send some more text
  lcd_byte(LCD_LINE_1, LCD_CMD)
  lcd_string("Modified by")
  lcd_byte(LCD_LINE_2, LCD_CMD)
  lcd_string("Robert Coward")

  time.sleep(3) # 3 second delay

  # Send some more text
  lcd_byte(LCD_LINE_1, LCD_CMD)
  lcd_string("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
  lcd_byte(LCD_LINE_2, LCD_CMD)
  lcd_string("1234567890!$%^&*()")

# ==============================================================================
# Ensure that the GPIO is cleaned up whichever way the program exits
# This avoids all those annoying "channel already in use" errors

if __name__ == '__main__':
  try:
    main()
  finally: GPIO.cleanup()

# ==============================================================================

texy
Forum Moderator
Forum Moderator
Posts: 5146
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: OLED 16x2 HD44780 woes

Mon Mar 03, 2014 11:02 am

Hi,
not tieing the R/W line low is one usual gotcha, but it's usually safer to ground the unused databits as well. Some LCD's may pull these low, but not all of them in my experience.
Texy
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

EssexInc
Posts: 15
Joined: Wed Jan 09, 2013 4:28 pm

Re: OLED 16x2 HD44780 woes

Tue Apr 15, 2014 1:25 pm

Hi, all!
I've been struggling with much the same issue... Got a nice big 16x2 OLED that mostly works with the Adafruit_CharLCD code... to a point... I've added a "createChar" function to the Adafruit_CharLCD.py file, and it works fine for the LCD displays, writing out "sideways" characters to the CGRAM area, where I can display them nicely using the "\x" escape sequence... However, when I call the createChar function with the OLED, it just seems to go off into la-la land..... I'll append the "createChar" function here, in case it may be something somebody else sees as obvious.... I'm stumped!

def createChar(self, location, bitmap):
self.write4bits(self.LCD_SETCGRAMADDR | ((location & 7) << 3)
self.write4bits(bitmap[0],true)
self.write4bits(bitmap[1],true)
self.write4bits(bitmap[2],true)
self.write4bits(bitmap[3],true)
self.write4bits(bitmap[4],true)
self.write4bits(bitmap[5],true)
self.write4bits(bitmap[6],true)
self.write4bits(bitmap[7],true)
self.write4bits(self.LCD_SETDDRAMADDR)

Anybody see anything obviously amiss here, for the OLED?

Thanks!
Joe

User avatar
FTrevorGowen
Forum Moderator
Forum Moderator
Posts: 4630
Joined: Mon Mar 04, 2013 6:12 pm
Location: Bristol, U.K.
Contact: Website

Re: OLED 16x2 HD44780 woes

Tue Apr 15, 2014 4:59 pm

texy wrote:Hi,
not tieing the R/W line low is one usual gotcha, but it's usually safer to ground the unused databits as well. Some LCD's may pull these low, but not all of them in my experience.
Texy
Hmmm... interesting. I'm playing around with various LCD 1602 interfaces at the moment: No problems with an "intelligent", PIC-based I2C (or serial, not yet tried) interface, nor with my own**, parallel, hard-wired "write-only" (R/W low), 8-bit interface (E & RS on GPIO pins, 8-bit data via an I2C PCF8574AP). However, I'm now trying out a Funduino LCM1602 I2C backpack**** with intriguing results so far. This is just a PCF8574T plus a "contrast pot" and a transistor buffer on the backlight. P7-P4 connect to D7-D4, P3 drives the backlight transistor, P2 --> E, P1 --> R/W and P0 --> RS. My ('C' based) program keeps R/W 'low' AFAICT (but I don't have access to an oscilloscope to check for "spikes") and I can initialise the LCD into 4-bit mode and write commands and data to it almost as well as with my 8-bit interface (I'm cloning/adapting my 8-bit tests). Almost, but not quite there (yet) - for some reason the last written command or data appears to be ignored until I (re-run the program and) write a new sequence. I'm beginning to wonder if the interface is "meant" to be used (in the "arduino world") in both read and write modes ie. by actually reading and checking the "Busy Flag"!
Trev.
** http://www.cpmspectrepi.webspace.virgin ... erial.html
**** http://www.amazon.co.uk/gp/product/B00F ... UTF8&psc=1

Edit: Update - I think I've solved my problem. It's unclear from the HD44780U data sheet I'm using whether the "idle state" of the E pin is "high" or "low". Re-checking the code used in wiringPi suggest that it's "low" and the strobe signal goes "high" then "low". In my "8-bit" code I was doing the opposite ie. idle "high", strobe "low" and then back "high" (which worked, maybe because the data is fully stable before the strobe happens ???) For the 4-bit interface the wiringPi method seems to be needed.
Still running Raspbian Jessie on some older Pi's (an A, B1, B2, B+, P2B, 3xP0, P0W) but Stretch on my 2xP3A+, P3B+, P3B, B+, A+ and a B2. See: https://www.cpmspectrepi.uk/raspberry_pi/raspiidx.htm

digitalForest
Posts: 7
Joined: Sat Jun 01, 2013 10:19 am

Re: OLED 16x2 HD44780 woes

Sun Dec 07, 2014 9:29 pm

Great to find this code. I am using it with the Adafruit 16x2 OLED display and it works nicely.

I played around a bit and noticed, that some pins are not needed:
robertcx wrote: # The wiring for the LCD is as follows:
# 1 : GND
# 2 : 5V
# 3 : Contrast (0-5V)*
# 4 : RS (Register Select)
# 5 : R/W (Read Write) - GROUND THIS PIN
# 6 : Enable or Strobe
# 7 : Data Bit 0 - NOT USED
# 8 : Data Bit 1 - NOT USED
# 9 : Data Bit 2 - NOT USED
# 10: Data Bit 3 - NOT USED
# 11: Data Bit 4
# 12: Data Bit 5
# 13: Data Bit 6
# 14: Data Bit 7
# 15: LCD Backlight +5V**
# 16: LCD Backlight GND
Specifically,
#3 contrast as the OLED do not need this.
#15, 16 as the OLED are driven directly from #2

My $0.02

dF

pmck
Posts: 1
Joined: Tue Aug 11, 2015 9:50 am

Re: OLED 16x2 HD44780 woes

Tue Aug 11, 2015 9:52 am

Just used this code to get the adafruit blue oled up and running on the pi 2.

Cheers, this saved me a lot of hassle :)

User avatar
kinski-SKI
Posts: 5
Joined: Sat Jun 17, 2017 11:34 am

Re: OLED 16x2 HD44780 woes

Sat Jun 17, 2017 11:49 am

Does anyone use LCD OLED based driver controller (WS0010) ...And I2C interface
I have Oled Winstar company WEH001602ALPP5N00001 / controller WS0010 (Supposedly compatible with HD44780)
Unfortunately I can not run this LCD.....OK works only for the first start of a program that supports it.
After shutting down the program / LCD... the second time it does not work properly
LCD shows chaotic entries and some bugs :-(
Does anyone have any solution and can help ?

User avatar
FTrevorGowen
Forum Moderator
Forum Moderator
Posts: 4630
Joined: Mon Mar 04, 2013 6:12 pm
Location: Bristol, U.K.
Contact: Website

Re: OLED 16x2 HD44780 woes

Sat Jun 17, 2017 1:38 pm

kinski-SKI wrote:Does anyone use LCD OLED based driver controller (WS0010) ...And I2C interface
I have Oled Winstar company WEH001602ALPP5N00001 / controller WS0010 (Supposedly compatible with HD44780)
...
It's going to be difficult to suggest anything without more info. HD44780/WS0010 compatibility aside (possible timing differences maybe) exactly what type of I2C interface? Is it an attached module** or part of the main board? Photographs may provide a clue.
Trev.
** Similar to one of these perhaps? : http://www.cpmspectrepi.uk/raspberry_pi ... D_Backpack (two other types follow in the same page)
Still running Raspbian Jessie on some older Pi's (an A, B1, B2, B+, P2B, 3xP0, P0W) but Stretch on my 2xP3A+, P3B+, P3B, B+, A+ and a B2. See: https://www.cpmspectrepi.uk/raspberry_pi/raspiidx.htm

StuartF
Posts: 27
Joined: Sun Feb 02, 2014 5:41 pm

Re: OLED 16x2 HD44780 woes

Sat Jun 17, 2017 2:06 pm

I have had experience of this chipset. There is a small but critical difference.
To quote from the datasheet

BUSY FLAG (BF)
The Busy Flag is used to determine whether WS0010 is idle or internally operating. When WS0010 is
performing some internal operations, the Busy Flag is set to "1". Under this condition, no other
instruction will be accepted. When RS Pin is set to "0" and R/WB Pin is set to "1", the Busy Flag will
be outputted to the DB7 pin.
When WS0010 is idle or has completed its previous internal operation, the Busy Flag is set to "0". The
next instruction can now be processed or executed.

User avatar
FTrevorGowen
Forum Moderator
Forum Moderator
Posts: 4630
Joined: Mon Mar 04, 2013 6:12 pm
Location: Bristol, U.K.
Contact: Website

Re: OLED 16x2 HD44780 woes

Sat Jun 17, 2017 2:36 pm

StuartF wrote:I have had experience of this chipset. There is a small but critical difference.
To quote from the datasheet

BUSY FLAG (BF)
The Busy Flag is used to determine whether WS0010 is idle or internally operating. When WS0010 is
performing some internal operations, the Busy Flag is set to "1". Under this condition, no other
instruction will be accepted. When RS Pin is set to "0" and R/WB Pin is set to "1", the Busy Flag will
be outputted to the DB7 pin.
When WS0010 is idle or has completed its previous internal operation, the Busy Flag is set to "0". The
next instruction can now be processed or executed.
That's also true for the HD44780 but the "usual practice" is to wire the LCD module to be write only (so nothing is ever "read back") and introduce a software timing delay after writing a command or data as per the "longest time" necessary (hence my reference to "timing differences"). The "unknown" issue (w/o cross-referencing the datasheets) is whether there are significant differences between enabling and operating in 4-bit or 8-bit data transfer modes. Certainly for some other "HD44780 compatible" LCD modules I've observed different minimum E-strobe pulse lengths/delays over a number of module types/samples** and interface connection modes: http://www.cpmspectrepi.uk/raspberry_pi ... gData.html
Trev.
** http://www.cpmspectrepi.uk/raspberry_pi ... plays.html
Still running Raspbian Jessie on some older Pi's (an A, B1, B2, B+, P2B, 3xP0, P0W) but Stretch on my 2xP3A+, P3B+, P3B, B+, A+ and a B2. See: https://www.cpmspectrepi.uk/raspberry_pi/raspiidx.htm

User avatar
kinski-SKI
Posts: 5
Joined: Sat Jun 17, 2017 11:34 am

Re: OLED 16x2 HD44780 woes

Sat Jun 17, 2017 5:24 pm

I'm sorry but I'm not a software developer and I do not understand everything.
But I read that this is a 4bit bus error In this controller WS0010... or initialization problem?
I have found some descriptions of the malfunction of this LCD Oled eg here:
https://forum.mikroe.com/viewtopic.php?f=76&t=66331
https://www.youtube.com/watch?v=mXbyB6htKGw

As I mentioned I use the I2C interface and the converter connected to the LCD
LCD controls the script in python + mpc / lcdproc programs (in the big clock option)
Previously I used two 40x2 / 16x2 LCDs with backlighting and contrast control
And it always worked OK
1602 16x2 Blue Module w/Serial Interface IIC/I2C HD44780 Arduino - PCF 8574AT ( i2cdetect -y 0 = 0x3f )
Here is the code in python for the mpc program:

Code: Select all

#!/usr/bin/python


import I2C_LCD_driver
import os
import sys
import subprocess
import time
import textwrap

from time       import sleep, strftime
from datetime   import datetime
from subprocess import *

mylcd = I2C_LCD_driver.lcd()

if not os.getegid() == 0:
  sys.exit('Script must be run as root')

def main():

  # Initialise display
  radio = 1
  counter = 0

  while True:

    # Get current status and playtime
    if radio == 1:
      process = subprocess.Popen('mpc -v', shell=True, stdout=subprocess.PIPE)
    if radio == 0:
      process = subprocess.Popen('mpc -f %artist%:%title%', shell=True, stdout=subprocess.PIPE)

    status = process.communicate()[0]
    if status == "":
      radioName = "    No radio    "
      listN = " or no network  "
      songName = " or no network  "
      if counter == 60:
        run_cmd("sudo service mpd restart")
    else:
      statusLines = status.split('\n')
      songN = statusLines[0]
      listN = statusLines[1]
      volumeN = statusLines[2]
      if ":" in songN:
        radioName = statusLines[0].split(':',1)[0].strip()
        songName = statusLines[0].split(':',1)[1].strip()
      if ":" not in songN:
        radioName = statusLines[0]
        songName = "                "
    if radioName == "volume":
      if counter == 60:
        run_cmd("mpc play")

    if counter == 1:
      mylcd.lcd_clear()
      mylcd.lcd_display_string(listN,1)
      mylcd.lcd_display_string(radioName[0:16],2)
    if counter == 30:
      mylcd.lcd_clear()
      mylcd.lcd_display_string(songName[0:16],1)
      mylcd.lcd_display_string(songName[16:31],2)

    sleep(0.1)
    counter = counter + 1
    if counter == 61:
      counter = 1



def run_cmd(cmd):
  p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT)
  output = p.communicate()[0]
  return output

if __name__ == '__main__':

  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:
    mylcd.lcd_display_string("    Goodbye!    ",1)
    mylcd.lcd_display_string("                ",2)
An example frequent effect:
Attachments
lcd-winstar.jpg
lcd-winstar.jpg (45.9 KiB) Viewed 4428 times
Last edited by kinski-SKI on Sat Jun 17, 2017 7:17 pm, edited 1 time in total.

User avatar
FTrevorGowen
Forum Moderator
Forum Moderator
Posts: 4630
Joined: Mon Mar 04, 2013 6:12 pm
Location: Bristol, U.K.
Contact: Website

Re: OLED 16x2 HD44780 woes

Sat Jun 17, 2017 7:10 pm

kinski-SKI wrote:I'm sorry but I'm not a software developer and I do not understand everything.
But I read that this is a 4bit bus error In this controller WS0010... or initialization problem?
I have found some descriptions of the malfunction of this LCD Oled eg here:
https://forum.mikroe.com/viewtopic.php?f=76&t=66331
https://www.youtube.com/watch?v=mXbyB6htKGw

As I mentioned I use the I2C interface and the converter connected to the LCD
LCD controls the script in python + mpc / lcdproc programs (in the big clock option)
Previously I used two 40x2 / 16x2 LCDs with backlighting and contrast control
And it always worked OK
1602 16x2 Blue Module w/Serial Interface IIC/I2C HD44780 Arduino
Here is the code in python for the mpc program:

Code: Select all

#!/usr/bin/python


import I2C_LCD_driver
import os
import sys
import subprocess
import time
import textwrap

from time       import sleep, strftime
from datetime   import datetime
from subprocess import *

mylcd = I2C_LCD_driver.lcd()

if not os.getegid() == 0:
  sys.exit('Script must be run as root')

def main():

  # Initialise display
  radio = 1
  counter = 0

  while True:

    # Get current status and playtime
    if radio == 1:
      process = subprocess.Popen('mpc -v', shell=True, stdout=subprocess.PIPE)
    if radio == 0:
      process = subprocess.Popen('mpc -f %artist%:%title%', shell=True, stdout=subprocess.PIPE)

    status = process.communicate()[0]
    if status == "":
      radioName = "    No radio    "
      listN = " or no network  "
      songName = " or no network  "
      if counter == 60:
        run_cmd("sudo service mpd restart")
    else:
      statusLines = status.split('\n')
      songN = statusLines[0]
      listN = statusLines[1]
      volumeN = statusLines[2]
      if ":" in songN:
        radioName = statusLines[0].split(':',1)[0].strip()
        songName = statusLines[0].split(':',1)[1].strip()
      if ":" not in songN:
        radioName = statusLines[0]
        songName = "                "
    if radioName == "volume":
      if counter == 60:
        run_cmd("mpc play")

    if counter == 1:
      mylcd.lcd_clear()
      mylcd.lcd_display_string(listN,1)
      mylcd.lcd_display_string(radioName[0:16],2)
    if counter == 30:
      mylcd.lcd_clear()
      mylcd.lcd_display_string(songName[0:16],1)
      mylcd.lcd_display_string(songName[16:31],2)

    sleep(0.1)
    counter = counter + 1
    if counter == 61:
      counter = 1



def run_cmd(cmd):
  p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT)
  output = p.communicate()[0]
  return output

if __name__ == '__main__':

  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:
    mylcd.lcd_display_string("    Goodbye!    ",1)
    mylcd.lcd_display_string("                ",2)
An example frequent effect:
The photo suggests it's the E-strobe length/timing issues I mentioned in a previous post**. You (if you can) need to look at the source code for I2C_LCD_driver and "tweak" the relevant pulse length/delay values. (I'm not a Python programmer so cannot advise fully).
Trev.
** Other examples here: http://www.cpmspectrepi.uk/raspberry_pi ... ml#Testing_...
Still running Raspbian Jessie on some older Pi's (an A, B1, B2, B+, P2B, 3xP0, P0W) but Stretch on my 2xP3A+, P3B+, P3B, B+, A+ and a B2. See: https://www.cpmspectrepi.uk/raspberry_pi/raspiidx.htm

User avatar
kinski-SKI
Posts: 5
Joined: Sat Jun 17, 2017 11:34 am

Re: OLED 16x2 HD44780 woes

Sat Jun 17, 2017 7:31 pm

So it follows that LCD Oled is not damaged
But the WS0010 controller is not 100% compatible with the HD44780
Maybe a good programmer will solve this problem ... :?:

User avatar
FTrevorGowen
Forum Moderator
Forum Moderator
Posts: 4630
Joined: Mon Mar 04, 2013 6:12 pm
Location: Bristol, U.K.
Contact: Website

Re: OLED 16x2 HD44780 woes

Sat Jun 17, 2017 8:02 pm

kinski-SKI wrote:So it follows that LCD Oled is not damaged
But the WS0010 controller is not 100% compatible with the HD44780
... :?:
More likely the original Python program was only ever tested with a small number of LCD (and, perhaps not, OLED) modules of the same basic, type. I only discovered "the problem" because:
1) I did not assume that the timings in the 'C' code example I was adapting were "the best".
2) Where possible I cross-checked with the data sheets.
3) I presumed "worst case" delays in data transfer (ie. waited long enough for the I2C data to transfer to avoid "edge clashes" and a "bit longer, just in case").
4) and after a long R&D career have good "diagnostic" skills still, even though I no longer have access "sophisticated" equipment, not even a basic oscilloscope.
Trev.
Still running Raspbian Jessie on some older Pi's (an A, B1, B2, B+, P2B, 3xP0, P0W) but Stretch on my 2xP3A+, P3B+, P3B, B+, A+ and a B2. See: https://www.cpmspectrepi.uk/raspberry_pi/raspiidx.htm

User avatar
DougieLawson
Posts: 34167
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
Contact: Website

Re: OLED 16x2 HD44780 woes

Sat Jun 17, 2017 8:16 pm

Try this https://github.com/ladyada/Adafruit_CharacterOLED on an Arduino.

If you can get that working it should be relatively easy to convert the bit settings and timings to a Raspberry python program.
Note:The use of baseball bats for educational purposes is completely disallowed on this forum.

Any DMs sent on Twitter will be answered next month.

StuartF
Posts: 27
Joined: Sun Feb 02, 2014 5:41 pm

Re: OLED 16x2 HD44780 woes

Sat Jun 17, 2017 8:56 pm

kinski-SKI wrote:But the WS0010 controller is not 100% compatible with the HD44780
It is compatible, but the "usual practice" of wiring the LCD module to be write only causes the problems with this chipset.
I have not looked into the I2C_LCD_driver module, but it may have a read function.
Failing that, assume that the I2C backpack is not compatible with the WS0010 OLED, and see if there is one that supports read/write.

This chipset requires reading of the busy flag, as it 'throws a wobbly' if it gets another command whilst working.
This makes it take even longer to process the command it is working on, and thus causes the display corruption.
Also, it requires 500ms to initialize from powerup and reset.

From my experience, it is possible to use delays as long as you don't require fast updating of the display, but when
you do, only 'busy' will do.

No offense is intended by these comments.

User avatar
FTrevorGowen
Forum Moderator
Forum Moderator
Posts: 4630
Joined: Mon Mar 04, 2013 6:12 pm
Location: Bristol, U.K.
Contact: Website

Re: OLED 16x2 HD44780 woes

Sun Jun 18, 2017 6:54 am

StuartF wrote: ...
It is compatible, but the "usual practice" of wiring the LCD module to be write only causes the problems with this chipset.
I have not looked into the I2C_LCD_driver module, but it may have a read function.
Failing that, assume that the I2C backpack is not compatible with the WS0010 OLED, and see if there is one that supports read/write.
This chipset requires reading of the busy flag, as it 'throws a wobbly' if it gets another command whilst working.
This makes it take even longer to process the command it is working on, and thus causes the display corruption.
Also, it requires 500ms to initialize from powerup and reset.
From my experience, it is possible to use delays as long as you don't require fast updating of the display, but when
you do, only 'busy' will do.
No offense is intended by these comments.
Thanks for than info. - that clarifies matters and, for me, suggests that it was designed/intended for use with "old-style" micro-controllers/micro-processors with "well-defined" read/write cycle timings. The 500 ms "reset" is somewhat long too!
Trev.
Still running Raspbian Jessie on some older Pi's (an A, B1, B2, B+, P2B, 3xP0, P0W) but Stretch on my 2xP3A+, P3B+, P3B, B+, A+ and a B2. See: https://www.cpmspectrepi.uk/raspberry_pi/raspiidx.htm

User avatar
kinski-SKI
Posts: 5
Joined: Sat Jun 17, 2017 11:34 am

Re: OLED 16x2 HD44780 woes

Sun Jun 18, 2017 7:11 am

Here is the I2C driver ( I2C_LCD_driver.py )

Code: Select all

# -*- coding: utf-8 -*-
# Original code found at:
# https://gist.github.com/DenisFromHR/cc863375a6e19dce359d

"""
Compiled, mashed and generally mutilated 2014-2015 by Denis Pleic
Made available under GNU GENERAL PUBLIC LICENSE

# Modified Python I2C library for Raspberry Pi
# as found on http://www.recantha.co.uk/blog/?p=4849
# Joined existing 'i2c_lib.py' and 'lcddriver.py' into a single library
# added bits and pieces from various sources
# By DenisFromHR (Denis Pleic)
# 2015-02-10, ver 0.1

"""

# i2c bus (0 -- original Pi, 1 -- Rev 2 Pi)
I2CBUS = 0

# LCD Address
ADDRESS = 0x3f

import smbus
from time import sleep

class i2c_device:
   def __init__(self, addr, port=I2CBUS):
      self.addr = addr
      self.bus = smbus.SMBus(port)

# Write a single command
   def write_cmd(self, cmd):
      self.bus.write_byte(self.addr, cmd)
      sleep(0.0001)

# Write a command and argument
   def write_cmd_arg(self, cmd, data):
      self.bus.write_byte_data(self.addr, cmd, data)
      sleep(0.0001)

# Write a block of data
   def write_block_data(self, cmd, data):
      self.bus.write_block_data(self.addr, cmd, data)
      sleep(0.0001)

# Read a single byte
   def read(self):
      return self.bus.read_byte(self.addr)

# Read
   def read_data(self, cmd):
      return self.bus.read_byte_data(self.addr, cmd)

# Read a block of data
   def read_block_data(self, cmd):
      return self.bus.read_block_data(self.addr, cmd)


# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80

# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00

# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00

# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00

# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00

# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00

En = 0b00000100 # Enable bit
Rw = 0b00000010 # Read/Write bit
Rs = 0b00000001 # Register select bit

class lcd:
   #initializes objects and lcd
   def __init__(self):
      self.lcd_device = i2c_device(ADDRESS)

      self.lcd_write(0x03)
      self.lcd_write(0x03)
      self.lcd_write(0x03)
      self.lcd_write(0x02)

      self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
      self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
      self.lcd_write(LCD_CLEARDISPLAY)
      self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
      sleep(0.2)


   # clocks EN to latch command
   def lcd_strobe(self, data):
      self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT)
      sleep(.0005)
      self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT))
      sleep(.0001)

   def lcd_write_four_bits(self, data):
      self.lcd_device.write_cmd(data | LCD_BACKLIGHT)
      self.lcd_strobe(data)

   # write a command to lcd
   def lcd_write(self, cmd, mode=0):
      self.lcd_write_four_bits(mode | (cmd & 0xF0))
      self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0))

   # write a character to lcd (or character rom) 0x09: backlight | RS=DR<
   # works!
   def lcd_write_char(self, charvalue, mode=1):
      self.lcd_write_four_bits(mode | (charvalue & 0xF0))
      self.lcd_write_four_bits(mode | ((charvalue << 4) & 0xF0))
  
   # put string function with optional char positioning
   def lcd_display_string(self, string, line=1, pos=0):
    if line == 1:
      pos_new = pos
    elif line == 2:
      pos_new = 0x40 + pos
    elif line == 3:
      pos_new = 0x14 + pos
    elif line == 4:
      pos_new = 0x54 + pos

    self.lcd_write(0x80 + pos_new)

    for char in string:
      self.lcd_write(ord(char), Rs)

   # clear lcd and set to home
   def lcd_clear(self):
      self.lcd_write(LCD_CLEARDISPLAY)
      self.lcd_write(LCD_RETURNHOME)

   # define backlight on/off (lcd.backlight(1); off= lcd.backlight(0)
   def backlight(self, state): # for state, 1 = on, 0 = off
      if state == 1:
         self.lcd_device.write_cmd(LCD_BACKLIGHT)
      elif state == 0:
         self.lcd_device.write_cmd(LCD_NOBACKLIGHT)

   # add custom characters (0 - 7)
   def lcd_load_custom_chars(self, fontdata):
      self.lcd_write(0x40);
      for char in fontdata:
         for line in char:
            self.lcd_write_char(line)
Thanks for than info. - that clarifies matters and, for me, suggests that it was designed/intended for use with "old-style" micro-controllers/micro-processors with "well-defined" read/write cycle timings. The 500 ms "reset" is somewhat long too!
So will not work properly with Winstar Oled / controler WS0010 ? :-(
Thank you for the information and help.......... I go back to LCD with backlight and contrast control
regards

User avatar
FTrevorGowen
Forum Moderator
Forum Moderator
Posts: 4630
Joined: Mon Mar 04, 2013 6:12 pm
Location: Bristol, U.K.
Contact: Website

Re: OLED 16x2 HD44780 woes

Sun Jun 18, 2017 6:17 pm

kinski-SKI wrote:Here is the I2C driver ( I2C_LCD_driver.py )

Code: Select all

...
# Write a single command
   def write_cmd(self, cmd):
      self.bus.write_byte(self.addr, cmd)
      sleep(0.0001)

# Write a command and argument
   def write_cmd_arg(self, cmd, data):
      self.bus.write_byte_data(self.addr, cmd, data)
      sleep(0.0001)

# Write a block of data
   def write_block_data(self, cmd, data):
      self.bus.write_block_data(self.addr, cmd, data)
      sleep(0.0001)
...
class lcd:
   #initializes objects and lcd
   def __init__(self):
      self.lcd_device = i2c_device(ADDRESS)

      self.lcd_write(0x03)
      self.lcd_write(0x03)
      self.lcd_write(0x03)
      self.lcd_write(0x02)

      self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
      self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
      self.lcd_write(LCD_CLEARDISPLAY)
      self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
      sleep(0.2)

   # clocks EN to latch command
   def lcd_strobe(self, data):
      self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT)
      sleep(.0005)
      self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT))
      sleep(.0001)
...
Thank you for the information and help.......... I go back to LCD with backlight and contrast control
regards
AFAICT, not being a Python programmer, and if I'm interpreting the sleep values correctly, they're (like. for example, the equivalent 50uS values in similar, wiringPi, 'C' code) somewhat generic and probably "work best" for direct GPIO connection and not via an I2C driven (PC8574-based) 4-bit interface. You could try changing them to values similar to those in my link posted previously (and those new values will also be O.K. for most, if not all, LCD modules - to date they haven't need "re-tweaking" for any new samples I've tested - I'm awaiting delivery of an "uncommon" 16x4 line variant at the moment).
Trev.
Still running Raspbian Jessie on some older Pi's (an A, B1, B2, B+, P2B, 3xP0, P0W) but Stretch on my 2xP3A+, P3B+, P3B, B+, A+ and a B2. See: https://www.cpmspectrepi.uk/raspberry_pi/raspiidx.htm

User avatar
kinski-SKI
Posts: 5
Joined: Sat Jun 17, 2017 11:34 am

Re: OLED 16x2 HD44780 woes

Tue Jun 27, 2017 4:14 pm

This is not a professional solution but it works for me :shock:
radio.py

Code: Select all

#!/usr/bin/python
# -*- coding: utf-8 -*-

import smbus
import time
import subprocess

from time       import sleep, strftime
from datetime   import datetime
from subprocess import *

# Define some device parameters
I2C_ADDR  = 0x3f # I2C device address
LCD_WIDTH = 16   # Maximum characters per line

# Timing constants for low level write operations
# NOTE: Enable cycle time must be at least 1 microsecond 
# NOTE2: Actually, these can be zero and the LCD will typically still work OK
EDEL_TAS =  0.00001      # Address setup time (TAS)
EDEL_PWEH = 0.00001      # Pulse width of enable (PWEH)
EDEL_TAH =  0.00001      # Address hold time (TAH)

# Timing constraints for initialisation steps - IMPORTANT!
# Note that post clear display must be at least 6.2ms for OLEDs, as opposed
# to only 1.4ms for HD44780 LCDs. This has caused confusion in the past.
DEL_INITMID = 0.01       # middle of initial write (min 4.1ms)
DEL_INITNEXT = 0.0002     # post ssecond initial write (min 100ns)
DEL_POSTCLEAR = 0.01       # post clear display step (busy, min 6.2ms)


# Define some 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
#LCD_BACKLIGHT = 0x0C  # Off


ENABLE = 0b00000100 # Enable bit

# Timing constants
E_PULSE = 0.005
E_DELAY = 0.005

#Open I2C interface
bus = smbus.SMBus(0)  # Rev 1 Pi uses 0 (and Orange PI PC, for pins 3 and 5)
#bus = smbus.SMBus(1) # Rev 2 Pi uses 1

def lcd_init():
  # Initialise display
  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)


  lcd_byte(0x06,LCD_CMD)    # entry mode set

# extra steps required for OLED initialisation (no effect on LCD)
  lcd_byte(0x17,LCD_CMD)    # character mode, power on

  # now turn on the display, ready for use - IMPORTANT!
  lcd_byte(0x0C,LCD_CMD)    # display on, cursor/blink off

def lcd_byte(bits, mode):
  # Send byte to data pins
  # bits = the data
  # mode = 1 for data
  #        0 for command

  bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
  bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT

  # High bits
  bus.write_byte(I2C_ADDR, bits_high)
  lcd_toggle_enable(bits_high)

  # Low bits
  bus.write_byte(I2C_ADDR, bits_low)
  lcd_toggle_enable(bits_low)

def lcd_toggle_enable(bits):
  # Toggle enable
  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)

def lcd_string(message,line):
  # Send string to display

  message = message.ljust(LCD_WIDTH," ")

  lcd_byte(line, LCD_CMD)

  for i in range(LCD_WIDTH):
    lcd_byte(ord(message[i]),LCD_CHR)

def replace_pl(chars):
  pl = {  'ą': 'a',
          'ć': 'c',
          'ę': 'e',
          'ł': 'l',
          'ń': 'n',
          'ó': 'o',
          'ś': 's',
          'ź': 'z',
          'ż': 'z',
          'Ą': 'A',
          'Ć': 'C',
          'Ę': 'E',
          'Ł': 'L',
          'Ń': 'N',
          'Ó': 'O',
          'Ś': 'S',
          'Ź': 'Z',
          'Ż': 'Z',
  }
  for f, t in pl.items():
    chars = chars.replace(f,t)
  return chars

def main():

  # Initialise display
  lcd_init()

  counter = 0

  while True:

  # Get current status and playtime
    process = subprocess.Popen('sudo mpc -v', shell=True, stdout=subprocess.PIPE)
    ekran1 = process.communicate()[0]
    ekran1 = replace_pl(ekran1)
    statusLines = ekran1.split('\n')
    ekran1 = statusLines[1]
    if ekran1 <> '':
      ekran1L1 = ekran1.split(' ',1)[0].strip()
      ekran1L2temp = ekran1.split(' ',1)[1].strip()
      ekran1L2 = ekran1L2temp.split(' ',1)[0].strip()

    process = subprocess.Popen('sudo mpc -f %name%', shell=True, stdout=subprocess.PIPE)
    ekran2 = process.communicate()[0]
    ekran2 = replace_pl(ekran2)
    statusLines = ekran2.split('\n')
    ekran2 = statusLines[0]
    ekran2L1 = ekran2[0:16]
    ekran2L2 = ekran2[16:31]

    process = subprocess.Popen('sudo mpc -f %artist%', shell=True, stdout=subprocess.PIPE)
    ekran3 = process.communicate()[0]
    ekran3 = replace_pl(ekran3)
    statusLines = ekran3.split('\n')
    ekran3 = statusLines[0]
    ekran3L1 = ekran3[0:16]
    ekran3L2 = ekran3[16:31]

    process = subprocess.Popen('sudo mpc -f %title%', shell=True, stdout=subprocess.PIPE)
    ekran4 = process.communicate()[0]
    ekran4 = replace_pl(ekran4)
    statusLines = ekran4.split('\n')
    ekran4 = statusLines[0]
    ekran4L1 = ekran4[0:16]
    ekran4L2 = ekran4[16:31]

    if counter == 1:
      if ekran1 == "":
        counter = 15
      else:
        lcd_string(ekran1L1,LCD_LINE_1)
        lcd_string(ekran1L2,LCD_LINE_2)
    if counter == 15:
      if ekran2 == "":
        counter = 30
      else:
        lcd_string(ekran2L1,LCD_LINE_1)
        lcd_string(ekran2L2,LCD_LINE_2)
    if counter == 30:
      if ekran3 == "":
        counter = 45
      else:
        lcd_string(ekran3L1,LCD_LINE_1)
        lcd_string(ekran3L2,LCD_LINE_2)
    if counter == 45:
      if ekran4 == "":
        counter = 60
      else:
        lcd_string(ekran4L1,LCD_LINE_1)
        lcd_string(ekran4L2,LCD_LINE_2)

    sleep(0.1)
    counter = counter + 1
    if counter == 61:
      counter = 1


if __name__ == '__main__':

  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:
    lcd_byte(0x00, LCD_CMD)
    lcd_byte(0x01, LCD_CMD)
    lcd_byte(0x08, LCD_CMD)
Note some entries refer to converting Polish diacritic marks: ąśćółńżź on ascolnzz
In configuration I also use se script which probably clears the display Oled
I'm sorry but I'm not a programmer :oops:
lcd-clear.py

Code: Select all

#!/usr/bin/python

import smbus
import time

# Define some device parameters
I2C_ADDR  = 0x3f # I2C device address
LCD_WIDTH = 16   # Maximum characters per line
LCD_HEIGHT = 2

# Timing constants for low level write operations
# NOTE: Enable cycle time must be at least 1 microsecond 
# NOTE2: Actually, these can be zero and the LCD will typically still work OK
EDEL_TAS =  0.00001      # Address setup time (TAS)
EDEL_PWEH = 0.00001      # Pulse width of enable (PWEH)
EDEL_TAH =  0.00001      # Address hold time (TAH)

# Timing constraints for initialisation steps - IMPORTANT!
# Note that post clear display must be at least 6.2ms for OLEDs, as opposed
# to only 1.4ms for HD44780 LCDs. This has caused confusion in the past.
DEL_INITMID = 0.01       # middle of initial write (min 4.1ms)
DEL_INITNEXT = 0.0002     # post ssecond initial write (min 100ns)
DEL_POSTCLEAR = 0.01       # post clear display step (busy, min 6.2ms)


# Define some 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
#LCD_BACKLIGHT = 0x0C  # Off


ENABLE = 0b00000100 # Enable bit

# Timing constants
E_PULSE = 0.0001
E_DELAY = 0.0001

#Open I2C interface
bus = smbus.SMBus(0)  # Rev 1 Pi uses 0 (and Orange PI PC, for pins 3 and 5)
#bus = smbus.SMBus(1) # Rev 2 Pi uses 1


def lcd_byte(bits, mode):
  # Send byte to data pins
  # bits = the data
  # mode = 1 for data
  #        0 for command

  bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
  bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT

  # High bits
  bus.write_byte(I2C_ADDR, bits_high)
  lcd_toggle_enable(bits_high)

  # Low bits
  bus.write_byte(I2C_ADDR, bits_low)
  lcd_toggle_enable(bits_low)

def lcd_toggle_enable(bits):
  # Toggle enable
  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)

def main():
  # Main program block



    # Send some test
    lcd_string("RPiSpy         <",LCD_LINE_1)
    lcd_string("I2C LCD        <",LCD_LINE_2)


if __name__ == '__main__':

  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:
    lcd_byte(0x00, LCD_CMD)
    lcd_byte(0x01, LCD_CMD)
    lcd_byte(0x08, LCD_CMD)
Stop mpc and run lcdproc with option :Big clock ..... mpc-stop.sh

Code: Select all

#! /bin/sh
mpc stop
killall python
killall lcdproc
killall LCDd
python /root/lcd-clear.py
LCDd -c /etc/LCDd.conf
lcdproc -c /etc/lcdproc.conf
Restart script radio.py : ....... mpc-start.sh

Code: Select all

#! /bin/sh
/bin/sh /root/1.sh
python /root/radio.py &
and 1.sh

Code: Select all

#!/bin/bash
killall lcdproc
killall LCDd
python /root/lcd-clear.py

I do not know why but it works :lol:
Maybe someone will do it professionally
Ps. But now I do not use Raspberry Pi but Orange Pi Lite / Armbian !
more information :
Orange/I2C
Internet radio + LCD 2x16 + TactSwitch
regards!

JoeBear9000
Posts: 1
Joined: Sat Nov 11, 2017 11:24 pm

Re: OLED 16x2 HD44780 woes

Sat Nov 11, 2017 11:29 pm

I bought one of these LCD panels today and soldered on an I2C module thinking it was going to be a straightforward replacement of my previous HDD44780 (as it's described) and I've been encountering tons of problems.

Scripts will execute correctly the first time and readouts are fine, however the screen will not clear upon any further runs, and text gets garbled or appended to the old text on the display. The only way to reset seems to be removing the 5v rail and replacing.

Has anyone come up with a decent solution to get this working? It's very frustrating as the display is very crisp and legible compared to the old backlit style.

Return to “General discussion”