SPIDev `cshigh` fails after update to 5.4.51-v7l+
Closed this issue · 8 comments
Prior to 5.4.51 setting device.cshigh = False
using Python's spidev would return without error.
Now it's returning a SystemError:
pi@raspberrypi:~ $ python3
Python 3.7.3 (default, Dec 20 2019, 18:57:59)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from unicornhatmini import UnicornHATMini
>>> uh = UnicornHATMini()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.7/dist-packages/unicornhatmini/__init__.py", line 56, in __init__
device.cshigh = False
SystemError: error return without exception set
>>> exit()
Under the hood this is running something like:
ioctl(fd, SPI_IOC_WR_MODE, SPI_CS_HIGH);
It's possible the SystemError is the expected result and there's something wrong with the spidev library, but since it's a sudden failure as of the new 5.x kernel I'm reporting it here just in case.
The above Python code uses the unicornhatmini
library, which just happens to attempt to set cshigh
and serves as a method to replicate this bug.
When you say "Prior to 5.4.51" do you mean 5.4.50 or 4.19.something?
Reading the linking report (thanks, GitHub) I think it must have been 4.19.
Related issue #3355
I've been playing with this but on rpi-5.7.y branch.
unicornhat uses py-spidev under the hood https://github.com/pimoroni/unicornhatmini-python/blob/master/library/unicornhatmini/__init__.py#L6
Sorry, I seem to have deleted the c code I was using to test this, I did the same thing that py-spidev does in its c module, so I'll just link to spidev code lines with comments:
https://github.com/doceme/py-spidev/blob/master/spidev_module.c#L896-L899 This ioctl call succeeds.
However the test to check if the mode actually changed fails, CS_HIGH is still present https://github.com/doceme/py-spidev/blob/master/spidev_module.c#L900-L904
PS: so it seems that ioctl that changes the mode succeeds but without actually changing the mode.
Other non CS related mode changes eg plain 0/1/2/3 seem to succeed.
That's correct- sorry I should have grabbed this info before I updated.
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.
P.S. At some point they may come out with an alternative to spidev
, but until then we're stuck with that behaviour.
P.P.S. If you try the same code on an upstream kernel the attempt to set cshigh to False will succeed, but the actual on-the-wire CS polarity will be inverted - as if you had set cshigh to True in the previous version - because you've trashed the magic flag. I have a patch in the Pi kernel that preserves/reasserts the flag, but at the expense of tripping up some cautious clients.
Thank you for doing the legwork here- I should have been able to figure this out for myself, d'oh! At least it's here for posterity, since I think a number of users may run into this problem.
It looks like my usual practise of handling chip-select as a GPIO pin with RPi.GPIO might work well here, although I'm reasonably sure that the library works fine without this line in all cases.
As long as you don't have any devices that really want an active-high CS line then you should be fine.