Skip to content

Commit

Permalink
Inky: Fix SPI CS, normalise image conversion.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gadgetoid committed Feb 7, 2024
1 parent 70d8d22 commit cd66f78
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 21 deletions.
34 changes: 24 additions & 10 deletions inky/inky.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""Inky e-Ink Display Driver."""
import struct
import time
import warnings
from datetime import timedelta

import gpiod
import gpiodevice
import numpy
from gpiod.line import Bias, Direction, Edge, Value
from gpiodevice import platform
from PIL import Image

from . import eeprom

Expand Down Expand Up @@ -252,6 +254,10 @@ def setup(self):
self._spi_bus = spidev.SpiDev()

self._spi_bus.open(0, self.cs_channel)
try:
self._spi_bus.no_cs = True
except OSError:
warnings.warn("SPI: Cannot disable chip-select!")
self._spi_bus.max_speed_hz = 488000

self._gpio_setup = True
Expand All @@ -262,7 +268,7 @@ def setup(self):
time.sleep(0.1)

self._send_command(0x12) # Soft Reset
self._busy_wait()
self._busy_wait(1.0)

def _busy_wait(self, timeout=30.0):
"""Wait for busy/wait pin."""
Expand Down Expand Up @@ -377,16 +383,24 @@ def set_border(self, colour):

def set_image(self, image):
"""Copy an image to the buffer.
The dimensions of `image` should match the dimensions of the display being used.
:param image: Image to copy.
:type image: :class:`PIL.Image.Image` or :class:`numpy.ndarray` or list
"""
if self.rotation % 180 == 0:
self.buf = numpy.array(image, dtype=numpy.uint8).reshape((self.width, self.height))
else:
self.buf = numpy.array(image, dtype=numpy.uint8).reshape((self.height, self.width))
image = image.resize((self.width, self.height))

if not image.mode == "P":
palette_image = Image.new("P", (1, 1))
r, g, b = 0, 0, 0
if self.colour == "red":
r = 255
if self.colour == "yellow":
r = g = 255
palette_image.putpalette([255, 255, 255, 0, 0, 0, r, g, b] + [0, 0, 0] * 252)
image.load()
image = image.im.convert("P", True, palette_image.im)

canvas = Image.new("P", (self.rows, self.cols))
width, height = image.size
canvas.paste(image, (0, 0, width, height))
self.buf = numpy.array(canvas, dtype=numpy.uint8).reshape((self.cols, self.rows))

def _spi_write(self, dc, values):
"""Write values over SPI.
Expand Down
40 changes: 30 additions & 10 deletions inky/inky_ssd1608.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"""Inky e-Ink Display Driver."""
import time
import warnings
from datetime import timedelta

import gpiod
import gpiodevice
import numpy
from gpiod.line import Direction, Edge, Value
from gpiod.line import Bias, Direction, Edge, Value
from gpiodevice import platform
from PIL import Image

Expand All @@ -26,7 +27,7 @@

MOSI_PIN = 10
SCLK_PIN = 11
CS0_PIN = 0
CS0_PIN = 8

_SPI_CHUNK_SIZE = 4096
_SPI_COMMAND = 0
Expand Down Expand Up @@ -104,6 +105,10 @@ def __init__(self, resolution=(250, 122), colour="black", cs_pin=CS0_PIN, dc_pin
self.reset_pin = reset_pin
self.busy_pin = busy_pin
self.cs_pin = cs_pin
try:
self.cs_channel = [8, 7].index(cs_pin)
except ValueError:
self.cs_channel = 0
self.h_flip = h_flip
self.v_flip = v_flip

Expand Down Expand Up @@ -135,15 +140,18 @@ def setup(self):
gpiochip = gpiodevice.find_chip_by_platform()
gpiodevice.friendly_errors = True
if gpiodevice.check_pins_available(gpiochip, {
"Chip Select": self.cs_pin,
"Data/Command": self.dc_pin,
"Reset": self.reset_pin,
"Busy": self.busy_pin
}):
self.cs_pin = gpiochip.line_offset_from_id(self.cs_pin)
self.dc_pin = gpiochip.line_offset_from_id(self.dc_pin)
self.reset_pin = gpiochip.line_offset_from_id(self.reset_pin)
self.busy_pin = gpiochip.line_offset_from_id(self.busy_pin)

self._gpio = gpiochip.request_lines(consumer="inky", config={
self.cs_pin: gpiod.LineSettings(direction=Direction.OUTPUT, output_value=Value.ACTIVE, bias=Bias.DISABLED),
self.dc_pin: gpiod.LineSettings(direction=Direction.OUTPUT, output_value=Value.INACTIVE),
self.reset_pin: gpiod.LineSettings(direction=Direction.OUTPUT, output_value=Value.ACTIVE),
self.busy_pin: gpiod.LineSettings(direction=Direction.INPUT, edge_detection=Edge.FALLING, debounce_period=timedelta(milliseconds=10))
Expand All @@ -154,7 +162,11 @@ def setup(self):

self._spi_bus = spidev.SpiDev()

self._spi_bus.open(0, self.cs_pin)
self._spi_bus.open(0, self.cs_channel)
try:
self._spi_bus.no_cs = True
except OSError:
warnings.warn("SPI: Cannot disable chip-select!")
self._spi_bus.max_speed_hz = 488000

self._gpio_setup = True
Expand All @@ -170,9 +182,12 @@ def setup(self):

def _busy_wait(self, timeout=5.0):
"""Wait for busy/wait pin."""
event = self._gpio.wait_edge_events(timedelta(seconds=timeout))
if not event:
raise RuntimeError("Timeout waiting for busy signal to clear.")
if self._gpio.get_value(self.busy_pin) == Value.ACTIVE:
event = self._gpio.wait_edge_events(timedelta(seconds=timeout))
if not event:
raise RuntimeError("Timeout waiting for busy signal to clear.")
for event in self._gpio.read_edge_events():
pass

def _update(self, buf_a, buf_b, busy_wait=True):
"""Update display.
Expand Down Expand Up @@ -267,21 +282,23 @@ def set_border(self, colour):

def set_image(self, image):
"""Copy an image to the display."""
image = image.resize((self.width, self.height))

if not image.mode == "P":
palette_image = Image.new("P", (1, 1))
r, g, b = 0, 0, 0
if self.colour == "red":
r = 255
if self.colour == "yellow":
g = 255
r = g = 255
palette_image.putpalette([255, 255, 255, 0, 0, 0, r, g, b] + [0, 0, 0] * 252)
image.load()
image = image.im.convert("P", True, palette_image.im)

canvas = Image.new("P", (self.cols, self.rows))
canvas = Image.new("P", (self.rows, self.cols))
width, height = image.size
canvas.paste(image, (self.offset_x, self.offset_y, width, height))
self.buf = numpy.array(canvas, dtype=numpy.uint8).reshape((self.rows, self.cols))
canvas.paste(image, (self.offset_x, self.offset_y, width + self.offset_x, height + self.offset_y))
self.buf = numpy.array(canvas, dtype=numpy.uint8).reshape((self.cols, self.rows))

def _spi_write(self, dc, values):
"""Write values over SPI.
Expand All @@ -290,6 +307,7 @@ def _spi_write(self, dc, values):
:param values: list of values to write
"""
self._gpio.set_value(self.cs_pin, Value.INACTIVE)
self._gpio.set_value(self.dc_pin, Value.ACTIVE if dc else Value.INACTIVE)
try:
self._spi_bus.xfer3(values)
Expand All @@ -298,6 +316,8 @@ def _spi_write(self, dc, values):
offset = x * _SPI_CHUNK_SIZE
self._spi_bus.xfer(values[offset : offset + _SPI_CHUNK_SIZE])

self._gpio.set_value(self.cs_pin, Value.ACTIVE)

def _send_command(self, command, data=None):
"""Send command over SPI.
Expand Down
2 changes: 1 addition & 1 deletion inky/inky_ssd1683.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def set_image(self, image):
if self.colour == "red":
r = 255
if self.colour == "yellow":
g = 255
r = g = 255
palette_image.putpalette([255, 255, 255, 0, 0, 0, r, g, b] + [0, 0, 0] * 252)
image.load()
image = image.im.convert("P", True, palette_image.im)
Expand Down

0 comments on commit cd66f78

Please sign in to comment.