1/*
2 * Author: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
3 * Copyright (c) 2014 Intel Corporation.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include <iostream>
26#include <string>
27#include <stdexcept>
28#include <unistd.h>
29#include "math.h"
30#include "adxl345.h"
31
32#define READ_BUFFER_LENGTH 6
33
34//address and id
35#define ADXL345_I2C_ADDR 0x53
36#define ADXL345_ID 0x00
37
38//control registers
39#define ADXL345_OFSX 0x1E
40#define ADXL345_OFSY 0x1F
41#define ADXL345_OFSZ 0x20
42#define ADXL345_TAP_THRESH 0x1D
43#define ADXL345_TAP_DUR 0x21
44#define ADXL345_TAP_LATENCY 0x22
45#define ADXL345_ACT_THRESH 0x24
46#define ADXL345_INACT_THRESH 0x25
47#define ADXL345_INACT_TIME 0x26
48#define ADXL345_INACT_ACT_CTL 0x27
49#define ADXL345_FALL_THRESH 0x28
50#define ADXL345_FALL_TIME 0x29
51#define ADXL345_TAP_AXES 0x2A
52#define ADXL345_ACT_TAP_STATUS 0x2B
53
54//interrupt registers
55#define ADXL345_INT_ENABLE 0x2E
56#define ADXL345_INT_MAP 0x2F
57#define ADXL345_INT_SOURCE 0x30
58
59//data registers (read only)
60#define ADXL345_XOUT_L 0x32
61#define ADXL345_XOUT_H 0x33
62#define ADXL345_YOUT_L 0x34
63#define ADXL345_YOUT_H 0x35
64#define ADXL345_ZOUT_L 0x36
65#define ADXL345_ZOUT_H 0x37
66#define DATA_REG_SIZE 6
67
68//data and power management
69#define ADXL345_BW_RATE 0x2C
70#define ADXL345_POWER_CTL 0x2D
71#define ADXL345_DATA_FORMAT 0x31
72#define ADXL345_FIFO_CTL 0x38
73#define ADXL345_FIFO_STATUS 0x39
74
75//useful values
76#define ADXL345_POWER_ON 0x08
77#define ADXL345_AUTO_SLP 0x30
78#define ADXL345_STANDBY 0x00
79
80//scales and resolution
81#define ADXL345_FULL_RES 0x08
82#define ADXL345_10BIT 0x00
83#define ADXL345_2G 0x00
84#define ADXL345_4G 0x01
85#define ADXL345_8G 0x02
86#define ADXL345_16G 0x03
87
88using namespace upm;
89
90Adxl345::Adxl345(int bus) : m_i2c(bus)
91{
92    //init bus and reset chip
93    if ( m_i2c.address(ADXL345_I2C_ADDR) != mraa::SUCCESS ){
94        throw std::invalid_argument(std::string(__FUNCTION__) +
95                                    ": i2c.address() failed");
96        return;
97    }
98
99    m_buffer[0] = ADXL345_POWER_CTL;
100    m_buffer[1] = ADXL345_POWER_ON;
101    if( m_i2c.write(m_buffer, 2) != mraa::SUCCESS){
102        throw std::runtime_error(std::string(__FUNCTION__) +
103                                    ": i2c.write() control register failed");
104        return;
105    }
106
107    if ( m_i2c.address(ADXL345_I2C_ADDR) != mraa::SUCCESS ){
108        throw std::invalid_argument(std::string(__FUNCTION__) +
109                                    ": i2c.address() failed");
110        return;
111    }
112
113    m_buffer[0] = ADXL345_DATA_FORMAT;
114    m_buffer[1] = ADXL345_16G | ADXL345_FULL_RES;
115    if( m_i2c.write(m_buffer, 2) != mraa::SUCCESS){
116        throw std::runtime_error(std::string(__FUNCTION__) +
117                                    ": i2c.write() mode register failed");
118        return;
119    }
120
121    //2.5V sensitivity is 256 LSB/g = 0.00390625 g/bit
122    //3.3V x and y sensitivity is 265 LSB/g = 0.003773584 g/bit, z is the same
123
124    m_offsets[0] = 0.003773584;
125    m_offsets[1] = 0.003773584;
126    m_offsets[2] = 0.00390625;
127
128    Adxl345::update();
129}
130
131float*
132Adxl345::getAcceleration()
133{
134    for(int i = 0; i < 3; i++){
135        m_accel[i] = m_rawaccel[i] * m_offsets[i];
136    }
137    return &m_accel[0];
138}
139
140int16_t*
141Adxl345::getRawValues()
142{
143    return &m_rawaccel[0];
144}
145
146uint8_t
147Adxl345::getScale(){
148
149    uint8_t result;
150
151    m_i2c.address(ADXL345_I2C_ADDR);
152    m_i2c.writeByte(ADXL345_DATA_FORMAT);
153
154    m_i2c.address(ADXL345_I2C_ADDR);
155    result = m_i2c.readByte();
156
157    return pow(2, (result & 0x03) + 1);
158}
159
160mraa::Result
161Adxl345::update(void)
162{
163    m_i2c.address(ADXL345_I2C_ADDR);
164    m_i2c.writeByte(ADXL345_XOUT_L);
165
166    m_i2c.address(ADXL345_I2C_ADDR);
167    m_i2c.read(m_buffer, DATA_REG_SIZE);
168
169    // x
170    m_rawaccel[0] = ((m_buffer[1] << 8 ) | m_buffer[0]);
171    // y
172    m_rawaccel[1] = ((m_buffer[3] << 8 ) | m_buffer[2]);
173    // z
174    m_rawaccel[2] = ((m_buffer[5] << 8 ) | m_buffer[4]);
175
176    return mraa::SUCCESS;
177}
178