Closed
Description
Sir, ... Lefti,
I ported the library to use gpiod instead of RPi.GPIO, however, I just can't get it to work, and was hoping you could take a look at it. The screen doesn't reset or turn on. The timing looks tricky for the reset too. I'm not sure what gpiod introduces as far as lag goes. Your RPi.GPIO version (with lgpio) works great, but we really need to move this, and everything over to libgpiod.
https://craiger.org/craiger/ILI9486_gpiod.txt (web server wont allow .py)
relevant portion of ILI9486_gpiod.py attached - thanks!
-craig
apt install python3-libgpiod
from enum import Enum
import time
import numpy as np
from PIL import Image, ImageDraw
#import RPi.GPIO as GPIO
import gpiod
from spidev import SpiDev
#GPIO.setmode(GPIO.BCM)
...
def __init__(self, spi: SpiDev, dc: int, rst: int = None, *, origin: Origin = Origin.UPPER_LEFT):
"""Creates an instance of the display using the given SPI connection. Must provide the SPI driver and the GPIO
pin number for the DC pin. Can optionally provide the GPIO pin number for the reset pin. Optionally the origin
can be set. The default is UPPER_LEFT, which is landscape mode this the bottom of the image located at the
power, video and audio out are of the Pi."""
self.__spi = spi
self.__dc = dc
self.__rst = rst
self.__origin = origin
self.__width = LCD_WIDTH
self.__height = LCD_HEIGHT
self.__inverted = False
self.__idle = False
# GPIO.setmode(GPIO.BCM)
# GPIO.setup(self.__dc, GPIO.OUT)
# GPIO.output(self.__dc, GPIO.HIGH)
chip = gpiod.Chip('gpiochip0') # RPi always on 0 now.
self.__dc_line = chip.get_line(self.__dc)
self.__dc_line.request(consumer="dc", type=gpiod.LINE_REQ_DIR_OUT)
self.__dc_line.set_value(1)
if self.__rst is not None:
# GPIO.setup(self.__rst, GPIO.OUT)
# GPIO.output(self.__rst, GPIO.HIGH)
# self.__rst_line = chip.get_line(self.__rst)
self.__rst_line = chip.get_line(25)
self.__rst_line.request(consumer="rst", type=gpiod.LINE_REQ_DIR_OUT)
# swap width and height if selected origin is landscape mode by checking if third bit is 1
if self.__origin.value & 0x20:
self.__width, self.__height = self.__height, self.__width
self.__buffer = Image.new('RGB', (self.__width, self.__height), (0, 0, 0))
def dimensions(self) -> tuple:
"""Returns the current display dimensions"""
return self.__width, self.__height
def is_landscape(self) -> bool:
"""Returns true if selected origin is landscape mode; false otherwise"""
return bool(self.__origin.value & 0x20)
def send(self, data, is_data=True, chunk_size=4096):
"""Writes a byte or an array of bytes to the display."""
# dc low for command, high for data
#GPIO.output(self.__dc, is_data)
self.__dc_line.set_value(1)
if isinstance(data, int):
self.__spi.writebytes([data])
else:
for start in range(0, len(data), chunk_size):
end = min(start + chunk_size, len(data))
self.__spi.writebytes(data[start: end])
return self
def command(self, data):
"""Writes a byte or an array of bytes to the display as a command."""
return self.send(data, False)
def data(self, data):
"""Writes a byte or an array of bytes to the display as data."""
return self.send(data, True)
def reset(self):
"""Resets the display if a reset pin is provided."""
if self.__rst is not None:
#GPIO.output(self.__rst, GPIO.HIGH)
self.__rst_line.set_value(1)
time.sleep(.001) # wait a bit to make sure the output was HIGH
#GPIO.output(self.__rst, GPIO.LOW)
self.__rst_line.set_value(0)
time.sleep(.000100) # wait 100 µs to trigger the reset (should be 10 µs, but the OS is not precise enough)
#GPIO.output(self.__rst, GPIO.HIGH)
self.__rst_line.set_value(1)
time.sleep(.120) # wait 120 ms for finishing blanking and resetting
self.__inverted = False
self.__idle = False
return self