How to connect ADXL345 accelerometer via SPI to BBB using Python

508 views
Skip to first unread message

MrVragilije

unread,
Jun 21, 2017, 8:12:15 PM6/21/17
to BeagleBoard
Hi guys,

My accelerometer is connected to spidev2.0 (pins 1, 3, 28, 29, 30, 31). Overlays are loaded correctly, HDMI is turned off, ports are tested using Molloy's spidev_test.c and to this point things are good.I have a problem with reading the data from accelerometer ADXL345 via SPI port using Python code I found on http://www.havnemark.dk/?p=148 ('Read the ADXL345 accelerometer with Raspberry Pi, using SPI bus'). Main problem is that I don't know how to use spidev Python library and I am not sure how SPI communication goes, although I am aware of the SPI principle thats says "if you want to send the data to read the data". It would be much easier for me if you can explain me what and how to send and how to read data.


I successfully connected sensor via I2C port and was able to read the accelerations. Everything worked perfectly and I get the idea behind I2C, which goes like this (please correct me if I am wrong): Device has its address (ADXL345 has 0x53 or 0x1d, it was 0x1d in my case). First, by going to address you go to a register which has 64 bytes. In register every byte is used for controlling sensor or for storing data that sensor acquires. Every one of these bytes has its position from 0x00 to 0x3f, and some values are stored in these bytes. For example, device ID is stored in byte at position 0x00, and value of device ID is always 0xe5. On the other hand at position 0x2d we can turn on or turn off accelerometar by writing a desired value to this byte, value of 0x08 will set the accelerometar in measurement mode. And then we need to read bytes from position 0x32 to position 0x37 to read the accelerations. For every axis (X, Y, Z) value of acceleration is stored in 2 bytes (because we have resoultions of 10 or 13 bits. After reading these bytes we combine values to get voltage and after that by using some math we can get accelerations in m/s^2 or g's or whatever we like. 

And I know that I must to do similar things when communicating via SPI but I don't know how to read or write the register values. So my questions are:

1) How to read the register data using spidev package. How would line of code that says "Go to address XxXX and read the value at the position YxYY" look like?

2) By using code from question 1 how would line that returns device ID look like.

3) How to write the data to the register? How would line of code that says "Go to address XxXX and write the value ZxZZ at the position YxYY" look like?

4) By using code from question 3 how to set the accelerometer in the measurement mode

5) How to combine bytes where the values of accelerations are stored? For example if I have 10 bit resolution I would have to combine first byte with last two bits of second byte. Then by multiplying the value of combination of bytes with 3.3 and then dividing with 1024 I would get a voltage. And then by knowing the range of measurement I can translate that in acceleration. How to do whole proccess?

Here is the 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])

    # 
    out = [rx[1] | (rx[2] << 8),rx[3] | (rx[4] << 8),rx[5] | (rx[6] << 8)]
    # Format x-axis
    if (out[0] & (1<<16 - 1 )):
        out[0] = out[0] - (1<<16)
    out[0] = out[0] * 0.004 * 9.82
    # Format y-axis
    if (out[1] & (1<<16 - 1 )):
        out[1] = out[1] - (1<<16)
    out[1] = out[1] * 0.004 * 9.82
    # Format z-axis
    if (out[2] & (1<<16 - 1 )):
        out[2] = out[2] - (1<<16)
    out[2] = out[2] * 0.004 * 9.82

    return out

# Initialize the ADXL345 accelerometer
initadxl345()

# Read the ADXL345 every half second
timeout = 0.5
while(1):
    axia = readadxl345()
    # Print the reading
    print axia[0]
    print axia[1]
    print str(axia[2]) + '\n'

    elapsed = time.clock()
    current = 0
    while(current < timeout):
        current = time.clock() - elapsed
Things go wrong from the very beginning: 
# Read the Device ID (should be xE5)
id = spi.xfer2([128,0])
print 'Device ID (Should be 0xE5):\n'+str(hex(id[1])) + '\n'
This line returns me device ID id[1] = 0xf2, and I am confused. Also I don't know how this xfer2 works, and why is there 128 (0x80).
By looking at the Arduino libraries for ADXL345 it seems to me like that is the address of device and I don't know how was this number obtained.
Also I think that the guy whose code this is made a mistake in function initadxl345(). 10 bit is not full resolution of device, it is 13 bit and 13 bit resolution is available only in +-16g mode. 
To turn that mode on value in register at the position 0x31 should be bin 00001011 = dec 11 = hex 0x0b. 
I bet there are also mistakes I am not fully aware of.
Please help me in answering questions above, it would help me a lot.

Reply all
Reply to author
Forward
0 new messages