BLINKT! or other HAT/pHat with Pi as GPIO expander

Hi,

In issue #67 of MagPi there is a article on how to setup a Pi as a GPIO expander.

I am running a MacBook with Raspbian Stretch and was wondering if there was anyway to use a Blinkt or other HAT from a system running Stretch Desktop with a PiZero as a GPIO expander?

Can the HAT/pHat libraries be installed onto the Pi GPIO expander once it is attached to a Stretch desktop system … ?

Andy

I don’t know the answer but I’m interested in any info anybody has on this. First thoughts are its not going to work. I think its a bit limited in what it can do? I played with it a while back but didn’t really pursue it much beyond a quick look see. It probably hinges on whether i2c and or SPI are accessible VIA the USB link. I do believe the Pi is in gadget mode or something?

I’m not entirely sure how the GPIO expander setup works, either! I haven’t had much time to look into it.

It should be possible to run Blinkt! quite trivially, since all the Blinkt! library really does is twiddle a couple of GPIO pins.

What I think this requires is either:

  • Libraries for our HATs/pHATs that are based upon GPIO Zero

Or

  • Support for the various peripherals our HATs/pHATs use in GPIO Zero, and examples to show how to control specific HATs and pHATs with these

I much prefer the latter for a few reasons:

  1. Our current libraries work well on the Pi with very minimal reliance on third party code, and if it ain’t broke don’t fix it!
  2. I think examples + support in GPIO Zero gives users better learning opportunities, and more awareness of what’s on a particular HAT/pHAT
  3. They will also allow users to mix/match features from HATs/pHATs into one Python program without needing a full library for each

At the moment GPIO Zero has no specific support for APA102 pixels (which are what the Blinkt! uses) but it does have support for SPI on arbitrary pins. However attempting to look into how to actually use this support has left me absolutely flummoxed! Possibly because: https://github.com/RPi-Distro/python-gpiozero/issues/551

I don’t know if this will work via the GPIO expander setup, but:

import time
import colorsys
import gpiozero

class Apa102(gpiozero.SPIDevice):
    def __init__(self, *args, **kwargs):
        gpiozero.SPIDevice.__init__(self, *args, **kwargs)

        self._led_count = kwargs.get('led_count', 8)
        self._led_values = [[0, 0, 0, 0] for _ in range(self._led_count)]

    def set_pixel(self, x, r, g, b, brightness=1.0):
        self._led_values[x] = [r, g, b, brightness]

    def set_all(self, r, g, b, brightness=1.0):
        for x in range(self._led_count):
            self.set_pixel(x, r, g, b, brightness)

    def show(self):
        data = []

        # Start Of Frame
        for _ in range(4):
            data.append(0)

        for led in self._led_values:
            r, g, b, brightness = led
            brightness = max(0, min(0b11111, int(brightness * 0b11111)))
            data.append(0b11100000 | brightness)
            data.append(b & 0xff)
            data.append(g & 0xff)
            data.append(r & 0xff)

        # End Of Frame
        for _ in range(5):
            data.append(0)

        self._spi.transfer(data)


blinkt = Apa102(mosi_pin=23, clock_pin=24)
blinkt.set_pixel(0, 0, 0, 255)
blinkt.set_pixel(1, 0, 255, 0)
blinkt.set_pixel(2, 255, 0, 0)
blinkt.show()
time.sleep(1.0)

while True:
    r, g, b = [int(c * 255) for c in colorsys.hsv_to_rgb(time.time() / 10, 1.0, 1.0)]
    blinkt.set_all(r, g, b, brightness=0.5)
    blinkt.show()
    time.sleep(1.0 / 60)