I'm currently using the LCD1602 with my raspberry pi 5 and have run into a few issues. I'm trying to use no library software i2c partially because I struggled to find a pi 5 - working LCD library and I want to gain a better understanding of the i2c protocol. So, to do this I decided to use the threading library to take control of the clock signal, and I'd have another thread for the main code: This is what it looks like:
import gpiod
import threading
import time
address = 0x27
Message = "hello"
global SDA
global SCL
global chip
chip = gpiod.Chip("gpiochip0")
SCL = chip.get_line(17)
SDA = chip.get_line(27)
event = threading.Event()
SDA.request(consumer="dev 1", type=gpiod.LINE_REQ_DIR_OUT)
SCL.request(consumer="dev 2", type=gpiod.LINE_REQ_DIR_OUT)
def CLOCK():
global SDA
global SCL
global chip
while True:
SCL.set_value(1)
event.set()
time.sleep(0.00006)
SCL.set_value(0)
event.clear()
time.sleep(0.00006)
CLOCK_thread = threading.Thread(target=CLOCK)
def Main_thread():
global SDA
global SCL
global chip
# 1. Start bits
SDA.set_value(1)
SCL.set_value(1)
time.sleep(0.00006)
SDA.set_value(0)
SCL.set_value(0)
CLOCK_thread.start()
# 2. Address sharing
for i in range(8):
event.wait() # wait for SCL to go high to continue
SDA.set_value((address >> (7 - i)) & 1)
time.sleep(0.000006)
# 3. Read/write bit
event.wait()# wait for SCL to go high to continue
SDA.set_value(0) # Assuming write operation
time.sleep(0.000006)
Start_time = time.time()
#ACK/NACK
SDA.release()
SDA.request(consumer = "dev2", type = gpiod.LINE_REQ_DIR_IN)
End_time = time.time()
event.wait() # wait for clock to go high - when ACK will be sent
ACK = SDA.get_value()
time.sleep(0.0000006)
print(ACK)
total = Start_time - End_time
print(total)
SDA.release()
SDA = chip.get_line(27)
SDA.request(consumer = "dev3", type = gpiod.LINE_REQ_DIR_OUT)
# 4. Data frame
for char in Message:
for bit in range(8):
event.wait() # wait for SCL to go high to continue
SDA.set_value((ord(char) >> (7 - bit)) & 1)
time.sleep(0.000006)
#ACK/NACK
SDA.release()
SDA.request(consumer = "dev2", type = gpiod.LINE_REQ_DIR_IN)
End_time = time.time()
event.wait() # wait for clock to go high - when ACK will be sent
ACK = SDA.get_value()
time.sleep(0.0000006)
print(ACK)
total = Start_time - End_time
print(total)
SDA.release()
SDA = chip.get_line(27)
SDA.request(consumer = "dev3", type = gpiod.LINE_REQ_DIR_OUT)
# finish
SCL.set_value(1)
time.sleep(0.000006)
SDA.set_value(0)
time.sleep(0.00006)
SDA.set_value(1)
time.sleep(0.00006)
MAIN_thread = threading.Thread(target=Main_thread)
MAIN_thread.start()
Here is an explanation of what is going on:
The start, I found that to start an i2c protocol you need to set the sda and scl high for one bit then low for one bit.
For the address sharing I used the address 0x27 which I found from the SparkFun site. To transmit the data, I used a system that pauses the main thread until the CLK signal is outputting a 1 (i2c devices only read/write on a high clock signal.) Then I used a mechanism that outputs the values from the address bit by bit using a for loop system.
Next is the read/write bit, where I again waited for the clock to go high, then sent a low (meaning the master is writing.)
Now it was time to check for the ACK/NACK bit. For this I released the SDA line then reset it up as an input. Then I took the value on the SDA line and slept for 1 bit. I found that this made my code return a 1 (if it is an ACK it should return a 0.) To try and debug this I timed how long it takes to change the SDA to an input, it takes 7e-5 seconds and each bit is apparently
Next, the data frame, here I made my code so that each letter of "hello" is converted into the ASCII of that letter then each individual bit is sent into the LCD’s SDA.
Next is the second ACK/NACK bit. Where I did the same as the previous ACK/NACK bit, and am still unsuccessful.
Here is the problem: After all this code, there is no change on what is displayed on my LCD. I am wondering if this is due to there needing to be a cursor position set before the ASCII. Could anyone provide some guidance on anything that is left out?
Here is what the lcd looks like (it looks the same after I run the code as it does at startup): enter image description here
Here is a good datasheet on the LCD: https://www.sparkfun.com/datasheets/LCD/HD44780.pdf
Thank you in advance.
-
what is displayed on the LCD?jsotola– jsotola2024年11月01日 06:55:45 +00:00Commented Nov 1, 2024 at 6:55
-
@jsotola The LCD was displaying the same at startup as it is after the code I ran, I've updated the original post with a picture, thanks!Matthew Moller– Matthew Moller2024年11月01日 08:18:17 +00:00Commented Nov 1, 2024 at 8:18
-
Can't see any Pi relevance. Get it working with a library before using your own code. E.g. abyz.me.uk/lgjoan– joan2024年11月01日 09:06:55 +00:00Commented Nov 1, 2024 at 9:06
-
@joan Hello, thank you for your helpful reply. I think it is a good idea to use a library before trying to create my own code. I think the one you suggested looks appropriate. Do you perhaps know where I can find the source code of the lgpio library, specifically its i2c capabilities so that I can use the source code to better understand how to create my own i2c? Thanks!Matthew Moller– Matthew Moller2024年11月01日 09:15:40 +00:00Commented Nov 1, 2024 at 9:15
-
For some reason you keep trying to run I²C using a user space python GPIO library rather than any of the kernel based solutions which work.Milliways– Milliways2024年11月01日 10:13:48 +00:00Commented Nov 1, 2024 at 10:13
1 Answer 1
There is kernel documentation See https://www.kernel.org/doc/html/latest/i2c/index.html for details of the I2C/SMBus Subsystem for background.
There are SMBus modules for python (I have used smbus2
although I normally use ioctl
drivers in c with python wrappers).
Joan's lgpio Python
I2C may be easier.
Using one of these would enable you to write a LCD1602 library, which should be relatively simple; CERTAINLY simpler than writing your own I2C code.
If you search there ARE LCD1602 python libraries, although I have never used one as I have only used on Arduino.
-
Thank you for your answer, it really helps!Matthew Moller– Matthew Moller2024年11月02日 02:21:04 +00:00Commented Nov 2, 2024 at 2:21