doceme / py-spidev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SPI mode won't change in program

aronfeher opened this issue · comments

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.

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.

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.

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.

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$

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:

py-spidev/spidev_module.c

Lines 1035 to 1036 in a5d82b8

// clean and set CPHA and CPOL bits
tmp = ( self->mode & ~(SPI_CPHA | SPI_CPOL) ) | mode ;

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

if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) {

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)

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.

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.