ChristophK
Posts: 15
Joined: Thu Oct 06, 2016 1:34 pm

pigpio aux-SPI strange bitorder

Fri May 12, 2017 11:37 am

Hi
I try to use the auxiliary SPI with pigpio for an Analog Devices 4*DAC AD5544. For each DAC it needs a SPI transmission of 18 bits, the first two for the DAC number, the rest are DAC-data. So i use the aux-SPI set to 18 bit (bits bbbbbb in spi_flags).
AuxSPI.jpg
AuxSPI.jpg (53.66 KiB) Viewed 986 times
AuxSPI2.jpg
different data
AuxSPI2.jpg (62.97 KiB) Viewed 973 times
It took me a lot of tries to find the correct bit order as shown here. I had to transmit 4 bytes and the last one is discarded (but influences the state of SDAT after the transmission). The two MSBs need to be the third byte's lowest bits.

I also tried with LSB first, but the order is as well a bit strange.

The pigpio documents don't tell me about this bit order.

User avatar
joan
Posts: 14688
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: pigpio aux-SPI strange bitorder

Fri May 12, 2017 1:44 pm

I hear you brother - it confuses the hell out of me too.

Are you saying there is a bug/error or is it a case of trying to improve the documentation?

If it's a documentation issue give me the words and I'll probably use them.

User avatar
joan
Posts: 14688
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: pigpio aux-SPI strange bitorder

Sat May 13, 2017 8:50 am

A test script.

The number of bytes sent per value is determined by the bit length (1 for <=8, 2 for <=16, 4 for <=32).

Multi-byte words are sent least significant byte first.

I'll add a note about byte order.

Code: Select all

#!/usr/bin/env python

import time
import pigpio

def spi_send(channel, bit_length, values):
   # transmit values to SPI channel with bit_length bits per value.

   assert 0 <= channel <= 2
   assert 1 <= bit_length <= 32

   flags = (bit_length)<<16 | 256 # set bit length and auxiliary

   h = pi.spi_open(channel, 50e3, flags)

   for v in values:
      if bit_length < 9:
         data = [v&255]
      elif bit_length < 17:
         data = [v&255, (v>>8)&255]
      else:
         data = [v&255, (v>>8)&255, (v>>16)&255, (v>>24)&255]
      pi.spi_write(h, data)

   pi.spi_close(h)

pi = pigpio.pi()
if not pi.connected:
   exit()

for bitlen in (1, 5, 8, 11, 16, 23, 24, 27, 32):
   # if the value has more bits than bitlen the excess will be lost
   spi_send(0, bitlen, [1, 10, 101, 1000, 10001, 100000, 1000001])

pi.stop()

ChristophK
Posts: 15
Joined: Thu Oct 06, 2016 1:34 pm

Re: pigpio aux-SPI strange bitorder

Mon May 15, 2017 6:42 am

I think, the main SPI is different here, it needs a most-significant byte first, aux-SPI LSByte first.
Let's take my second example, I want to transmit 18 bits (written as hex number:) 2aff5.
First I fill it with leading zeroes to 32 bit, 0002aff5.
For the main SPI this is transmitted with pi.spi_write(handle, b'\x00\x02\xaf\xf5')
but for the aux-SPI it is pi.spi_write(handle, b'\xf5\xaf\x02\x00')


Some month ago I wrote this "how-to":
The SPI-bus needs a "bytestring" as data, an integer number needs to be split into 8-bit parts.
To split a number into bytes there are some ways in Python:

Given a bytearray of hexadecimal digits (no leading 0x)
even number of digits necessary , Python 2 and 3
>>> import binascii
>>> x=b'12345678'
>>> binascii.unhexlify(x) - also possible: binascii.a2b_hex(x)
b'\x124Vx'
http://stackoverflow.com/questions/2340 ... ex/2340358:
I wonder why it's called "hexlify"
It was shorter than "hexlificationize" :^)

Given a bytearray of hexadecimal digits (no leading 0x)
even number of digits necessary , Python 2 and 3
depending from bit number: b16decode / b32decode / b64decode
>>> import base64
>>> x = b'12345678'
>>> base64.b16decode(x)
b'\x124Vx'

Given a textstring of hexadecimal digits (no leading 0x)
even number of digits necessary , Python 2 and 3
>>> import codecs
>>> codecs.decode("12345678", "hex")
b'\x124Vx'

Given a hex number (leading 0x, decimal or binary also possible)
no import necessary, number of digits don't care, not in Python2
>>> (0x12345678).to_bytes(4, byteorder='big')
b'\x124Vx'
If you use Python 3 only, this is my preferred way. Here you can also change the byteorder for aux-SPI !
https://docs.python.org/3/library/stdtypes.html
int.to_bytes(length, byteorder, *, signed=False) Return an array of bytes representing an integer.

All have in common that printing a bytestring to the screen produces "letter soup". Python prints all bytes that are printable ASCII characters as that character. Not printable characters are shown as hexadecimal number with leading "\x". But this is not important for the use of the SPI-Bus.
Transforming to the usual bytestring-look is done e.g. that way:
>>> x=b'\x31\x32\x33\x34\x35\x36\x37\x38'
>>> print(x)
b'12345678'
>>> print("".join("\\x%02x" % i for i in x))
\x31\x32\x33\x34\x35\x36\x37\x38
Last edited by ChristophK on Mon May 15, 2017 7:32 am, edited 1 time in total.

User avatar
joan
Posts: 14688
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: pigpio aux-SPI strange bitorder

Mon May 15, 2017 7:26 am

Remember the main SPI only permits 8 bit words (ignoring the 9-bit LOSSI which I don't want to understand). So the main SPI accepts bytes in the order you send which is outside pigpio's control.

The auxiliary SPI has a configurable word length of 1-32 bits. It's those you need to pack into 1/2/4 bytes according to bit length and then send in least significant byte order. That packing is decided by pigpio.

Return to “Python”