user space i2c driver for adxl345 with BBB

Before I start, lets see two useless things.
This post is not about learning but how checking if adxl chip works.


My ADXL345 chip schematic



This is the chip


Why I use this, because I searched beforehand for which accelerometer chip I will have lots of tutorials on internet.
After I am able to check if the chip works, I will go for device tree overlay to make it work on boot.
Below is bad and useless code which I thought is useful.



/*
 * Simple I2C example
 *
 * Copyright 2017 Joel Stanley <joel@jms.id.au>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <err.h>
#include <errno.h>

#include <linux/types.h>
//#include <linux/i2c.h>
#include "/usr/include/linux/i2c-dev.h"

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define STEP 0.00390625
#define CHIP_ADDR 0x53   //ADXL chip address

#define DATAX0  0x32
#define DATAX1  0x33
#define DATAY0  0x34
#define DATAY1  0x35
#define DATAZ0  0x36
#define DATAZ1  0x37

/*static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command,
                                     int size, union i2c_smbus_data *data)
{
struct i2c_smbus_ioctl_data args;

args.read_write = read_write;
args.command = command;
args.size = size;
args.data = data;
return ioctl(file,I2C_SMBUS,&args);
}*/


/*static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
{
union i2c_smbus_data data;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
                     I2C_SMBUS_BYTE_DATA,&data))
return -1;
else
            return 0x0FF & data.byte;
        
}*/

int main(int argc, char **argv)
{
uint8_t data[2], addr = CHIP_ADDR, reg = 0x36;
        int16_t x, y, z;
        float g;
const char *path = (char*)"/dev/i2c-2";
int file, rc;
file = open(path, O_RDWR);
if (file < 0)
err(errno, "Tried to open '%s'", path); 

rc = ioctl(file, I2C_SLAVE, addr);
if (rc < 0)
err(errno, "Tried to set device address '0x%02x'", addr);

       rc = i2c_smbus_write_byte_data(file, 0x2D, 0);
       printf("rc1=%d\n",rc);
       rc = i2c_smbus_write_byte_data(file, 0x2D, 16);
       printf("rc2=%d\n",rc);
       rc = i2c_smbus_write_byte_data(file, 0x2D, 8);
       printf("rc3=%d\n",rc);
        while (1){

data[0] = i2c_smbus_read_byte_data(file, DATAX0);
data[1] = i2c_smbus_read_byte_data(file, DATAX1);
x = data[0] | (data[1]<<8);
printf("x = %04x %d ",x, x); 
g = x * STEP;
printf("x = %fg,", g);
     
data[0] = i2c_smbus_read_byte_data(file, DATAY0);
data[1] = i2c_smbus_read_byte_data(file, DATAY1);
y = data[0] | (data[1]<<8);
printf("y = %04x %d ",y, y); 
g = y * STEP;
printf("y = %fg ,", g);

data[0] = i2c_smbus_read_byte_data(file, DATAZ0);
data[1] = i2c_smbus_read_byte_data(file, DATAZ1);
z = data[0] | (data[1]<<8);
printf("z = %04x %d ",z, z); 
g = z * STEP;
printf("z = %fg", g);
       
sleep(2);
printf("\n\n");
       }

}

This is the C code. I found it in i2c-tools files and modified a little .
Flash any debian image in SD card. Why? Just because you will get to use sudo apt-get thing in these pre installed.

'opkg' is also there but seriously why in the hell we want to use that?Its just a hassle. So better use debian.

put this file in
/home/debian/Desktop

gcc adxl345app.c
./a.out

done.

Some notes to see
to detect i2c device

This will search for i2c devices connected on i2c2

i2cdetect -y -r 2/1/0

if this works than you will get some output like this,

root@arm:~# i2cdetect -y -r 2
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- 53 UU UU UU UU -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         

root@arm:~# 

After that try this command and match default register values from data sheet,

i2cdump -y 2 0x53

root@arm:~# i2cdump -y 2 0x53
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: e5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4a    ?..............J
10: 00 00 10 00 00 00 00 00 00 00 00 ff 00 00 00 00    ..?.............
20: 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 00    ............?...
30: 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............
40: e5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4a    ?..............J
50: 00 00 10 00 00 00 00 00 00 00 00 ff 00 00 00 00    ..?.............
60: 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 00    ............?...
70: 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............
80: e5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4a    ?..............J
90: 00 00 10 00 00 00 00 00 00 00 00 ff 00 00 00 00    ..?.............
a0: 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 00    ............?...
b0: 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............
c0: e5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4a    ?..............J
d0: 00 00 10 00 00 00 00 00 00 00 00 ff 00 00 00 00    ..?.............
e0: 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 00    ............?...
f0: 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............

root@arm:~# 

I can match at 0x00 default data is 0xef. So proven that device is responding and chip is not malfunctioned. Its helpful becuase most of the time we do not have oscilloscope or even multimeter(not recommended to not have a multimeter though), so these commands can tell if the chip that you bought, works.


echo adxl345_i2c 0x53 > /sys/bus/i2c/devices/i2c-2/new_device
check dmesg
to on adxl345

sudo i2cset -y 2 0x53 0x2d 0x00
sudo i2cset -y 2 0x53 0x2d 16
sudo i2cset -y 2 0x53 0x2d 8

x data
sudo i2cget -y 2 0x53 0x32


writeTo(DEVICE, 0x2D, 0);      
writeTo(DEVICE, 0x2D, 16);
writeTo(DEVICE, 0x2D, 8);

data understanding.
int x = data[0] | (((int)data[1])<<8);
int y = data[2] | (((int)data[3])<<8);
int z = data[4] | (((int)data[5])<<8);


by default resolution is 10 bit
in 2g mode the full range is 4
data resolution is 10 bit on reset.
so 2^10 = 1024
1 step = total range / total data
       = 4/1024
       = 0.00390625

so any value inx, y, z will be multiplied with 0.00390625 to get value in g in 2g mode.Similarly for other 4g, 8g, and 16g modes we can calculate.
E.g.
we get data from DATAZ0 = 0xDF = 223
223 * 0.00390625 = 0.87109375 g


Also try this python script

first install

sudo apt-get install python-smbus 

then take code from

https://github.com/pimoroni/adxl345-python/blob/master/adxl345.py

just change the i2c bus as you are connected to 0, 1 or 2 and the script should work.
bus = smbus.SMBus(1 if int(revision, 16) >= 4 else 0)



https://www.youtube.com/watch?v=usVeVb9FWoQ

https://www.youtube.com/watch?v=_NjQ6m3ZbEo

These videos are made after using above steps.





Comments

Popular posts from this blog

dev_get_platdata understanding

Getting started with pinctrl subsystem linux

How to take systrace in android