pimoroni / blinkt

Python Library for Blinkt; 8 APA102 LEDs for your Raspberry Pi
https://shop.pimoroni.com/products/blinkt
MIT License
314 stars 103 forks source link

Any interest in spi-gpio? #65

Closed shenghaoyang closed 2 years ago

shenghaoyang commented 6 years ago

Upstream raspberrypi/linux recently put in a commit to enabe the spi-gpio functionality in the kernel (might see the change trickling down soon). This allows the kernel to handle all the SPI bitbanging, and software simply accesses SPI functionality through spidev device files. This works over any chosen set of GPIOs, that are not in use by the kernel otherwise.

Might it be possible to support this method of control as well? I've tested running the Blinkt! off this functionality on the Arch Linux ARM kernel, that has the module enabled a long time ago. Wrote a C++ application to relay E1.31 data to the Blinkt, but if anyone's interested I could port something to python.

Since the kernel now handles all the timing to achieve a particular data rate, there shouldn't be problems like #62 cropping up, since it knows when it has called into the hardware better than userspace, anyway. Might make the kernel GPIO maintainers happier too, see: https://www.kernel.org/doc/Documentation/gpio/drivers-on-gpio.txt (just a joke, heh.)

All that's needed is a device tree overlay, to specify the pins used to control the blinkt.

Gadgetoid commented 6 years ago

Is a custom dtoverlay necessary, or will there be a helper dtbo like there is with i2c-gpio?

IE: something like dtoverlay=spi-gpio,mosi=A,miso=B,clk=C

And if there's a helper dtbo, is it possible to load it at runtime with the dtoverlay command and have a new SPI bus pop up, or is it an on-boot-only deal (I haven't had any success loading i2c-gpio at runtime).

Don't worry if you don't know the answers, I can probably go digging, but I'm just trying to picture how Blinkt! (and other boards using bitbanged SPI for apa102s) might be able to detect and automatically switch between Python bitbanged GPIO and the kernel driver.

shenghaoyang commented 6 years ago

Is a custom dtoverlay necessary, or will there be a helper dtbo like there is with i2c-gpio?`

Well, the original pull request by the author over on raspberrypi/linux included an overlay, but it wasn't configurable and overrode spi0. In the end, the kernel functionality was enabled but overlay inclusion was skipped pending a better one. Not sure how good it would have been, though, since the software SPI driver can be configured in amazing ways. I had it drive the Blinkt without reserving a MISO pin or a SS pin. Maybe someone will come up with a generic overlay that provides a simple way of allocating those, but I think that would involve a bit of device tree parameter magic.

is it possible to load it at runtime with the dtoverlay command and have a new SPI bus pop up, or is it an on-boot-only deal (I haven't had any success loading i2c-gpio at runtime).

When I wrote the overlay for the blinkt, I had success loading it at runtime using configfs and dtoverlay, assuming ArchArm bundled the same dtoverlay tool. The kernels should be roughly the same, though, so that should work.

I'm just trying to picture how Blinkt! (and other boards using bitbanged SPI for apa102s) might be able to detect and automatically switch between Python bitbanged GPIO and the kernel driver.

udev rules seem to be perfect for this. The device node in the overlay can be given a unique name, and udev can be used to match on that name and create symlinks under /dev like blinkt, deadbeef, etc, so you could check whether the HAT can be driven using the kernel bitbanged SPI.

Gadgetoid commented 6 years ago

Thanks for the super detailed reply. I'm particularly intrigued by the ability to exclude MISO/SS since write-only SPI busses are particularly common for displays/LEDs.

Regarding detection, I'm going to have to brush up on udev and see what I can cobble together! I think this will probably be of utility only to advanced users, but it's something worth investigating.

shenghaoyang commented 6 years ago

Thanks for the super detailed reply. I'm particularly intrigued by the ability to exclude MISO/SS since write-only SPI busses are particularly common for displays/LEDs.

No problem. I'd just want to try and see people shift away from using libraries that access GPIO through mapping the GPIO registers into the relevant processes' address space - feels a bit hacky, like you're going around the kernel instead of coexisting with it. Not to mention that this doesn't really play nice with restrictive environments, and could lead to conflicts between different users.

Hopefully people start moving towards using the GPIO character device and also taking advantage of using the kernel to bitbang interfaces (a-la spi-gpio, i2c-gpio). It'll probably make porting easier, too, since a comparable kernel on another device should offer the same interfaces.

I think this will probably be of utility only to advanced users, but it's something worth investigating.

Yeah, that might be true for now, but I think it's a much more stable path forward for these kinds of devices in the future.

marvinroger commented 4 years ago

Can someone share a blinkt .dts? Something like this:

/dts-v1/;
/plugin/;

/ {
    compatible = "brcm,bcm2708";
    fragment@0 {
        target = <&spi0>;
        #address-cells = <1>;
        #size-cells = <0>;
        __overlay__ {
            compatible = "spi-gpio";
            #address-cells = <1>;
            #size-cells = <0>;
            ranges;
            mosi-gpios = <&gpio 23 0>;
            sck-gpios = <&gpio 24 0>;
            cs-gpios = <&gpio 25 1>;
            num-chipselects = <1>;
            status = "ok";
            spidev@1{
                compatible = "spidev";
                reg = <0>;
                spi-max-frequency = <2000000>;
            };
        };
    };
};

This overrides spi0, and cs-gpios should be optional if num-chipselects = <0>, but /dev/spidev0.0 does not show up if these parameters are not set.

Am I on the right track? To be honest, I quite don't know what I'm doing!

Gadgetoid commented 4 years ago

I don't have any experience with spi-gpio, but do you see /dev/spidev0.

/dev/spidev0.0 implies Channel 0, Chip-select 0 and if you have 0 chip-select pins then it would strike me as redundant to specify a chip-select in the device node name since it's not possible to refer to the nth of an empty set.

marvinroger commented 4 years ago

No, I don't see any /dev/spi*.

To be more precise:

Thanks for your answer!

Gadgetoid commented 4 years ago

Related, I wonder? https://patchwork.kernel.org/patch/11150619/

Gadgetoid commented 4 years ago

Yup:

static int spi_gpio_setup(struct spi_device *spi)
{
    struct gpio_desc    *cs;
    int         status = 0;
    struct spi_gpio     *spi_gpio = spi_to_spi_gpio(spi);

    /*
     * The CS GPIOs have already been
     * initialized from the descriptor lookup.
     */
    cs = spi_gpio->cs_gpios[spi->chip_select];
    if (!spi->controller_state && cs)
        status = gpiod_direction_output(cs,
                        !(spi->mode & SPI_CS_HIGH));

    if (!status)
        status = spi_bitbang_setup(spi);

    return status;
}

From: https://github.com/raspberrypi/linux/blob/rpi-4.19.y/drivers/spi/spi-gpio.c#L235-L254

shenghaoyang commented 4 years ago

https://raw.githubusercontent.com/shenghaoyang/e131_blinkt/master/blinkt-overlay.dts

That's what I had working in arch back in the day, but it seems it won't work so long as the bug in 4.19 remains unfixed.

shenghaoyang commented 4 years ago

This patch popped up on lkml. Seems someone wrote a driver for apa102 LEDs that exposes them to userspace as classic LEDs that I presume could be controlled from sysfs?

https://lwn.net/ml/linux-kernel/1582018657-5720-1-git-send-email-nbelin@baylibre.com/

On Thu, Dec 19, 2019, 00:11 Philip Howard notifications@github.com wrote:

Yup:

static int spi_gpio_setup(struct spi_device spi) { struct gpio_desc cs; int status = 0; struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);

/*

  • The CS GPIOs have already been
  • initialized from the descriptor lookup. */ cs = spi_gpio->cs_gpios[spi->chip_select]; if (!spi->controller_state && cs) status = gpiod_direction_output(cs, !(spi->mode & SPI_CS_HIGH));

    if (!status) status = spi_bitbang_setup(spi);

    return status; }

From: https://github.com/raspberrypi/linux/blob/rpi-4.19.y/drivers/spi/spi-gpio.c#L235-L254

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/pimoroni/blinkt/issues/65?email_source=notifications&email_token=ACPEEDAQZTYW3NEMF55A7D3QZJDRJA5CNFSM4FERTZ62YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEHGUETA#issuecomment-567099980, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACPEEDHZ4VZIC6HYBSHNEZDQZJDRJANCNFSM4FERTZ6Q .

Gadgetoid commented 4 years ago

This is interesting- we're working on another board that involves apa102 LEDs that this kind of driver would be very well suited for. I wonder how long it will take to make it through the pipeline. Thanks for bringing it to our attention!