rm-hull / luma.core

A component library providing a Pillow-compatible drawing canvas, and other functionality to support drawing primitives and text-rendering capabilities for small displays on the Raspberry Pi and other single board computers.
https://luma-core.readthedocs.io
MIT License
148 stars 52 forks source link

ftdi_spi doesn't appear to support chips with more than 8 GPIO's #251

Closed jasongaunt closed 2 years ago

jasongaunt commented 2 years ago

System: Ubuntu 22.04 Linux Kernel: 5.15.0-48-generic Python version: 3.10.6

This is potentially an odd one, fringe case or even PICNIC.

I'm trying to utilise a SSD1322 OLED display through an FTDI FT232h USB adapter. The chip on the adapter has 2x GPIO banks (the usual ADBUS pins 0-7 labelled as D0-7, and the secondary ACBUS pins 0-7 labelled as pins C0-7)...

Schematic

This used to work fine under Ubuntu 16.04 using the Adafruit_GPIO Python2.7 module to wrap the SPI interface (it provided an abstraction of FT232H) with the following pin configuration...

CS = 3     #D3 Brown
RESET = 13 #C5 Purple
DC = 14    #C6 White

...however this has been completely dropped and I've migrated to pyftdi to try and return to what the luma.core documents state. In migrating, I now find myself with this error:

pyftdi.spi.SpiIOError: No such GPO pins: 0000/2000

This is the code I've written to try and initialise it;

from luma.core.interface.serial import ftdi_spi
from luma.core.render import canvas
from luma.oled.device import ssd1322

SPI = ftdi_spi(device='ftdi://ftdi:232h:RP39WI7Z/1', bus_speed_hz=8E6, gpio_CS=3, gpio_DC=14, gpio_RST=13)

To which I get the following traceback;

Traceback (most recent call last):
  File "/root/src/oled-esxi/test.py", line 67, in <module>
    SPI = ftdi_spi(device='ftdi://ftdi:232h:RP39WI7Z/1', bus_speed_hz=8E6, gpio_CS=3, gpio_DC=14, gpio_RST=13)
  File "/root/src/oled-esxi/venv/lib/python3.10/site-packages/luma/core/interface/serial.py", line 495, in ftdi_spi
    serial = spi(
  File "/root/src/oled-esxi/venv/lib/python3.10/site-packages/luma/core/interface/serial.py", line 299, in __init__
    bitbang.__init__(self, gpio, transfer_size, reset_hold_time, reset_release_time, DC=gpio_DC, RST=gpio_RST)
  File "/root/src/oled-esxi/venv/lib/python3.10/site-packages/luma/core/interface/serial.py", line 195, in __init__
    self._gpio.output(self._RST, self._gpio.HIGH)  # Keep RESET pulled high
  File "/root/src/oled-esxi/venv/lib/python3.10/site-packages/luma/core/interface/serial.py", line 427, in output
    self._gpio.write(self._data)
  File "/root/src/oled-esxi/venv/lib/python3.10/site-packages/pyftdi/spi.py", line 316, in write
    return self._controller.write_gpio(value)
  File "/root/src/oled-esxi/venv/lib/python3.10/site-packages/pyftdi/spi.py", line 682, in write_gpio
    raise SpiIOError('No such GPO pins: %04x/%04x' %
pyftdi.spi.SpiIOError: No such GPO pins: 0000/2000

Sadly I cannot simply "rewire" - this was a small run custom PCB made by an Aida64 forum member and as such, immutable.

The pyftdi module references 16-bit wide GPIOs for the 232h so I know this is possible. Richard (or perhaps another developer), please can you look into this when you find yourself with a few mins? šŸ„°

rm-hull commented 2 years ago

Probably better off raising this directly with pyftdi developers?

jasongaunt commented 2 years ago

Hi @rm-hull , sadly it's actually a bug in luma.core. It's a really easy fix though, this was all that was required;

In luma/core/interface/serial.py on line 493 is this line...

    gpio.set_direction(pins, pins & 0xFF)

This needs to be changed to the following;

    if (gpio.width == 16):
        gpio.set_direction(pins, pins & 0xFFFF)
    else:
        gpio.set_direction(pins, pins & 0xFF)

Or as a quick dirty one-liner;

    gpio.set_direction(pins, pins & ((1 << gpio.width) - 1))

Hope this helps šŸ‘

thijstriemstra commented 2 years ago

great, could you make a pull request @jasongaunt?

rm-hull commented 2 years ago

@jasongaunt thanks for investigating. Do you happen to know what are the permissible values of gpio.width are? I would assume 8, 16, 32, ... if so, then the one-liner is probably a better choice

jasongaunt commented 2 years ago

Good morning @rm-hull and @thijstriemstra ,

According to the GPIO API page on pyftdi the following GPIO configurations exist;

I don't quite know if there'll be any issues accessing the devices with two or four ports, I don't have one to test. I'll see if I can get hold of one though.

Lets get it working for the single ports first and assess if this needs to be fixed for the dual / quad port chips later. Purely based on the first 4 bullets above I'd say the one-liner is the best option for scalability.

Pull request #257 has been raised šŸ‘

jasongaunt commented 2 years ago

FT2232H-based dev kit (2x 16-bit wide GPIO ports) ordered for testing and I have a spare ST7735-based LCD display in the "I'm bored now" box šŸ‘

Edit: Tigard dev board now due Weds (12th Oct 2022)

jasongaunt commented 2 years ago

So Amazon managed to lose it...

Lost package

Have chosen an alternative and it's on its way; https://www.mouser.co.uk/ProductDetail/895-FT2232HMINIMOD

thijstriemstra commented 2 years ago

Pull request https://github.com/rm-hull/luma.core/pull/257 has been raised

Closing.