doceme / py-spidev

MIT License
461 stars 203 forks source link

writebytes/readbytes broken? #19

Open JAEGER2K opened 9 years ago

JAEGER2K commented 9 years ago

I connected MISO and MOSI on my RaspberryPI and ran this program:

#!/usr/bin/env python
import spidev
def dmp(A):
    s = ""
    cnt = 0
    for a in A:
        s+="%0.2X " % a
        cnt=(cnt+1)%6
        if cnt == 0:
            s+="\n"
    print s

spi = spidev.SpiDev()
spi.open(0,0)
b = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD, 0xF0, 0x0D]
print "testing read/write bytes"
spi.writebytes(b)
dmp(spi.readbytes(len(b)))
print "testing xfer"
dmp(spi.xfer(b))
print "testing xfer2"
dmp(spi.xfer2(b))
spi.close()

The array b should be echoed, but instead there are only zeroes. I checked writebytes() with an oscilloscope and it seems like it doesn't send anything at all. But xfer and xfer2 work.

Or have I misunderstood writebytes? I thought it doesn't return anything, but keeps the data in a buffer which is accessable via readbytes.

some other interesting stuff:

$ uname -a
Linux raspberrypi 3.18.9+ #768 PREEMPT Sun Mar 15 18:59:03 GMT 2015 armv6l GNU/Linux
$ modinfo spi-bcm2708 
filename:       /lib/modules/3.18.9+/kernel/drivers/spi/spi-bcm2708.ko
alias:          platform:bcm2708_spi
license:        GPL v2
author:         Chris Boot <bootc@bootc.net>
description:    SPI controller driver for Broadcom BCM2708
srcversion:     4C511494EF4EBE6610ACDB6
alias:          of:N*T*Cbrcm,bcm2708-spi*
depends:        
intree:         Y
vermagic:       3.18.9+ preempt mod_unload modversions ARMv6 
jainakshay91 commented 8 years ago

I second this. Readbytes and writebytes do not seem to be working. Instead I am using xfer and xfer2.

Gadgetoid commented 8 years ago

Tested this on a Raspberry Pi 3, running Raspbian, Kernel 4.4.15 and Python 2.7.9.

Ran, simply:

from spidev import SpiDev
dev = SpiDev(0,0)
dev.writebytes([0,1,2,4,8,16,32,64,128])

Results were exactly as expected. 9 groups of clock pulses on my scope, with each bit asserted at the right time.

I used the repl to run the writebytes command and caught it in single-shot mode on my scope.

Same result sending: list(range(0,128)) - got the sequential list of numbers I expected.

Can you identify your Pi, by running:

cat /proc/cpuinfo | grep Revision

And I'll see if I can replicate on the same hardware.

I haven't tested readbytes yet.

JAEGER2K commented 8 years ago

Can you identify your Pi, by running:

Unfortunately I can't. At the time I posted this issue I've worked on a project for my university. Now it's finished and I don't have access to the hardware anymore. But maybe @jainakshay91 can help you.

dwhall commented 7 years ago

I believe I am seeing this issue. Hardware is a Raspberry Pi 3 Model B. Software is Raspbian Jessie w/Desktop 2017-06-21 straight from raspiberrypi.org. I'm using the spidev module built into the raspbian image; I don't know how old the module is. Spi enabled via sudo raspi-config, but only /dev/spi0.0 and /dev/spi0.1 are present. No /dev/spi1* devices. Loopback wire connecting Rpi's pins 19 to 21 (SPI0 MOSI to MISO).

$ uname -a
Linux KC4KSU-41 4.4.50-v7+ #970 SMP Mon Feb 20 19:18:29 GMT 2017 armv7l GNU/Linux

$ cat /proc/cpuinfo | grep Revision
Revision    : a22082

$ modinfo /lib/modules/4.4.50-v7+/kernel/drivers/spi/spi-bcm2835.ko 
filename:       /lib/modules/4.4.50-v7+/kernel/drivers/spi/spi-bcm2835.ko
license:        GPL v2
author:         Chris Boot <bootc@bootc.net>
description:    SPI controller driver for Broadcom BCM2835
srcversion:     64E8A93AAE8A9E8C014112F
alias:          of:N*T*Cbrcm,bcm2835-spi*
depends:        
intree:         Y
vermagic:       4.4.50-v7+ SMP mod_unload modversions ARMv7 

$ python3
Python 3.4.2 (default, Oct 19 2014, 13:31:11) 
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import spidev
>>> s = spidev.SpiDev(0,0)
>>> d = [0xaa,0x55,0xcc,0x33]
>>> s.xfer2(d)
[170, 85, 204, 51]
>>> s.xfer(d)
[170, 85, 204, 51]
>>> s.writebytes(d)
>>> s.readbytes(len(d))
[0, 0, 0, 0]

With a scope, I can see that the calls to xfer2(), xfer() and writebytes() all generate proper signals on the MOSI line. I get the same result using Python 2.7.9 (default, Sep 17 2016, 20:26:04) [GCC 4.9.2] on linux2

I see that the call to writebytes() generates a signal on MOSI that loops back to MISO. I expect that the data on MISO is then read into a hardware or software buffer and that readbytes() would convey the data from that buffer. Is this expectation wrong?

If there are instructions on how to build and install this module, please share and I'll retry using the latest source.

Other tidbit. I can call readbytes() with any reasonable non-zero value (1..512) and I get in return a list of that many zeros. I can call readbytes(100) repeatedly and get many 100-length lists of zeros, but there was no traffic on the SPI bus. I would expect some error reading from an empty queue.

aromanro commented 5 years ago

I just did the same check, with a loopback line between MOSI and MISO and got the same result for readbytes. xfer replicates the input as expected, but not writebytes/readbytes.

aromanro commented 5 years ago

I have more info on this, I played with the SPI driver more on Raspberry, the issue is originating from the driver itself. I wrote some C code that does something similar as the python lib and it seems that it's not the library's fault, it's the way the driver works.

semininja commented 5 years ago

I believe that writebytes() and readbytes() cannot be used with a loopback, because when you use the former, you'll write 8 bits of data without reading, which means MISO ignores the written bits; then, when you readbytes() after that, you have already stopped sending data on MOSI, so there's nothing to read but 0.

In other words, you'd need to have an external device, at least to act as a buffer, in order to test this properly. I believe this is not a bug, but an implementation/testing error.

semininja commented 5 years ago

To provide some more explanation, I believe that write/readbytes() are meant for one-way transfer; i.e. "write bytes and ignore response" and "read bytes without writing anything", while xfer/2() are meant for reading while writing.

LazloKovacs commented 3 years ago

It seems to be an issue on the second SPI bus on the pi4 using spidev. This code fails

from spidev import *

BUS = 0

BUS = 1 spi = SpiDev(BUS,0) spi.max_speed_hz = 1000000 spi.no_cs = True spi.mode = 1 contents = [6]

spi.xfer(contents)

spi.writebytes(contents)

while the other three combinations of BUS= 0/1 and xfer/writebytes work. My /boot/config.txt includes

dtparam=spi=on dtoverlay=spi1-3cs

LazloKovacs commented 3 years ago

Please ignore my last (too hasty) comment. I was correct with the observation that it's spi1 related, but not in my diagnosis. It seems to be an interaction between spi mode and the bus. On my system, both writebytes and xfer fail with xfer reporting "SystemError: <method 'xfer' of 'SpiDev' objects> returned a result with an error set",
both work for (1,0), (0,0), and (0,1).
Also fails in the same way for MODE =3 but not for MODE = 2, so its definitely phase-related. Here's my code:

Fails for both xfer and writebytes for BUS = 1 and MODE = 1, works for other

combinations.

from spidev import *

BUS = 1 MODE = 1 ComMethod = 'xfer' ComMethod = 'writebytes'

spi = SpiDev(BUS,0) spi.max_speed_hz = 1000000 spi.mode = MODE contents = [6] if ComMethod == 'xfer': spi.xfer(contents) else: spi.writebytes(contents)

Since this is not the problem reported, (differing behavior of xfer and either readbytes or writebytes), it may have nothing to do with the reported problem. Sorry for any confusion caused.