adafruit / Adafruit_Blinka

Add CircuitPython hardware API and libraries to MicroPython & CPython devices
https://learn.adafruit.com/circuitpython-on-raspberrypi-linux
MIT License
448 stars 335 forks source link

inconsistent spidev index on BeagleBone/PocketBeagle #106

Closed pdp7 closed 5 years ago

pdp7 commented 5 years ago

This issue effects boards with the AM3358 chip such as BeagleBone and PocketBeagle. It was discovered while testing #100.

The index in the spidev path can be inconsistent between kernel builds. This means that sometimes SPI0 is /dev/spidev0.x and sometimes SPI0 is /dev/spidev1.x

For example, SPI0 is /dev/spidev1.0 when using the 4.14.108-ti-r103 kernel:

debian@beaglebone:~$ ls -ltar /dev/spidev*
crw-rw---- 1 root spi 153, 0 Apr 12 17:42 /dev/spidev1.0
crw-rw---- 1 root spi 153, 1 Apr 12 17:42 /dev/spidev2.0
crw-rw---- 1 root spi 153, 2 Apr 12 17:42 /dev/spidev2.1

However, SPI0 is /dev/spidev0.0 when using the 4.14.106-bone20 kernel:

debian@beaglebone:~$ ls -la /dev/spidev*
crw-rw---- 1 root spi 153, 0 Apr 13 13:35 /dev/spidev0.0
crw-rw---- 1 root spi 153, 1 Apr 13 13:35 /dev/spidev1.0
crw-rw---- 1 root spi 153, 2 Apr 13 13:35 /dev/spidev1.1
pdp7 commented 5 years ago

Short-term workaround for spidev path:

Install bone instead of ti kernel:

sudo /opt/scripts/tools/update_kernel.sh --bone-kernel --lts-4_14
reboot

SPI0 is now /dev/spidev0.0:

debian@beaglebone:~$ ls -ltar /dev/spidev*
crw-rw---- 1 root spi 153, 0 Apr 13 13:35 /dev/spidev0.0
crw-rw---- 1 root spi 153, 2 Apr 13 13:35 /dev/spidev1.1
crw-rw---- 1 root spi 153, 1 Apr 13 13:35 /dev/spidev1.0
pdp7 commented 5 years ago

Long-term solution

@RobertCNelson added udev rules to add symlinks that will not change:

For reference the udev rule:

debian@beaglebone:/etc/udev/rules.d$ cat 10-of-symlink.rules 
# vim: ft=udevrules

#From: https://github.com/mvduin/py-uio/blob/master/etc/udev/rules.d/10-of-symlink.rules

# allow declaring a symlink for a device in DT

ATTR{device/of_node/symlink}!="", \
    ENV{OF_SYMLINK}="%s{device/of_node/symlink}"

ENV{OF_SYMLINK}!="", ENV{DEVNAME}!="", \
    SYMLINK+="%E{OF_SYMLINK}", \
    TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/dev/%E{OF_SYMLINK}"

With symlink properties added to the device tree, these symlinks are created by udev:

debian@beaglebone:~$ ls -la /dev/spi/
total 0
drwxr-xr-x  2 root root  100 Apr 13 13:35 .
drwxr-xr-x 16 root root 3180 Apr 13 13:35 ..
lrwxrwxrwx  1 root root   12 Apr 13 13:35 0.0 -> ../spidev0.0
lrwxrwxrwx  1 root root   12 Apr 13 13:35 1.0 -> ../spidev1.0
lrwxrwxrwx  1 root root   12 Apr 13 13:35 1.1 -> ../spidev1.1
pdp7 commented 5 years ago

Issue with long-term solution

I'm uncertain of the correct approach to add logic in Adafruit_Blinka to use the /dev/spi/X.Y for BeagleBone and PocketBeagle. Currently, Adafruit_Blinka generic_linux SPI implementation just uses py-spidev Python module and I don't believe has a way to communicate the /dev/ path to use.

In theory, this logic could be added to py-spidev but I am not sure if the maintainer would approve of this approach, and how long it would take to get merged.

pdp7 commented 5 years ago

Possible solution: create SPI class for am335x chip

Currently in busio, detector.board.any_beaglebone uses adafruit_blinka.microcontroller.generic_linux.spi:

    def configure(self, baudrate=100000, polarity=0, phase=0, bits=8):
        if detector.board.any_raspberry_pi:
            from adafruit_blinka.microcontroller.bcm283x.pin import Pin
            from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
        elif detector.board.any_beaglebone:
            from adafruit_blinka.microcontroller.am335x.pin import Pin
            from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI

However, it is possible to create adafruit_blinka.microcontroller.am335x.spi and then do this:

        elif detector.board.any_beaglebone:
            from adafruit_blinka.microcontroller.am335x.pin import Pin
            from adafruit_blinka.microcontroller.am335x.spi import SPI as _SPI

I think that adafruit_blinka.microcontroller.am335x.spi could just implement the logic to handled the SPI port index and not re-implement everything in adafruit_blinka.microcontroller.generic_linux.spi. I need to experiment and see if that is possible.

ladyada commented 5 years ago

hiya the beaglbone maintainers need to fix onto one SPI naming, no other linux board changes the SPI port name - we'll go with whatever the latest is.

RobertCNelson commented 5 years ago

@ladyada this situation pisses me off too, from 3.8.x to 4.4.x we dealt with uart/gpio/mmc renaming due to mainline changes. And now spi bit us in the butt with 4.14.x (but i reverted that change) to give us time to build a fix/workaround for 4.19.x. Since for me it's all personal time on this, if i have a choice between mainline and our hacks, i'll drop our patch like a rock (thank god the patchset is getting smaller). Now @jadonk, is proposing a workaround that would also a similar api naming for the incoming BeagleBone AI, such we can lock in something, while mainline will keep renaming things..

https://elinux.org/Beagleboard:BeagleBone_cape_interface_spec

Regards,

pdp7 commented 5 years ago

@RobertCNelson thanks for the explanation.

@ladyada thanks, your comment made me realize that I can adjust the indexes in spiPorts inside microcontroller/am335x/pin.py

SPI0 is /dev/spidev1.x and SPI1 is /dev/spidev2.x on both:

I think spiPorts should changed from:

# ordered as spiId, sckId, mosiId, misoId
spiPorts = (
    (0, SPI0_SCLK, SPI0_D1, SPI0_D0),
    (1, SPI1_SCLK, SPI1_D1, SPI1_D0),
)

to:

# ordered as spiId, sckId, mosiId, misoId
spiPorts = (
    (1, SPI0_SCLK, SPI0_D1, SPI0_D0),
    (2, SPI1_SCLK, SPI1_D1, SPI1_D0),
)

By the way, the new BeagleBone AI should hopefully launch this Summer. It uses a much more powerful TI Sitara AM5729 SoC but keeps the traditional P8/P9 BeagleBone headers. @jadonk has been working on BeagleBone cape interface spec so that we can have consistency between the new and old BeagleBones.

ladyada commented 5 years ago

nice - yes id rather mess with the pins/spi index definition than the core blinka SPI code. lets keep that neat and organized :)