Contiki-NG
adxl345.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, Swedish Institute of Computer Science.
3  * Copyright (c) 2016, Zolertia <http://www.zolertia.com>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the Institute nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * This file is part of the Contiki operating system.
31  *
32  */
33 /*---------------------------------------------------------------------------*/
34 /**
35  * \file
36  * Device drivers for adxl345 accelerometer in Zolertia Z1.
37  * \author
38  * Marcus Lundén, SICS <mlunden@sics.se>
39  * Enric M. Calvo, Zolertia <ecalvo@zolertia.com>
40  * Antonio Lignan, Zolertia <alinan@zolertia.com>
41  */
42 /*---------------------------------------------------------------------------*/
43 #include <stdio.h>
44 #include "contiki.h"
45 #include "adxl345.h"
46 #include "cc2420.h"
47 #include "i2cmaster.h"
48 #include "isr_compat.h"
49 #include "lib/sensors.h"
50 /*---------------------------------------------------------------------------*/
51 #define DEBUG 0
52 #if DEBUG
53 #define PRINTF(...) printf(__VA_ARGS__)
54 #else
55 #define PRINTF(...)
56 #endif
57 /*---------------------------------------------------------------------------*/
58 static uint8_t enabled;
59 /*---------------------------------------------------------------------------*/
60 /* Callback pointers when interrupt occurs */
61 void (*accm_int1_cb)(uint8_t reg);
62 void (*accm_int2_cb)(uint8_t reg);
63 /*---------------------------------------------------------------------------*/
64 /* Bitmasks for the interrupts */
65 static uint16_t int1_mask = 0, int2_mask = 0;
66 
67 /* Default values for adxl345 at startup.
68  * This will be sent to the adxl345 in a
69  * stream at init to set it up in a default state
70  */
71 
72 static uint8_t adxl345_default_settings[] = {
73  /* Note, as the two first two bulks are to be written in a stream, they contain
74  * the register address as first byte in that section.
75  * 0--14 are in one stream, start at ADXL345_THRESH_TAP
76  */
77  /* XXX NB Register address, not register value!! */
78  ADXL345_THRESH_TAP,
79  ADXL345_THRESH_TAP_DEFAULT,
80  ADXL345_OFSX_DEFAULT,
81  ADXL345_OFSY_DEFAULT,
82  ADXL345_OFSZ_DEFAULT,
83  ADXL345_DUR_DEFAULT,
84  ADXL345_LATENT_DEFAULT,
85  ADXL345_WINDOW_DEFAULT,
86  ADXL345_THRESH_ACT_DEFAULT,
87  ADXL345_THRESH_INACT_DEFAULT,
88  ADXL345_TIME_INACT_DEFAULT,
89  ADXL345_ACT_INACT_CTL_DEFAULT,
90  ADXL345_THRESH_FF_DEFAULT,
91  ADXL345_TIME_FF_DEFAULT,
92  ADXL345_TAP_AXES_DEFAULT,
93 
94  /* 15--19 start at ADXL345_BW_RATE */
95  /* XXX NB Register address, not register value!! */
96  ADXL345_BW_RATE,
97  ADXL345_BW_RATE_DEFAULT,
98  ADXL345_POWER_CTL_DEFAULT,
99  ADXL345_INT_ENABLE_DEFAULT,
100  ADXL345_INT_MAP_DEFAULT,
101 
102  /* These two: 20, 21 write separately */
103  ADXL345_DATA_FORMAT_DEFAULT,
104  ADXL345_FIFO_CTL_DEFAULT
105 };
106 /*---------------------------------------------------------------------------*/
107 PROCESS(accmeter_process, "Accelerometer process");
108 /*---------------------------------------------------------------------------*/
109 static void
110 accm_write_reg(uint8_t reg, uint8_t val)
111 {
112  uint8_t tx_buf[] = {reg, val};
113 
114  i2c_transmitinit(ADXL345_ADDR);
115  while (i2c_busy());
116  PRINTF("ADXL345: I2C Ready to TX\n");
117 
118  i2c_transmit_n(2, tx_buf);
119  while (i2c_busy());
120  PRINTF("ADXL345: WRITE_REG 0x%02X @ reg 0x%02X\n", val, reg);
121 }
122 /*---------------------------------------------------------------------------*/
123 /* First byte in stream must be the register address to begin writing to.
124  * The data is then written from second byte and increasing.
125  */
126 static void
127 accm_write_stream(uint8_t len, uint8_t *data)
128 {
129  i2c_transmitinit(ADXL345_ADDR);
130  while (i2c_busy());
131  PRINTF("ADXL345: I2C Ready to TX(stream)\n");
132 
133  i2c_transmit_n(len, data); // start tx and send conf reg
134  while (i2c_busy());
135  PRINTF("ADXL345: WRITE_STR %u B to 0x%02X\n", len, data[0]);
136 }
137 
138 /*---------------------------------------------------------------------------*/
139 static uint8_t
140 accm_read_reg(uint8_t reg)
141 {
142  uint8_t retVal = 0;
143  uint8_t rtx = reg;
144  PRINTF("ADXL345: READ_REG 0x%02X\n", reg);
145 
146  /* transmit the register to read */
147  i2c_transmitinit(ADXL345_ADDR);
148  while (i2c_busy());
149  i2c_transmit_n(1, &rtx);
150  while (i2c_busy());
151 
152  /* receive the data */
153  i2c_receiveinit(ADXL345_ADDR);
154  while (i2c_busy());
155  i2c_receive_n(1, &retVal);
156  while (i2c_busy());
157 
158  return retVal;
159 }
160 /*---------------------------------------------------------------------------*/
161 static void
162 accm_read_stream(uint8_t reg, uint8_t len, uint8_t *whereto)
163 {
164  uint8_t rtx = reg;
165  PRINTF("ADXL345: READ_STR %u B from 0x%02X\n", len, reg);
166 
167  /* transmit the register to start reading from */
168  i2c_transmitinit(ADXL345_ADDR);
169  while (i2c_busy());
170  i2c_transmit_n(1, &rtx);
171  while (i2c_busy());
172 
173  /* receive the data */
174  i2c_receiveinit(ADXL345_ADDR);
175  while (i2c_busy());
176  i2c_receive_n(len, whereto);
177  while (i2c_busy());
178 }
179 
180 /*---------------------------------------------------------------------------*/
181 /* Read an axis of the accelerometer (x, y or z). Return value is a signed
182  * 10 bit int.
183  * The resolution of the acceleration measurement can be increased up to 13 bit,
184  * but will change the data format of this read out. Refer to the data sheet if
185  * so is wanted/needed.
186  */
187 int16_t
188 accm_read_axis(enum ADXL345_AXIS axis)
189 {
190  int16_t rd = 0;
191  uint8_t tmp[2];
192  if(axis > Z_AXIS){
193  return 0;
194  }
195  accm_read_stream(ADXL345_DATAX0 + axis, 2, &tmp[0]);
196  rd = (int16_t)(tmp[0] | (tmp[1]<<8));
197  return rd;
198 }
199 /*---------------------------------------------------------------------------*/
200 int
201 accm_set_grange(uint8_t grange)
202 {
203  uint8_t tempreg = 0;
204 
205  if(grange > ADXL345_RANGE_16G) {
206  PRINTF("ADXL345: grange invalid: %u\n", grange);
207  return ADXL345_ERROR;
208  }
209 
210  if(!enabled) {
211  return ADXL345_ERROR;
212  }
213 
214  /* Keep the previous contents of the register, zero out the last two bits */
215  tempreg = (accm_read_reg(ADXL345_DATA_FORMAT) & 0xFC);
216  tempreg |= grange;
217  accm_write_reg(ADXL345_DATA_FORMAT, tempreg);
218  return ADXL345_SUCCESS;
219 }
220 
221 /*---------------------------------------------------------------------------*/
222 void
223 accm_init(void)
224 {
225  PRINTF("ADXL345: init\n");
226  accm_int1_cb = NULL;
227  accm_int2_cb = NULL;
228 
229  /* Set up ports and pins for interrups. */
230  ADXL345_DIR &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
231  ADXL345_SEL &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
232  ADXL345_SEL2 &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
233 
234  /* Set up ports and pins for I2C communication */
235  i2c_enable();
236 
237  /* set default register values. */
238  accm_write_stream(15, &adxl345_default_settings[0]);
239  accm_write_stream(5, &adxl345_default_settings[15]);
240  accm_write_reg(ADXL345_DATA_FORMAT, adxl345_default_settings[20]);
241  accm_write_reg(ADXL345_FIFO_CTL, adxl345_default_settings[21]);
242 
243  process_start(&accmeter_process, NULL);
244 
245  /* Enable msp430 interrupts on the two interrupt pins. */
246  dint();
247  /* low to high transition interrupts */
248  ADXL345_IES &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
249  /* enable interrupts */
250  ADXL345_IE |= (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
251  eint();
252 
253  enabled = 1;
254 }
255 /*---------------------------------------------------------------------------*/
256 void
257 accm_stop(void)
258 {
259  dint();
260  ADXL345_IE &= ~(ADXL345_INT1_PIN | ADXL345_INT2_PIN);
261  accm_write_reg(ADXL345_INT_ENABLE, ~(int1_mask | int2_mask));
262  accm_write_reg(ADXL345_INT_MAP, ~int2_mask);
263  eint();
264  enabled = 0;
265 }
266 /*---------------------------------------------------------------------------*/
267 int
268 accm_set_irq(uint8_t int1, uint8_t int2)
269 {
270  if(!enabled) {
271  return ADXL345_ERROR;
272  }
273 
274  /* Set the corresponding interrupt mapping to INT1 or INT2 */
275  PRINTF("ADXL345: IRQs set to INT1: 0x%02X IRQ2: 0x%02X\n", int1, int2);
276 
277  int1_mask = int1;
278  int2_mask = int2;
279 
280  accm_write_reg(ADXL345_INT_ENABLE, (int1 | int2));
281  /* int1 bits are zeroes in the map register so this is for both ints */
282  accm_write_reg(ADXL345_INT_MAP, int2);
283  return ADXL345_SUCCESS;
284 }
285 /*---------------------------------------------------------------------------*/
286 /* Invoked after an interrupt happened. Reads the interrupt source reg at the
287  * accelerometer, which resets the interrupts, and invokes the corresponding
288  * callback. It passes the source register value so the callback can determine
289  * what interrupt happened, if several interrupts are mapped to the same pin.
290  */
291 static void
292 poll_handler(void)
293 {
294  uint8_t ireg = 0;
295  ireg = accm_read_reg(ADXL345_INT_SOURCE);
296 
297  /* Invoke callbacks for the corresponding interrupts */
298  if(ireg & int1_mask){
299  if(accm_int1_cb != NULL){
300  PRINTF("ADXL345: INT1 cb invoked\n");
301  accm_int1_cb(ireg);
302  }
303  } else if(ireg & int2_mask){
304  if(accm_int2_cb != NULL){
305  PRINTF("ADXL345: INT2 cb invoked\n");
306  accm_int2_cb(ireg);
307  }
308  }
309 }
310 /*---------------------------------------------------------------------------*/
311 /* This process is sleeping until an interrupt from the accelerometer occurs,
312  * which polls this process from the interrupt service routine. */
313 PROCESS_THREAD(accmeter_process, ev, data)
314 {
315  PROCESS_POLLHANDLER(poll_handler());
317  PROCESS_BEGIN();
318  while(1){
320  }
321  PROCESS_END();
322 }
323 /*---------------------------------------------------------------------------*/
324 /* This interrupt vector is shared with the interrupts from CC2420, so that
325  * was moved here
326  */
327 static struct timer suppressTimer1, suppressTimer2;
328 
329 ISR(PORT1, port1_isr)
330 {
331  /* ADXL345_IFG.x goes high when interrupt occurs, use to check what
332  * interrupted
333  */
334  if((ADXL345_IFG & ADXL345_INT1_PIN) && !(ADXL345_IFG & BV(CC2420_FIFOP_PIN))){
335  /* Check if this should be suppressed or not */
336  if(timer_expired(&suppressTimer1)) {
337  timer_set(&suppressTimer1, SUPPRESS_TIME_INT1);
338  ADXL345_IFG &= ~ADXL345_INT1_PIN; // clear interrupt flag
339  process_poll(&accmeter_process);
340  LPM4_EXIT;
341  }
342  } else if((ADXL345_IFG & ADXL345_INT2_PIN) &&
343  !(ADXL345_IFG & BV(CC2420_FIFOP_PIN))){
344  /* Check if this should be suppressed or not */
345  if(timer_expired(&suppressTimer2)) {
346  timer_set(&suppressTimer2, SUPPRESS_TIME_INT2);
347  /* clear interrupt flag */
348  ADXL345_IFG &= ~ADXL345_INT2_PIN;
349  process_poll(&accmeter_process);
350  LPM4_EXIT;
351  }
352  } else {
353  /* CC2420 interrupt */
354  if(cc2420_interrupt()) {
355  LPM4_EXIT;
356  }
357  }
358 }
359 /*---------------------------------------------------------------------------*/
360 static int
361 configure(int type, int value)
362 {
363  if(type != SENSORS_ACTIVE) {
364  return ADXL345_ERROR;
365  }
366 
367  if(value) {
368  accm_init();
369  } else {
370  accm_stop();
371  }
372  enabled = value;
373  return ADXL345_SUCCESS;
374 }
375 /*---------------------------------------------------------------------------*/
376 static int
377 status(int type)
378 {
379  switch(type) {
380  case SENSORS_ACTIVE:
381  case SENSORS_READY:
382  return enabled;
383  }
384  return ADXL345_SUCCESS;
385 }
386 /*---------------------------------------------------------------------------*/
387 static int
388 value(int type)
389 {
390  if(!enabled) {
391  return ADXL345_ERROR;
392  }
393 
394  if((type != X_AXIS) && (type != Y_AXIS) && (type != Z_AXIS)) {
395  return ADXL345_ERROR;
396  }
397 
398  switch(type) {
399  case X_AXIS:
400  return accm_read_axis(X_AXIS);
401  case Y_AXIS:
402  return accm_read_axis(Y_AXIS);
403  case Z_AXIS:
404  return accm_read_axis(Z_AXIS);
405  default:
406  return ADXL345_ERROR;
407  }
408 }
409 /*---------------------------------------------------------------------------*/
410 SENSORS_SENSOR(adxl345, ADXL345_SENSOR, value, configure, status);
411 /*---------------------------------------------------------------------------*/
CC2420 driver header file
void timer_set(struct timer *t, clock_time_t interval)
Set a timer.
Definition: timer.c:64
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
I2C communication device driver header file for Zolertia Z1 sensor node.
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
int cc2420_interrupt(void)
Interrupt function, called from the simple-cc2420-arch driver.
Definition: cc2420.c:870
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition: process.h:157
A timer.
Definition: timer.h:82
#define PROCESS_EXITHANDLER(handler)
Specify an action when a process exits.
Definition: process.h:254
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
int timer_expired(struct timer *t)
Check if a timer has expired.
Definition: timer.c:123
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1097
Device drivers header file for adxl345 accelerometer in Zolertia Z1.
#define PROCESS_POLLHANDLER(handler)
Specify an action when a process is polled.
Definition: process.h:242
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99