How do I read a register via spi?

For Adafruit customers who seek help with microcontrollers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
octopus
 
Posts: 2
Joined: Fri Feb 15, 2013 7:35 pm

How do I read a register via spi?

Post by octopus »

Here is my Python code so far:

from Adafruit_BBIO.SPI import SPI
spi = SPI(0,0)

My question is how do I read register 0x00? The device I am working with shoudl have 0x17 in that register. It is it's deviceID.

The docs for that device read:

"A read operation, defined as data going from the ADNS-
3080 to the micro-controller, is always initiated by the
micro-controller and consists of two bytes. The first byte
contains the address, is sent by the micro-controller over
MOSI, and has a “0” as its MSB to indicate data direction.
The second byte contains the data and is driven by the
ADNS-3080 over MISO. The sensor outputs MISO bits on
falling edges of SCLK and samples MOSI bits on every
rising edge of SCLK."

So, I figured I should be able to do this:

spi.writebytes([0x00])
val = spi.readbytes(1)

And then val should be 0x17, but that's not what I get. What should my code look like?

User avatar
tdicola
 
Posts: 1074
Joined: Thu Oct 17, 2013 9:11 pm

Re: How do I read a register via spi?

Post by tdicola »

Oh it sounds like you want to use the xfer2 (transfer) function from the library. The BBIO SPI support is actually a fork of the python spidev module and you can see a little summary of the functions it exposes here: http://tightdev.net/SpiDev_Doc.pdf With SPI there are basically 3 types of actions you can perform:
- Read, just reading bytes from the MISO pin
- Write, just writing bytes out the MOSI pin
- Transfer, both reading from MISO and writing to MOSI at the same time

Because you're trying to read and write in the same SPI 'call' (i.e. in the same transaction where the device's CS/chip select pin is enabled) you want to use the transfer function. If you used a write and then read it actually turns into to two separate SPI transactions where the CS pin is enabled and disabled between them. For some devices you don't want that behavior and instead need the CS pin to stay enabled during the write and read, that's where the transfer function comes in handy.

One thing to note is that there are actually two transfer functions, xfer and xfer2. The linked PDF mentions the difference is with how the CS pin acts. With xfer it disables and enables the CS pin after sending/receiving each byte, whereas with xfer2 it just keeps the CS pin enabled the entire time bytes are read and written. Most devices expect behavior like xfer2, but check the datasheet and its SPI / timing diagrams to see if they show the CS pin being disabled after every byte.

So ultimately you want to switch your code to look something like:

Code: Select all

from Adafruit_BBIO.SPI import SPI
spi = SPI(0,0)

// Transfer 0x00, 0x00.  The first 0x00 is the register to read and the second
// 0x00 is a dummy byte that pads out the length of the transfer to 2 bytes in length.
result = spi.xfer2([0x00, 0x00]) 
// The result of the transfer will be an array of 2 bytes where the first byte is what
// was read while the first byte was written and the second byte is what was read
// while the second byte was written.  We care about the second byte since that's
// where the chip's response after it sees the first byte will be.
val = result[1]

octopus
 
Posts: 2
Joined: Fri Feb 15, 2013 7:35 pm

Re: How do I read a register via spi?

Post by octopus »

Thanks for this excellent information. That leaped a hurdle for me. Tonight I am miles ahead of where I was last night.

User avatar
tdicola
 
Posts: 1074
Joined: Thu Oct 17, 2013 9:11 pm

Re: How do I read a register via spi?

Post by tdicola »

No problem, glad I could help and good luck with the project!

User avatar
hari_cet
 
Posts: 2
Joined: Sun Sep 20, 2015 9:45 am

Re: How do I read a register via spi?

Post by hari_cet »

Hello
How to read a 16 bit register using xfer2 command

I have a register with 16 bit address.

the command i used is
value=spi.xfer2([0x43,0x31]) as theaddress of my register is 0x43C1.

The output value is 32 bit

Help in sorting out the problem is highly appreciated
thanks

User avatar
tdicola
 
Posts: 1074
Joined: Thu Oct 17, 2013 9:11 pm

Re: How do I read a register via spi?

Post by tdicola »

Ah, yeah Python can be a little tricky since it doesn't have explicit 16 bit number types. If you're sending a 16-bit address (0x43C1) and then expect to read 16-bits you actually want to add two zero bytes to the xfer2 command. That will twiddle the SPI clock lines, etc. to read the 16-bit response after sending the 16-bit address. So do something like:

Code: Select all

value=spi.xfer2([0x43,0x31,0x00,0x00])
Then the response should be 4 bytes long and the last 2 are your 16-bit response. You can grab these and assemble them into an unsigned 16-bit value by doing (assuming the high order byte comes first and low order byte comes second, i.e. big endian byte order):

Code: Select all

low_byte = value[2] & 0xFF
high_byte = value[3] & 0xFF
result = high_byte << 8 & low_byte
The '& 0xFF' is the trick to help ensure python interprets the value as an 8-bit unsigned type instead of some arbitrarily long signed value. It's basically chopping off all other data beyond the 8 bits we care about and ignoring any negative value sign extension, etc. You can do this to turn any Python number into an unsigned value of a specific length, so a 16-bit unsigned value would be & 0xFFFF. Hope that helps, thanks!

User avatar
hari_cet
 
Posts: 2
Joined: Sun Sep 20, 2015 9:45 am

Re: How do I read a register via spi?

Post by hari_cet »

Thank you very much.

Locked
Please be positive and constructive with your questions and comments.

Return to “Microcontrollers”