Weird I2C Problem?

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
Post Reply
HRD
Posts: 4
Joined: Sat Dec 24, 2016 1:52 am

Weird I2C Problem?

Post by HRD » Sat Dec 24, 2016 3:34 am

This is a strange one....

I am attempting to move a simple Python I2C LCD library for an HD44780 working on an RPi to an ESP8266 NodeMCU. The changes are limited to the supporting I2C library file and the changes only substitute the I2C initialization and write commands (see below). Here is the problem: Characters with the low order binary nibble of 1100 - 1111 appear on the LCD display as the corresponding characters with low order nibble 1000 - 1011 so ASCII 0x4C appears as the character ASCII 0x48, ASCII 0x4D appears as the character ASCII 0x49, ASCII 0x4E appears as the character ASCII 0x4A, and ASCII 0x4F appears as the character ASCII 0x4B. Therefore the string '@ABCDEFGHIJKLMNOP' appears on the display as '@ABCDEFGHIJKHIJKP' (no 'LMNO'), but any characters with low order nibble 0000 - 1011 appears properly. This phenomenon occurs/repeats for all characters for each high order nibble: (ASCII 0x2C, 0x2D, 0x2E, 0x2F appear as characters 0x28, 0x29, 0x2A, 0x2B, ASCII 0x3C, 0x3D, 0x3E, 0x3F appear as characters 0x38, 0x39, 0x3A, 0x3B, etc.). I added a print statement in the I2C library to show the low order nibble of the character being sent to the LCD via I2C bus and it is correct. This occurs regardless of where on the LCD display the characters appear. I have increased/decreased the delays, change the frequency in the initialization of the I2C bus to no avail. The display, I2C to LCD interface, and the (original) code operates properly on the RPi.

Thoughts? My code is far from perfect, but could the Micropython I2C library have a bug? What am I missing?

Thanks in advance!

Harold

I2C LCD Driver original source (for RPI): https://www.raspberrypi.org/forums/view ... 1&p=378524
Hardware: ESP8266 NodeMCU LoLin
Micropython version 1.8.6 (esp8266-20161110-v1.8.6.bin)

Original I2C_lib.py:
import smbus
from time import *

class I2C_device:
def __init__(self, addr, port=1):
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)

. . .

Modified I2C_lib.py:
from machine import Pin, I2C
from time import *

class I2C_device:
def __init__(self, addr, port=1):
self.addr = addr
self.bus = I2C(scl=Pin(5), sda=Pin(4))

# Write a single command
def write_cmd(self, cmd):
self.bus.writeto(self.addr, chr(cmd))
sleep(0.0001)
print("CMD:",cmd >> 4) # Added for debugging - upper 4 bit is data sent to LCD !!!

(Deleted all the remaining excess/unused code in the library)

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Weird I2C Problem?

Post by Roberthh » Sat Dec 24, 2016 8:16 am

Looks like bit 2 is stuck or set to 0 somewhere. It is hard to tell where, not seeing the full picture. Could be software or hardware.

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: Weird I2C Problem?

Post by deshipu » Mon Dec 26, 2016 7:20 pm

I would avoid using the chr() function converting integers into text characters, and instead use ustruct to convert integer values into bytes. MicroPython uses UTF8 internally for representing text characters, and not all sequences of bytes are valid.

HRD
Posts: 4
Joined: Sat Dec 24, 2016 1:52 am

Re: Weird I2C Problem?

Post by HRD » Mon Dec 26, 2016 9:16 pm

That did it!!!

Replaced 'self.bus.writeto(self.addr, chr(cmd))' with 'self.bus.writeto(self.addr, ustruct.pack("B",cmd))' and it works perfectly!

Thanks for the help!!!!!!!

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Weird I2C Problem?

Post by dhylands » Mon Dec 26, 2016 9:38 pm

Personally, I tend to use bytearrays. If you want to reduce memory allocations you can combine allocating a bytearray, and then create a memoryview onto it, and pass the memoryview to the write command.

Here's an example of using a bytearray (it will allocate a new one each time its called, like using ustruct.pack):

Code: Select all

packet = bytearray((0xff, 0xff, servo_id, 4, 3, 0x19, 1, 0))
There was an example of using memoryview posted here: http://forum.micropython.org/viewtopic. ... 84&p=10115

Post Reply