Skip to content

Commit

Permalink
All: Always use software CS.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gadgetoid committed Feb 6, 2024
1 parent 0b50f4c commit 49945f7
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 53 deletions.
54 changes: 34 additions & 20 deletions inky/inky.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
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 . import eeprom

Expand All @@ -17,19 +18,19 @@
BLACK = 1
RED = YELLOW = 2

# GPIO pins required by BCM number
RESET_PIN = "PIN13" # GPIO 27
BUSY_PIN = "PIN11" # GPIO 17
DC_PIN = "PIN15" # GPIO 22
if platform.get_name().startswith("Raspberry Pi 5"):
RESET_PIN = "PIN13" # GPIO 27
BUSY_PIN = "PIN11" # GPIO 17
DC_PIN = "PIN15" # GPIO 22
else:
RESET_PIN = "GPIO27"
BUSY_PIN = "GPIO17"
DC_PIN = "GPIO22"

# In addition the following pins are used for SPI
# CS_PIN = 8
# MOSI_PIN = 10
# SCLK_PIN = 11
# SCLK_PIN = 11

# SPI channel for device 0
CS0 = 0
MOSI_PIN = 10
SCLK_PIN = 11
CS0_PIN = 8

_SPI_CHUNK_SIZE = 4096
_SPI_COMMAND = 0
Expand All @@ -55,7 +56,7 @@ class Inky:
RED = 2
YELLOW = 2

def __init__(self, resolution=(400, 300), colour="black", cs_channel=CS0, dc_pin=DC_PIN, reset_pin=RESET_PIN, busy_pin=BUSY_PIN, h_flip=False, v_flip=False,
def __init__(self, resolution=(400, 300), colour="black", cs_pin=CS0_PIN, dc_pin=DC_PIN, reset_pin=RESET_PIN, busy_pin=BUSY_PIN, h_flip=False, v_flip=False,
spi_bus=None, i2c_bus=None, gpio=None):
"""Initialise an Inky Display.
Expand Down Expand Up @@ -103,7 +104,11 @@ def __init__(self, resolution=(400, 300), colour="black", cs_channel=CS0, dc_pin
self.dc_pin = dc_pin
self.reset_pin = reset_pin
self.busy_pin = busy_pin
self.cs_channel = cs_channel
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 @@ -225,18 +230,21 @@ def setup(self):
gpiochip = gpiodevice.find_chip_by_platform()

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.dc_pin: gpiod.LineSettings(direction=Direction.OUTPUT),
self.reset_pin: gpiod.LineSettings(direction=Direction.OUTPUT),
self.busy_pin: gpiod.LineSettings(direction=Direction.INPUT, edge_detection=Edge.FALLING)
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, bias=Bias.DISABLED),
self.reset_pin: gpiod.LineSettings(direction=Direction.OUTPUT, output_value=Value.ACTIVE, bias=Bias.DISABLED),
self.busy_pin: gpiod.LineSettings(direction=Direction.INPUT, edge_detection=Edge.FALLING, bias=Bias.DISABLED)
})

if self._spi_bus is None:
Expand All @@ -258,9 +266,12 @@ def setup(self):

def _busy_wait(self, timeout=30.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 @@ -383,6 +394,7 @@ def _spi_write(self, dc, values):
:param dc: whether to write as data or command
: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 @@ -391,6 +403,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
12 changes: 9 additions & 3 deletions inky/inky_ac073tc1a.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import gpiod
import gpiodevice
from gpiod.line import Direction, Edge, Value
from gpiodevice import platform
from PIL import Image

from . import eeprom
Expand All @@ -24,9 +25,14 @@
ORANGE = 6
CLEAN = 7

RESET_PIN = "PIN13" # GPIO 27
BUSY_PIN = "PIN11" # GPIO 17
DC_PIN = "PIN15" # GPIO 22
if platform.get_name().startswith("Raspberry Pi 5"):
RESET_PIN = "PIN13" # GPIO 27
BUSY_PIN = "PIN11" # GPIO 17
DC_PIN = "PIN15" # GPIO 22
else:
RESET_PIN = "GPIO27"
BUSY_PIN = "GPIO17"
DC_PIN = "GPIO22"

MOSI_PIN = 10
SCLK_PIN = 11
Expand Down
12 changes: 9 additions & 3 deletions inky/inky_ssd1608.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import gpiodevice
import numpy
from gpiod.line import Direction, Edge, Value
from gpiodevice import platform
from PIL import Image

from . import eeprom, ssd1608
Expand All @@ -14,9 +15,14 @@
BLACK = 1
RED = YELLOW = 2

RESET_PIN = "PIN13" # GPIO 27
BUSY_PIN = "PIN11" # GPIO 17
DC_PIN = "PIN15" # GPIO 22
if platform.get_name().startswith("Raspberry Pi 5"):
RESET_PIN = "PIN13" # GPIO 27
BUSY_PIN = "PIN11" # GPIO 17
DC_PIN = "PIN15" # GPIO 22
else:
RESET_PIN = "GPIO27"
BUSY_PIN = "GPIO17"
DC_PIN = "GPIO22"

MOSI_PIN = 10
SCLK_PIN = 11
Expand Down
48 changes: 34 additions & 14 deletions inky/inky_ssd1683.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
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

from . import eeprom, ssd1683
Expand All @@ -14,13 +15,18 @@
BLACK = 1
RED = YELLOW = 2

RESET_PIN = 27
BUSY_PIN = 17
DC_PIN = 22
if platform.get_name().startswith("Raspberry Pi 5"):
RESET_PIN = "PIN13" # GPIO 27
BUSY_PIN = "PIN11" # GPIO 17
DC_PIN = "PIN15" # GPIO 22
else:
RESET_PIN = "GPIO27"
BUSY_PIN = "GPIO17"
DC_PIN = "GPIO22"

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

SUPPORTED_DISPLAYS = 17, 18, 19

Expand Down Expand Up @@ -86,6 +92,10 @@ def __init__(self, resolution=(400, 300), 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 @@ -117,26 +127,29 @@ 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.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))
self.cs_pin: gpiod.LineSettings(direction=Direction.OUTPUT, output_value=Value.INACTIVE, bias=Bias.DISABLED),
self.dc_pin: gpiod.LineSettings(direction=Direction.OUTPUT, output_value=Value.INACTIVE, bias=Bias.DISABLED),
self.reset_pin: gpiod.LineSettings(direction=Direction.OUTPUT, output_value=Value.ACTIVE, bias=Bias.DISABLED),
self.busy_pin: gpiod.LineSettings(direction=Direction.INPUT, edge_detection=Edge.FALLING, bias=Bias.DISABLED)
})

if self._spi_bus is None:
import spidev

self._spi_bus = spidev.SpiDev()

self._spi_bus.open(0, self.cs_pin)
self._spi_bus.open(0, self.cs_channel)
self._spi_bus.max_speed_hz = 10000000 # Should be good for 20MHz according to datasheet

self._gpio_setup = True
Expand All @@ -147,14 +160,17 @@ def setup(self):
time.sleep(0.5)

self._send_command(0x12) # Soft Reset
time.sleep(1.0)
time.sleep(1.0) # Required, or we'll miss buf_a (black)
self._busy_wait()

def _busy_wait(self, timeout=5.0):
def _busy_wait(self, timeout=30.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 @@ -272,14 +288,18 @@ 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)
except AttributeError:
for x in range(((len(values) - 1) // _SPI_CHUNK_SIZE) + 1):
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
31 changes: 18 additions & 13 deletions inky/inky_uc8159.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
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

from . import eeprom
Expand Down Expand Up @@ -43,9 +44,14 @@
[255, 255, 255]
]

RESET_PIN = "PIN13" # GPIO 27
BUSY_PIN = "PIN11" # GPIO 17
DC_PIN = "PIN15" # GPIO 22
if platform.get_name().startswith("Raspberry Pi 5"):
RESET_PIN = "PIN13" # GPIO 27
BUSY_PIN = "PIN11" # GPIO 17
DC_PIN = "PIN15" # GPIO 22
else:
RESET_PIN = "GPIO27"
BUSY_PIN = "GPIO17"
DC_PIN = "GPIO22"

MOSI_PIN = 10
SCLK_PIN = 11
Expand Down Expand Up @@ -218,12 +224,11 @@ def setup(self):
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),
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.RISING, debounce_period=timedelta(milliseconds=10))
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, bias=Bias.DISABLED),
self.reset_pin: gpiod.LineSettings(direction=Direction.OUTPUT, output_value=Value.ACTIVE, bias=Bias.DISABLED),
self.busy_pin: gpiod.LineSettings(direction=Direction.INPUT, edge_detection=Edge.RISING, debounce_period=timedelta(milliseconds=10), bias=Bias.DISABLED)
})

if self._spi_bus is None:
Expand All @@ -242,6 +247,7 @@ def setup(self):
self._gpio.set_value(self.reset_pin, Value.INACTIVE)
time.sleep(0.1)
self._gpio.set_value(self.reset_pin, Value.ACTIVE)
time.sleep(0.1)

self._busy_wait(1.0)

Expand Down Expand Up @@ -338,16 +344,14 @@ def _busy_wait(self, timeout=40.0):
return

for event in self._gpio.read_edge_events():
print(timeout, event)
if event.Type == Edge.RISING:
return

def _update(self, buf):
"""Update display.
Dispatches display update to correct driver.
:param buf_a: Black/White pixels
:param buf_b: Yellow/Red pixels
"""
self.setup()
self._send_command(UC8159_DTM1, buf)
Expand Down Expand Up @@ -438,6 +442,7 @@ def _spi_write(self, dc, values):
for x in range(((len(values) - 1) // _SPI_CHUNK_SIZE) + 1):
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):
Expand Down

0 comments on commit 49945f7

Please sign in to comment.