Freenove / WebIOPi

WebIOPi-0.7.1 for Raspberry B+, Pi2, Pi3, and Pi4
21 stars 8 forks source link

WebIOPi using piFace and raspios-bullseye does not start; spi init fails #4

Open noanight opened 2 years ago

noanight commented 2 years ago

Setup

uname -a
Linux piface 5.15.32+ #1538 Thu Mar 31 19:37:58 BST 2022 armv6l GNU/Linux

WebIOPi Config

[DEVICES]
pifaceModule = PiFaceDigital

Startup log

2022-04-20 16:51:18 - WebIOPi - INFO - Starting WebIOPi/0.7.1/Python3.9
2022-04-20 16:51:18 - WebIOPi - DEBUG - Mapping GPIO.digitalCount to REST GET /GPIO/count
2022-04-20 16:51:18 - WebIOPi - DEBUG - Mapping GPIO.digitalRead to REST GET /GPIO/%(channel)d/value
2022-04-20 16:51:18 - WebIOPi - DEBUG - Mapping GPIO.digitalWrite to REST POST /GPIO/%(channel)d/value/%(value)d
2022-04-20 16:51:19 - WebIOPi - DEBUG - Mapping GPIO.getFunctionString to REST GET /GPIO/%(channel)d/function
2022-04-20 16:51:19 - WebIOPi - DEBUG - Mapping GPIO.getPulse to REST GET /GPIO/%(channel)d/pulse
2022-04-20 16:51:19 - WebIOPi - DEBUG - Mapping GPIO.outputSequence to REST POST /GPIO/%(channel)d/sequence/%(args)s
2022-04-20 16:51:19 - WebIOPi - DEBUG - Mapping GPIO.portRead to REST GET /GPIO/*/integer
2022-04-20 16:51:19 - WebIOPi - DEBUG - Mapping GPIO.portWrite to REST POST /GPIO/*/integer/%(value)d
2022-04-20 16:51:19 - WebIOPi - DEBUG - Mapping GPIO.pulse to REST POST /GPIO/%(channel)d/pulse/
2022-04-20 16:51:19 - WebIOPi - DEBUG - Mapping GPIO.pulseAngle to REST POST /GPIO/%(channel)d/pulseAngle/%(value)f
2022-04-20 16:51:19 - WebIOPi - DEBUG - Mapping GPIO.pulseRatio to REST POST /GPIO/%(channel)d/pulseRatio/%(value)f
2022-04-20 16:51:19 - WebIOPi - DEBUG - Mapping GPIO.setFunctionString to REST POST /GPIO/%(channel)d/function/%(value)s
2022-04-20 16:51:19 - WebIOPi - DEBUG - Mapping GPIO.wildcard to REST GET /GPIO/*
2022-04-20 16:51:19 - WebIOPi - INFO - GPIO - Native mapped to REST API /GPIO
2022-04-20 16:51:19 - WebIOPi - INFO - Loading configuration from /etc/webiopi/config
2022-04-20 16:51:19 - WebIOPi - INFO - Loading SPI modules
2022-04-20 16:51:19 - WebIOPi - DEBUG - Loading module : spi-bcm2708
modprobe: FATAL: Module spi-bcm2708 not found in directory /lib/modules/5.15.32+
2022-04-20 16:51:19 - WebIOPi - DEBUG - Loading module : spidev
2022-04-20 16:51:19 - WebIOPi - ERROR - 
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/WebIOPi-0.7.1-py3.9-linux-armv6l.egg/webiopi/__main__.py", line 75, in <module>
    main(sys.argv)
  File "/usr/local/lib/python3.9/dist-packages/WebIOPi-0.7.1-py3.9-linux-armv6l.egg/webiopi/__main__.py", line 69, in main
    server = Server(port=port, configfile=configfile, scriptfile=scriptfile)
  File "/usr/local/lib/python3.9/dist-packages/WebIOPi-0.7.1-py3.9-linux-armv6l.egg/webiopi/server/__init__.py", line 66, in __init__
    manager.addDevice(name, driver, args)
  File "/usr/local/lib/python3.9/dist-packages/WebIOPi-0.7.1-py3.9-linux-armv6l.egg/webiopi/devices/manager.py", line 28, in addDevice
    dev = devClass()
  File "/usr/local/lib/python3.9/dist-packages/WebIOPi-0.7.1-py3.9-linux-armv6l.egg/webiopi/devices/shield/piface.py", line 22, in __init__
    mcp = MCP23S17(0, 0x20+board)
  File "/usr/local/lib/python3.9/dist-packages/WebIOPi-0.7.1-py3.9-linux-armv6l.egg/webiopi/devices/digital/mcp23XXX.py", line 148, in __init__
    MCP23SXX.__init__(self, chip, slave, 16, "MCP23S17")
  File "/usr/local/lib/python3.9/dist-packages/WebIOPi-0.7.1-py3.9-linux-armv6l.egg/webiopi/devices/digital/mcp23XXX.py", line 119, in __init__
    SPI.__init__(self, toint(chip), 0, 8, 10000000)
  File "/usr/local/lib/python3.9/dist-packages/WebIOPi-0.7.1-py3.9-linux-armv6l.egg/webiopi/devices/spi.py", line 98, in __init__
    assert(self.mode == mode)
AssertionError

Errors

modprobe: FATAL: Module spi-bcm2708 not found in directory /lib/modules/5.15.32+

from https://forums.raspberrypi.com/viewtopic.php?p=675658#p675658

The January 2015 Raspbian release, with Pi 2 support, switches to a new kernel (3.18), and includes a configuration change to enable Device Tree support by default. This has caused some previously working things to mysteriously stop working, but with a few configuration changes normal service should be resumed. We'll tell you how to do that in a moment, but first here's some background information. 

Conclusion: so no module load required

Workaround

sudo nano /usr/local/lib/python3.9/dist-packages/WebIOPi-0.7.1-py3.9-linux-armv6l.egg/webiopi/devices/bus.py

replace spi-bcm2708 with spi-bcm2835

BUSLIST = { "I2C": {"enabled": False, "gpio": {0:"SDA", 1:"SCL", 2:"SDA", 3:"SCL"}, "modules": ["i2c-bcm2708", "i2c-dev"]}, "SPI": {"enabled": False, "gpio": {7:"CE1", 8:"CE0", 9:"MISO", 10:"MOSI", 11:"SCLK"}, "modules": ["spi-bcm2835", "spidev"]> "UART": {"enabled": False, "gpio": {14:"TX", 15:"RX"}}, "ONEWIRE": {"enabled": False, "gpio": {4:"DATA"}, "modules": ["w1-gpio"], "wait": 2} }

SPI.init(self, toint(chip), 0, 8, 10000000) File "/usr/local/lib/python3.9/dist-packages/WebIOPi-0.7.1-py3.9-linux-armv6l.egg/webiopi/devices/spi.py", line 98, in init assert(self.mode == mode)

Workaround

sudo nano /usr/local/lib/python3.9/dist-packages/WebIOPi-0.7.1-py3.9-linux-armv6l.egg/webiopi/devices/spi.py
class SPI(Bus):
    def __init__(self, chip=0, mode=0, bits=8, speed=0):
        Bus.__init__(self, "SPI", "/dev/spidev0.%d" % chip)
        self.chip = chip

        val8 = array.array('B', [0])
        val8[0] = mode
        '''
        if fcntl.ioctl(self.fd, SPI_IOC_WR_MODE, val8):
            raise Exception("Cannot write SPI Mode")
        if fcntl.ioctl(self.fd, SPI_IOC_RD_MODE, val8):
            raise Exception("Cannot read SPI Mode")
        self.mode = struct.unpack('B', val8)[0]
        assert(self.mode == mode)
        '''
MichaIng commented 2 years ago

Confirmed: https://github.com/raspberrypi/linux/commit/bdfc988 This was removed with RPi Linux 4.3 already, spi-bcm2835 is available instead.

MichaIng commented 2 years ago

The same is true for I2C: While the module is still available, it is deprecated in favour of i2c-bcm2835: https://forums.raspberrypi.com/viewtopic.php?t=133024

MichaIng commented 2 years ago

PR up to fix this: #5

noanight commented 2 years ago

I think the loadModule and unloadModule Functions, calling modprobe, should be removed, because it's outdated. The Kernel uses device tree.

noanight commented 2 years ago

About the failing assert...

SPI_CS_HIGH Flag is always set when reading the SPI mode...though the assertion fails.

According to https://github.com/raspberrypi/linux/issues/3745

_CS_HIGH handling has changed between 4.19 and 5.4 - the SPI framework forces CS_HIGH then leaves it up to the GPIO layer to handle the ACTIVE_LOW semantics. I don't like the change because it is (ab)using user-facing flags - CS_HIGH no longer means what you think it means. The attitude upstream (and I may be missing some nuance here) seems to be that CS_HIGH is a bus property rather than a device property - if you have to wait until an application starts to reverse the polarity of one of the CS pins then the device has possibly already been responding to and interfering with devices on other CS lines from the same controller.

In short - dropping the device.cshigh = False line not only makes it work but is the right thing to do. Under other circumstances this kernel change might have broken other aspects of the py-spidev library, but I think the fact that it reads the initial value of the mode from spidev means that everything is fine unless you try to clear cshigh._

https://github.com/raspberrypi/linux/issues/4018 https://forums.raspberrypi.com/viewtopic.php?t=304156

Tried the C Version with the same result...SPI_CS_HIGH is set.

wget https://raw.githubusercontent.com/torvalds/linux/master/tools/spi/spidev_test.c
gcc -o spidev_test spidev_test.c
./spidev_test -D /dev/spidev0.0
sudo nano /usr/local/lib/python3.9/dist-packages/WebIOPi-0.7.1-py3.9-linux-armv6l.egg/webiopi/devices/spi.py

SPI_CS_HIGH     = 0x04
# SPI_LSB_FIRST   = 0x08
# SPI_3WIRE       = 0x10
# SPI_LOOP        = 0x20
# SPI_NO_CS       = 0x40
# SPI_READY       = 0x80
...
...
..

class SPI(Bus):
    def __init__(self, chip=0, mode=0, bits=8, speed=0):
        Bus.__init__(self, "SPI", "/dev/spidev0.%d" % chip)
        self.chip = chip

        val8 = array.array('B', [0])
        val8[0] = mode
        if fcntl.ioctl(self.fd, SPI_IOC_WR_MODE, val8):
            raise Exception("Cannot write SPI Mode")
        if fcntl.ioctl(self.fd, SPI_IOC_RD_MODE, val8):
            raise Exception("Cannot read SPI Mode")
        self.mode = struct.unpack('B', val8)[0]
        self.mode &= ~SPI_CS_HIGH
        assert(self.mode  == mode)