doceme / py-spidev

MIT License
459 stars 205 forks source link

SPI mode won't change in program #105

Closed aronfeher closed 1 year ago

aronfeher commented 4 years ago

Hi py-spidev team!

I want to interface a Banana PI M2 Zero with an ADS1294 IC. This IC requires an SPI communication with MODE = 1, but changing the settings in python won't take effect (SPI remains in MODE = 3). Maybe it's something trivial, but so far I couldn't figure out what am I doing wrong, or where is the problem.

I'm using Jupyter Notebook with the following code snippet:

class ads129x:
    def __init__(self, num=0, dev=0, max_speed=2000000, mode=0b01, msbfirst=True):
        self.spi = spidev.SpiDev()
        self.spi.open(num,dev)
        self.spi.max_speed_hz = 2000000
        self.spi.mode = mode
        self.spi.lsbfirst = not msbfirst

    def ads_wreg(self, reg, val):
        self.spi.xfer2([(spi_command["wreg"] | reg), 0, val]) 

    def ads_rreg(self, reg):
        ret = self.spi.xfer2([(spi_command["rreg"] | reg), 0x00, 0x00])  
        return ret[2]
        #return ret

    def ads_send_cmd(self, cmd):
        self.spi.xfer2([cmd])

    def close(self):
        self.spi.close()

if __name__ == "__main__":
    print("This is main")
    x = ads129x()
    x.ads_send_cmd(spi_command["sdatac"])
    name = x.ads_rreg(reg_vals["id"])
    print(name)
    x.close()

Regardless of the settings the result is the same, shown in the image below. Untitled-1

Any help would be appreciated.

aronfeher commented 4 years ago

One more thing that I've tried is the speed. I can change the clock speed, but I can't figure out why won't the polarity change.

aronfeher commented 4 years ago

Ok. So I've managed to make the CPOL work somewhat, but there is an initial pulse which confuses the slave. Is this the normal operation mode for the SPI in SPIDEV? In any other MCU the initial pulse is not present, and everything works just fine. mode1 mode1_arduino The first image shows the mode 1 transfer on the BPI, while the second image shows the transfer on an Arduino nano.

Gadgetoid commented 4 years ago

py-spidev doesn't really do anything but throw ioctls at the kernel and hope for the best. It may be that the underlying hardware/device drivers are the root of your problem.

Ideally you should throw out py-spidev temporarily and try accessing things more directly to elminate this library from the equation.

There's a tool in the Linux kernel source tree for diagnosing things like this: https://github.com/raspberrypi/linux/blob/rpi-5.4.y/tools/spi/spidev_test.c

You should build/run this tool with the settings your aiming for, and confirm if it meets your expectations.

If this works as per your expectations, then we at least have a good idea there's a problem in this library rather than anywhere else.

aronfeher commented 4 years ago

Hi! I've built the tool, and made an external loop-back. It is working fine.

ubuntu@bpi-m2z:~/Projects/CPP$ ./spidev_test.o --device /dev/spidev0.0 -s 1000000 -b 8  -H -v
spi mode: 0x1
bits per word: 8
max speed: 1000000 Hz (1000 KHz)
TX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D  |......@.........................|
RX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D  |......@.........................|
ubuntu@bpi-m2z:~/Projects/CPP$
Gadgetoid commented 4 years ago

You may need to be more thorough than that- since if the mode isn't changing then a loopback test would presumably work either way.

Looking over the spidev_module.c code I can't see anything that would cause the mode to be set incorrectly:

https://github.com/doceme/py-spidev/blob/a5d82b88bd1c95c9f9ec46e9f7afe08c3323e625/spidev_module.c#L1035-L1036

The specific line for setting mode closely mirrors the spidev_test.c, though it uses the byte-mode rather than 32bit mode:

https://github.com/doceme/py-spidev/blob/a5d82b88bd1c95c9f9ec46e9f7afe08c3323e625/spidev_module.c#L896

vs:

ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);

I'm really no expert on this stuff- just a frequent user of the library who has fumbled his way through some minor contributions here- but my point is that py_spidev is just a thin wrapper around SPI ioctls and while it's far from perfect, I struggle to identify how it could cause the problems you're describing.

If I were you- my next step would be to hack on spidev_test.c to try and get some pure-C code communicating with your device. If you still see the same weirdness then produce a minimum viable test example and push that upstream to whoever at Banana Pi has any ability to fix/understand this.

Maybe I can tempt you over to the nice cozy world of Raspberry Pi? (not that we aren't having our own quirks with SPI right now)

aronfeher commented 4 years ago

Thanks for the quick reply. I'll try the pure C version, maybe I have some luck.

My only problem with RPi so far was that when I wanted to buy the RPi zero it was always out of stock, and that was when I purchased the BPi zero, and got stuck with it. If push comes to shove, I could put an intermediary IC (some Atmel/Microchip, or Lattice MachX02 FPGA) to handle the bare-bone stuf, like the data acquisition and the filtering, and implement a slave SPI module in them with mode3, that way it should work, but in the long run that would be overkill/unnecessary in my opinion.

Either way, I'll edit this comment when I test my setup with C.

Gadgetoid commented 4 years ago

Yeah Pi Zero availability can be hit and miss. FWIW we have stock of both the Pi Zero and Pi Zero W at the moment, but in all cases they are still limited to 1-unit per order, which is a pain if you need a couple for a project.

I don't get much exposure to boards other than the Pi these days, so I don't have any great ideas. Would be a shame to need an intermediate ic just to get sensible SPI communications though.