How to read the accelerometer ADXL345 data via SPI using Python code and spidev libraries

I have successfully loaded overlays and tested ports using Derek Molloy’s spidev_test.c. Devices spidev1.0, 1.1, 2.0 and 2.1 are working fine. Then I connected my accelerometer on pins 1, 3, 28, 29, 30, 31. I tried using the slightly modified Python code I found on http://www.havnemark.dk/?p=148 ('Read the ADXL345 accelerometer with Raspberry Pi, using SPI bus’) and the code is not working properly. Code will be posted below.

On the other hand, I was able to connect device on I2C port and read the data without any problem. And I think I got an idea how I2C work, and idea goes like this (correct me if I am wrong): device is connected on bus and has its address (in case of ADXL345 address of device for I2C is 0x53 or 0x1d, in my case address was 0x1d). Then you access this address to open the register. This register has 64 bytes in this case, every byte has its position going from 0x00 to 0x3f. To be able to control device we write bytes to setup the device and then we read the bytes to get data from sensor. In this case accelerations are stored in 6 bytes, in pairs of two for each axis because resolution of accelerometer is 10 or 13 bits which means we need minimum of two bytes. Consequently 6 or 3 bytes don’t mean anything. And then when I have values of these bytes I can combine them, do some operations and translate these values in voltage and finally translate the voltage in acceleration.

I have following questions about SPI:

  1. How to read the register using the spidev package (https://github.com/doceme/py-spidev)? Main problem is I really don’t get how the communication goes. I am familiar with concept “to read data you have to send the data” but I don’t know how to make the code that would do that. In other words, how would piece of Python code that says “Go to address XxXX and read the register values at position YxYY” look like?

  2. Using the code from question 1 - how to access the accelerometer and read the device ID which is in register positioned at 0x00?

  3. How to write the data to register? In other words how would piece of Python code that says “Go to address XxXX and write the value ZxZZ to register at position YxYY” look like.

  4. Using the code from question 3 - how to put the accelerometer in measuring mode by writing the value 0x08 to register at position 0x2d

Code I used:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Example on how to read the ADXL345 accelerometer.
# Kim H. Rasmussen, 2014
import time
import spidev

# Setup SPI
spi = spidev.SpiDev()
#spi.mode = 3    <-- Important: Do not do this! Or SPI won't work as intended, or even at all.
spi.open(2,0)
spi.mode = 3 
spi.max_speed_hz = 3500000 
# Read the Device ID (should be xE5)
id = spi.xfer2([128,0])
print 'Device ID (Should be 0xE5):\n'+str(hex(id[1])) + '\n'

# Read the offsets
xoffset = spi.xfer2([30 | 128,0])
yoffset = spi.xfer2([31 | 128,0])
zoffset = spi.xfer2([32 | 128,0])
print 'Offsets: '
print xoffset[1]
print yoffset[1]
print str(zoffset[1]) + "\n\nRead the ADXL345 every half second:"

# Initialize the ADXL345
def initadxl345():
    # Enter power saving state
    spi.xfer2([45, 0])

    # Set data rate to 100 Hz
    spi.xfer2([44, 10])

    # Enable full range (10 bits resolution) and +/- 16g 4 LSB
    spi.xfer2([49, 16])

    # Enable measurement
    spi.xfer2([45, 8])

# Read the ADXL x-y-z axia
def readadxl345():
    rx = spi.xfer2([242,0,0,0,0,0,0])

On Wed, 21 Jun 2017 01:05:18 -0700 (PDT),
zvonimir.maranic@gmail.com declaimed the
following:

This code is not working. First problem is that line

id = spi.xfer2([128,0])

returns 0xf2. If 128 is replaced with 64 I get 0x79. If 128 is replaced
with 0 I get 0xe5. I cannot debug this because I don't know what exactly
this line does. By answering questions above, you would help me a lot.

  Per the data sheet (page 16, figure 38 -- presuming you wired for
4-wire mode) that defines a single byte read operation at address 0, with
dummy output data of 0 (as the input has to be clocked from it).

  >1|0|00000 00000000
   > > > >data
   > > >address (register)
   > >single byte (1 = multiple byte)
   >read (ignore sent data) (0 = write data to register)

  Also (page 23 table 19) address 0 is DEVID, which is read-only and has
the value 11100101 (0xe5)

0xf2 => 11110010
0x79 => 01111001
0xe5 => 11100101

I'd say there is some sort of timing problem somewhere in that system (0x64
should be a multibyte WRITE operation, 0x00 is a single byte write). Note
that the other values you see are bit-shifted to the right with an
additional leading 1 bit (one bit shift, and two bit shift).

  I've not encountered "spidev" module before. Have you tried the
Adafruit_BBIO module?

# Setup SPI
spi = spidev.SpiDev()
#spi.mode = 3 <-- Important: Do not do this! Or SPI won't work as intended, or even at all.

  Interesting -- this line is commented out, yet...

spi.open(2,0)
spi.mode = 3

... after opening the device, they then set the same mode that was just
warned against.

  Page 4890 of the TRM describes the four values for mode, and it does
seem to match page 15 of the data sheet...

  Given the apparent bit-shifts described above, you might try reducing
the clock speed from 3.5MHz... And making sure you have similar wire runs
for clock, data-out, data-in, with similar capacitances -- since the data
shift described above could be a matter of being out of sync with the clock
vs data lines.