Comments (5)
And, finally, the reason why this throws an error at all is that lsbfirst = True
may be unsupported on the Raspberry Pi. If you need to reverse your bit order, you'll have to do it in software.
from py-spidev.
I'm a little late to the party, but I've just duplicated your test script and am getting exactly the same results.
Suffice to say, I'm a little baffled- BCM 23 has nothing to do with SPI. However, lsbfirst
is implemented with setters/getters so it has side-effects.
Here's the setter:
static int
SpiDev_set_lsbfirst(SpiDevObject *self, PyObject *val, void *closure)
{
uint8_t tmp;
if (val == NULL) {
PyErr_SetString(PyExc_TypeError,
"Cannot delete attribute");
return -1;
}
else if (!PyBool_Check(val)) {
PyErr_SetString(PyExc_TypeError,
"The lsbfirst attribute must be boolean");
return -1;
}
if (val == Py_True)
tmp = self->mode | SPI_LSB_FIRST;
else
tmp = self->mode & ~SPI_LSB_FIRST;
__spidev_set_mode(self->fd, tmp);
self->mode = tmp;
return 0;
}
which calls:
static int __spidev_set_mode( int fd, __u8 mode) {
__u8 test;
if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) {
PyErr_SetFromErrno(PyExc_IOError);
return -1;
}
if (ioctl(fd, SPI_IOC_RD_MODE, &test) == -1) {
PyErr_SetFromErrno(PyExc_IOError);
return -1;
}
if (test != mode) {
return -1;
}
return 0;
}
But why the SPI_IOC_WR_MODE
or SPI_IOC_RD_MODE
ioctls called on the SPI device should have any effect on GPIO is beyond me. This might be an issue to raise against RPi.GPIO too.
from py-spidev.
Okay, this is a good one!
Here's a puzzler for you. Modify your original code example to:
import time
import RPi.GPIO as GPIO
import spidev
spi = spidev.SpiDev()
spi.open(0, 0)
spi.lsbfirst = True
# Initialize GPIO23 as an output.
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
try:
GPIO.setup(23, GPIO.OUT)
except IOError:
pass
GPIO.setup(23, GPIO.OUT)
# Set GPIO23 high and then low.
print 'High'
GPIO.output(23, GPIO.HIGH)
time.sleep(1)
print 'Low'
GPIO.output(23, GPIO.LOW)
time.sleep(1)
print 'Done!'
And see if you can figure out why that works :D
from py-spidev.
Welp! Down the rabbit hole I went. The issue is this;
lsbfirst = True
triggersset_lsbfirst
- This calls
__spidev_set_mode
__spidev_set_mode
calls ioctl which fails with[Errno 22] Invalid Argument
and passes this to Python withPyErr_SetFromErrno
- Back to
set_lsbfirst
which somehow exits without the previously set PyErr being raised - Now we have an error buried in Python which hasn't been raised...
- Along comes RPi.GPIO... for some reason
GPIO.setwarnings
andGPIO.setmode
ignore this buried error - But now
GPIO.setup(23, GPIO.OUT)
digs up the error set by__spidev_set_mode
and raises it... WHY!? I don't even...
Note about point 6. setwarnings
bails with Py_RETURN_NONE
so why it takes until setup
for the error to be raised is anyone's guess. This stuff is bonkers!
I've rewritten a substantial portion of the code to check the return value of __spidev_set_mode
and use Py_RETURN_NONE
which seems to trigger error handling- whereas return NULL
or return 0
do not.
This is odd, because according to https://docs.python.org/3/extending/extending.html#intermezzo-errors-and-exceptions return NULL
should cause Python to choke and raise the exception, whereas Py_RETURN_NONE
should do.. ?
With the setter and getter functions defined as static PyObject *
. return NULL
not only doesn't raise an exception set by PyErr_SetFromErrno
but leaves that error latent in the interpreter:
Exceptions are stored in a static global variable inside the interpreter
For the next method that uses Py_RETURN_NONE
to inadvertently raise.
D'oh =/
I've pushed these "fixes" (I'm not 100% sure what I'm doing is correct) into a new branch on my fork for some testing and peer overview before I submit a PR:
from py-spidev.
After bashing my head against this problem for some time, I determined I'd made a mistake in changing the setters from static int
to PyObject *
in my original tweaks.
Despite the overwhelming majority of documentation pointing toward returning Py_NONE ( or a value ) upon success, and NULL upon error and using the PyObject type for functions that communicate with Python, a setter is a special little snowflake which, presumably, is called by some internal glue logic and must return 0 upon success, and -1 upon error.
This is alluded to only in its definition: typedef int (*setter)(PyObject *, PyObject *, void *);
and I couldn't find any good examples or documentation for setters anywhere- it must be too generic a search term, and my search-fu has failed me.
Anyway, with my latest commit I have reverted my fudge and now only check __spidev_set_mode
for a -1 return code, and bubble this up accordingly:
if (__spidev_set_mode(self->fd, tmp) == -1){
return -1;;
}
As simple as that.
https://github.com/Gadgetoid/py-spidev/tree/ErrorHandling
from py-spidev.
Related Issues (20)
- Reading from SPI 0.0 is always zero HOT 3
- CS line double pulsing HOT 3
- spurious low pulse on CS0 HOT 28
- SPI CE0 bounce problem HOT 1
- after close and recreate got Bad file decriptor HOT 1
- The CS_HIGH handling code triggers a lockup on Raspberry Pi in 5.10 HOT 3
- [RPi 4] Spurious CS pulse after transfer HOT 3
- Type interface to writebytes not clear HOT 1
- RX buffer overwrites the TX buffer in 'xfer2' HOT 2
- "xfer2"/"xfer" command erases slave data / slave is unable to respond HOT 6
- support for python 3.9.4 HOT 1
- Please tag 3.5 version
- Unexpected SCK behavior
- Installation Python Spidev fails on Alpine Linux aarch64 HOT 3
- How to define a GPIO pin of Raspberry Pi while I'm using spidev lib? HOT 1
- Install failing on macos [missing linux/spi/spidev.h] HOT 1
- Supporting with-statements
- The open() method is not well suited to hot-plugged SPI device controllers (e.g. USB, Thunderbolt, PCIe and similar situations). HOT 2
- Could not build wheels for spidev HOT 2
- Quad and Dual format support for Synopsys Enhanced SPI controllers
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from py-spidev.