Contiki-NG
adxl346.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, OpenMote Technologies, S.L.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 /*---------------------------------------------------------------------------*/
33 /**
34  * \addtogroup openmote-adxl346-sensor
35  * @{
36  *
37  * \file
38  * Driver for the ADXL346 acceleration sensor
39  *
40  * \author
41  * Pere Tuset <peretuset@openmote.com>
42  */
43 /*---------------------------------------------------------------------------*/
44 #include "dev/i2c.h"
45 #include "dev/adxl346.h"
46 #include "lib/sensors.h"
47 /*---------------------------------------------------------------------------*/
48 #define DEBUG 0
49 #if DEBUG
50 #define PRINTF(...) printf(__VA_ARGS__)
51 #else
52 #define PRINTF(...)
53 #endif
54 /*---------------------------------------------------------------------------*/
55 /**
56  * \name ADXL346 address and device identifier
57  * @{
58  */
59 #define ADXL346_ADDRESS (0x53)
60 #define ADXL346_DEVID_VALUE (0xE6)
61 /** @} */
62 /* -------------------------------------------------------------------------- */
63 /**
64  * \name ADXL346 register addresses
65  * @{
66  */
67 #define ADXL346_DEVID_ADDR (0x00)
68 #define ADXL346_THRES_TAP_ADDR (0x1D)
69 #define ADXL346_OFSX_ADDR (0x1E)
70 #define ADXL346_OFSY_ADDR (0x1F)
71 #define ADXL346_OFSZ_ADDR (0x20)
72 #define ADXL346_DUR_ADDR (0x21)
73 #define ADXL346_LATENT_ADDR (0x22)
74 #define ADXL346_WINDOW_ADDR (0x23)
75 #define ADXL346_THRESH_ACT_ADDR (0x24)
76 #define ADXL346_THRESH_INACT_ADDR (0x25)
77 #define ADXL346_TIME_INACT_ADDR (0x26)
78 #define ADXL346_ACT_INACT_CTL_ADDR (0x27)
79 #define ADXL346_THRESH_FF_ADDR (0x28)
80 #define ADXL346_TIME_FF_ADDR (0x29)
81 #define ADXL346_TAP_AXES_ADDR (0x2A)
82 #define ADXL346_ACT_TAP_STATUS_ADDR (0x2B)
83 #define ADXL346_BW_RATE_ADDR (0x2C)
84 #define ADXL346_POWER_CTL_ADDR (0x2D)
85 #define ADXL346_INT_ENABLE_ADDR (0x2E)
86 #define ADXL346_INT_MAP_ADDR (0x2F)
87 #define ADXL346_INT_SOURCE_ADDR (0x30)
88 #define ADXL346_DATA_FORMAT_ADDR (0x31)
89 #define ADXL346_DATAX0_ADDR (0x32)
90 #define ADXL346_DATAX1_ADDR (0x33)
91 #define ADXL346_DATAY0_ADDR (0x34)
92 #define ADXL346_DATAY1_ADDR (0x35)
93 #define ADXL346_DATAZ0_ADDR (0x36)
94 #define ADXL346_DATAZ1_ADDR (0x37)
95 #define ADXL346_FIFO_CTL_ADDR (0x38)
96 #define ADXL346_FIFO_STATUS_ADDR (0x39)
97 #define ADXL346_TAP_SIGN_ADDR (0x3A)
98 #define ADXL346_ORIENT_CONF_ADDR (0x3B)
99 #define ADXL346_ORIENT_ADDR (0x3C)
100 /** @} */
101 /* -------------------------------------------------------------------------- */
102 /**
103  * \name ADXL346 register values
104  * @{
105  */
106 #define ADXL346_INT_ENABLE_DATA_READY (1 << 7)
107 #define ADXL346_INT_ENABLE_SINGLE_TAP (1 << 6)
108 #define ADXL346_INT_ENABLE_DOUBLE_TAP (1 << 5)
109 #define ADXL346_INT_ENABLE_ACTIVITY (1 << 4)
110 #define ADXL346_INT_ENABLE_INACTIVITY (1 << 3)
111 #define ADXL346_INT_ENABLE_FREE_FALL (1 << 2)
112 #define ADXL346_INT_ENABLE_WATERMARK (1 << 1)
113 #define ADXL346_INT_ENABLE_OVERRUN (1 << 0)
114 
115 #define ADXL346_ACT_INACT_CTL_ACT_ACDC (1 << 7)
116 #define ADXL346_ACT_INACT_CTL_ACT_X_EN (1 << 6)
117 #define ADXL346_ACT_INACT_CTL_ACT_Y_EN (1 << 5)
118 #define ADXL346_ACT_INACT_CTL_ACT_Z_EN (1 << 4)
119 #define ADXL346_ACT_INACT_CTL_INACT_ACDC (1 << 3)
120 #define ADXL346_ACT_INACT_CTL_INACT_X_EN (1 << 2)
121 #define ADXL346_ACT_INACT_CTL_INACT_Y_EN (1 << 1)
122 #define ADXL346_ACT_INACT_CTL_INACT_Z_EN (1 << 0)
123 
124 #define ADXL346_TAP_AXES_SUPPRESS (1 << 3)
125 #define ADXL346_TAP_AXES_TAP_X_EN (1 << 2)
126 #define ADXL346_TAP_AXES_TAP_Y_EN (1 << 1)
127 #define ADXL346_TAP_AXES_TAP_Z_EN (1 << 0)
128 
129 #define ADXL346_ACT_TAP_STATUS_ACT_X_SRC (1 << 6)
130 #define ADXL346_ACT_TAP_STATUS_ACT_Y_SRC (1 << 5)
131 #define ADXL346_ACT_TAP_STATUS_ACT_Z_SRC (1 << 4)
132 #define ADXL346_ACT_TAP_STATUS_ASLEEP (1 << 3)
133 #define ADXL346_ACT_TAP_STATUS_TAP_X_SRC (1 << 2)
134 #define ADXL346_ACT_TAP_STATUS_TAP_Y_SRC (1 << 1)
135 #define ADXL346_ACT_TAP_STATUS_TAP_Z_SRC (1 << 0)
136 
137 #define ADXL346_BW_RATE_POWER (1 << 4)
138 #define ADXL346_BW_RATE_RATE(x) ((x) & 0x0F)
139 
140 #define ADXL346_POWER_CTL_LINK (1 << 5)
141 #define ADXL346_POWER_CTL_AUTO_SLEEP (1 << 4)
142 #define ADXL346_POWER_CTL_MEASURE (1 << 3)
143 #define ADXL346_POWER_CTL_SLEEP (1 << 2)
144 #define ADXL346_POWER_CTL_WAKEUP(x) ((x) & 0x03)
145 
146 #define ADXL346_DATA_FORMAT_SELF_TEST (1 << 7)
147 #define ADXL346_DATA_FORMAT_SPI (1 << 6)
148 #define ADXL346_DATA_FORMAT_INT_INVERT (1 << 5)
149 #define ADXL346_DATA_FORMAT_FULL_RES (1 << 3)
150 #define ADXL346_DATA_FORMAT_JUSTIFY (1 << 2)
151 #define ADXL346_DATA_FORMAT_RANGE(x) ((x) & 0x03)
152 #define ADXL346_DATA_FORMAT_RANGE_PM_2g (0)
153 #define ADXL346_DATA_FORMAT_RANGE_PM_4g (1)
154 #define ADXL346_DATA_FORMAT_RANGE_PM_8g (2)
155 #define ADXL346_DATA_FORMAT_RANGE_PM_16g (3)
156 
157 #define ADXL346_USER_CONFIGURATION (ADXL346_DATA_FORMAT_RANGE_PM_2g)
158 
159 /** @} */
160 /*---------------------------------------------------------------------------*/
161 static uint8_t enabled;
162 /*---------------------------------------------------------------------------*/
163 static void
164 adxl346_init(void)
165 {
166  uint8_t config[2];
167 
168  config[0] = ADXL346_BW_RATE_ADDR;
169  config[1] = (ADXL346_BW_RATE_RATE(6));
170  i2c_burst_send(ADXL346_ADDRESS, config, sizeof(config));
171 
172  config[0] = ADXL346_DATA_FORMAT_ADDR;
173  config[1] = (ADXL346_USER_CONFIGURATION);
174  i2c_burst_send(ADXL346_ADDRESS, config, sizeof(config));
175 
176  config[0] = ADXL346_POWER_CTL_ADDR;
177  config[1] = (ADXL346_POWER_CTL_MEASURE);
178  i2c_burst_send(ADXL346_ADDRESS, config, sizeof(config));
179 }
180 /*---------------------------------------------------------------------------*/
181 static uint8_t
182 adxl346_is_present(void)
183 {
184  uint8_t is_present;
185 
186  i2c_single_send(ADXL346_ADDRESS, ADXL346_DEVID_ADDR);
187  i2c_single_receive(ADXL346_ADDRESS, &is_present);
188 
189  return is_present == ADXL346_DEVID_VALUE;
190 }
191 /*---------------------------------------------------------------------------*/
192 static int16_t
193 adxl346_read_accel(uint8_t addr1, uint8_t addr2)
194 {
195  uint8_t acceleration[2];
196  int16_t result;
197 
198  i2c_single_send(ADXL346_ADDRESS, addr1);
199  i2c_single_receive(ADXL346_ADDRESS, &acceleration[0]);
200  i2c_single_send(ADXL346_ADDRESS, addr2);
201  i2c_single_receive(ADXL346_ADDRESS, &acceleration[1]);
202 
203  result = (acceleration[1] << 8) | acceleration[0];
204 
205  return result;
206 }
207 /*---------------------------------------------------------------------------*/
208 static int16_t
209 adxl346_convert_accel(int16_t accel)
210 {
211  int32_t result;
212 
213  result = (1000 * accel) / 256;
214 
215  return (int16_t)result;
216 }
217 /*---------------------------------------------------------------------------*/
218 static void
219 adxl346_calibrate_offset(void)
220 {
221  int32_t accum_x = 0;
222  int32_t accum_y = 0;
223  int32_t accum_z = 0;
224  uint8_t config[2];
225  int8_t offset;
226 
227  config[0] = ADXL346_OFSX_ADDR;
228  config[1] = 0;
229  i2c_burst_send(ADXL346_ADDRESS, config, sizeof(config));
230  config[0] = ADXL346_OFSY_ADDR;
231  config[1] = 0;
232  i2c_burst_send(ADXL346_ADDRESS, config, sizeof(config));
233  config[0] = ADXL346_OFSZ_ADDR;
234  config[1] = 0;
235  i2c_burst_send(ADXL346_ADDRESS, config, sizeof(config));
236 
237  uint16_t i;
238  for(i = 0; i < 100; i++) {
239  uint16_t x, y, z;
240 
241  x = adxl346_read_accel(ADXL346_DATAX0_ADDR, ADXL346_DATAX1_ADDR);
242  accum_x += x;
243 
244  y = adxl346_read_accel(ADXL346_DATAY0_ADDR, ADXL346_DATAY1_ADDR);
245  accum_y += y;
246 
247  z = adxl346_read_accel(ADXL346_DATAZ0_ADDR, ADXL346_DATAZ1_ADDR);
248  accum_z += z;
249  }
250 
251  offset = (64 * accum_x) / 25600;
252  config[0] = ADXL346_OFSX_ADDR;
253  config[1] = -offset;
254  i2c_burst_send(ADXL346_ADDRESS, config, sizeof(config));
255  PRINTF("ADXL346: X calibration offset is %d\n", offset);
256 
257  offset = (64 * accum_y) / 25600;
258  config[0] = ADXL346_OFSY_ADDR;
259  config[1] = -offset;
260  i2c_burst_send(ADXL346_ADDRESS, config, sizeof(config));
261  PRINTF("ADXL346: Y calibration offset is %d\n", offset);
262 
263  offset = (64 * accum_z) / 25600;
264  config[0] = ADXL346_OFSZ_ADDR;
265  config[1] = -offset;
266  i2c_burst_send(ADXL346_ADDRESS, config, sizeof(config));
267  PRINTF("ADXL346: Z calibration offset is %d\n", offset);
268 }
269 /*---------------------------------------------------------------------------*/
270 static int
271 status(int type)
272 {
273  switch(type) {
274  case SENSORS_ACTIVE:
275  case SENSORS_READY:
276  return enabled;
277  }
278  return 0;
279 }
280 /*---------------------------------------------------------------------------*/
281 static int
282 value(int type)
283 {
284  int16_t accel;
285  if(!enabled) {
286  PRINTF("ADXL346: sensor not started\n");
287  return ADXL346_ERROR;
288  }
289 
290  if(type == ADXL346_READ_X) {
291  return adxl346_read_accel(ADXL346_DATAX0_ADDR, ADXL346_DATAX1_ADDR);
292  } else if(type == ADXL346_READ_Y) {
293  return adxl346_read_accel(ADXL346_DATAY0_ADDR, ADXL346_DATAY1_ADDR);
294  } else if(type == ADXL346_READ_Z) {
295  return adxl346_read_accel(ADXL346_DATAZ0_ADDR, ADXL346_DATAZ1_ADDR);
296  } else if(type == ADXL346_READ_X_mG) {
297  accel = adxl346_read_accel(ADXL346_DATAX0_ADDR, ADXL346_DATAX1_ADDR);
298  return adxl346_convert_accel(accel);
299  } else if(type == ADXL346_READ_Y_mG) {
300  accel = adxl346_read_accel(ADXL346_DATAY0_ADDR, ADXL346_DATAY1_ADDR);
301  return adxl346_convert_accel(accel);
302  } else if(type == ADXL346_READ_Z_mG) {
303  accel = adxl346_read_accel(ADXL346_DATAZ0_ADDR, ADXL346_DATAZ1_ADDR);
304  return adxl346_convert_accel(accel);
305  } else {
306  PRINTF("ADXL346: invalid value requested\n");
307  return ADXL346_ERROR;
308  }
309 
310  return ADXL346_ERROR;
311 }
312 /*---------------------------------------------------------------------------*/
313 static int
314 configure(int type, int value)
315 {
316  if(type == ADXL346_ACTIVATE) {
317  if(!adxl346_is_present()) {
318  PRINTF("ADXL346: is not present\n");
319  enabled = 0;
320  return ADXL346_ERROR;
321  } else {
322  adxl346_init();
323  enabled = 1;
324  return ADXL346_SUCCESS;
325  }
326  }
327 
328  if(type == ADXL346_CALIB_OFFSET && enabled) {
329  adxl346_calibrate_offset();
330  return ADXL346_SUCCESS;
331  }
332 
333  return ADXL346_ERROR;
334 }
335 /*---------------------------------------------------------------------------*/
336 SENSORS_SENSOR(adxl346, ADXL346_SENSOR, value, configure, status);
337 /*---------------------------------------------------------------------------*/
338 /** @} */
uint8_t i2c_burst_send(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to send multiple bytes to a slave.
Definition: i2c.c:188
static int config(int type, int c, nrf_drv_gpiote_pin_t pin)
Configuration function for the button sensor for all buttons.
uint8_t i2c_single_receive(uint8_t slave_addr, uint8_t *data)
Perform all operations to receive a byte from a slave.
Definition: i2c.c:172
ADXL346 acceleration sensor driver header file.
uint8_t i2c_single_send(uint8_t slave_addr, uint8_t data)
Perform all operations to send a byte to a slave.
Definition: i2c.c:159