Contiki 3.x
adxl345.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, Swedish Institute of Computer Science.
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  * \file
35  * Device drivers for adxl345 accelerometer in Zolertia Z1.
36  * \author
37  * Marcus Lundén, SICS <mlunden@sics.se>
38  * Enric M. Calvo, Zolertia <ecalvo@zolertia.com>
39  */
40 
41 
42 #include <stdio.h>
43 #include "contiki.h"
44 #include "adxl345.h"
45 //#include "cc2420.h"
46 #include "platform-conf.h"
47 #include <cc1120.h>
48 #include <cc1120-arch.h>
49 #include "i2cmaster.h"
50 #include "isr_compat.h"
51 
52  #ifdef ADXLDEBUG
53  #define PRINTFDEBUG(...) printf(__VA_ARGS)
54  #else
55  #define PRINTFDEBUG(...)
56  #endif
57 
58 /* Callback pointers when interrupt occurs */
59 void (*accm_int1_cb)(uint8_t reg);
60 void (*accm_int2_cb)(uint8_t reg);
61 
62 process_event_t int1_event, int2_event;
63 
64 /* Bitmasks for the interrupts */
65 static uint16_t int1_mask = 0, int2_mask = 0;
66 
67 /* Keep track of when the interrupt was last seen in order to reduce the amount
68  of interrupts. Kind of like button debouncing. This can't be per int-pin, as
69  there can be several very different int per pin (eg tap && freefall). */
70 // XXX Not used now, only one global timer.
71 //static volatile clock_time_t ints_lasttime[] = {0, 0, 0, 0, 0, 0, 0, 0};
72 
73 /* Bitmasks and bit flag variable for keeping track of adxl345 status. */
74 enum ADXL345_STATUSTYPES {
75  /* must be a bit and not more, not using 0x00. */
76  INITED = 0x01,
77  RUNNING = 0x02,
78  STOPPED = 0x04,
79  LOW_POWER = 0x08,
80  AAA = 0x10, // available to extend this...
81  BBB = 0x20, // available to extend this...
82  CCC = 0x40, // available to extend this...
83  DDD = 0x80, // available to extend this...
84 };
85 static enum ADXL345_STATUSTYPES _ADXL345_STATUS = 0x00;
86 
87 /* Default values for adxl345 at startup. This will be sent to the adxl345 in a
88  stream at init to set it up in a default state */
89 static uint8_t adxl345_default_settings[] = {
90  /* Note, as the two first two bulks are to be written in a stream, they contain
91  the register address as first byte in that section. */
92  /* 0--14 are in one stream, start at ADXL345_THRESH_TAP */
93  ADXL345_THRESH_TAP, // XXX NB Register address, not register value!!
94  ADXL345_THRESH_TAP_DEFAULT,
95  ADXL345_OFSX_DEFAULT,
96  ADXL345_OFSY_DEFAULT,
97  ADXL345_OFSZ_DEFAULT,
98  ADXL345_DUR_DEFAULT,
99  ADXL345_LATENT_DEFAULT,
100  ADXL345_WINDOW_DEFAULT,
101  ADXL345_THRESH_ACT_DEFAULT,
102  ADXL345_THRESH_INACT_DEFAULT,
103  ADXL345_TIME_INACT_DEFAULT,
104  ADXL345_ACT_INACT_CTL_DEFAULT,
105  ADXL345_THRESH_FF_DEFAULT,
106  ADXL345_TIME_FF_DEFAULT,
107  ADXL345_TAP_AXES_DEFAULT,
108 
109  /* 15--19 start at ADXL345_BW_RATE */
110  ADXL345_BW_RATE, // XXX NB Register address, not register value!!
111  ADXL345_BW_RATE_DEFAULT,
112  ADXL345_POWER_CTL_DEFAULT,
113  ADXL345_INT_ENABLE_DEFAULT,
114  ADXL345_INT_MAP_DEFAULT,
115 
116  /* These two: 20, 21 write separately */
117  ADXL345_DATA_FORMAT_DEFAULT,
118  ADXL345_FIFO_CTL_DEFAULT
119 };
120 
121 
122 /*---------------------------------------------------------------------------*/
123 PROCESS(accmeter_process, "Accelerometer process");
124 /*---------------------------------------------------------------------------*/
125 /* Write to a register.
126  args:
127  reg register to write to
128  val value to write
129 */
130 
131 void
132 accm_write_reg(uint8_t reg, uint8_t val) {
133  uint8_t tx_buf[] = {reg, val};
134 
135  i2c_transmitinit(ADXL345_ADDR);
136  while (i2c_busy());
137  PRINTFDEBUG("I2C Ready to TX\n");
138 
139  i2c_transmit_n(2, tx_buf);
140  while (i2c_busy());
141  PRINTFDEBUG("WRITE_REG 0x%02X @ reg 0x%02X\n", val, reg);
142 }
143 /*---------------------------------------------------------------------------*/
144 /* Write several registers from a stream.
145  args:
146  len number of bytes to read
147  data pointer to where the data is read from
148 
149  First byte in stream must be the register address to begin writing to.
150  The data is then written from second byte and increasing. */
151 
152 void
153 accm_write_stream(uint8_t len, uint8_t *data) {
154  i2c_transmitinit(ADXL345_ADDR);
155  while (i2c_busy());
156  PRINTFDEBUG("I2C Ready to TX(stream)\n");
157 
158  i2c_transmit_n(len, data); // start tx and send conf reg
159  while (i2c_busy());
160  PRINTFDEBUG("WRITE_STR %u B to 0x%02X\n", len, data[0]);
161 }
162 
163 /*---------------------------------------------------------------------------*/
164 /* Read one register.
165  args:
166  reg what register to read
167  returns the value of the read register
168 */
169 
170 uint8_t
171 accm_read_reg(uint8_t reg) {
172  uint8_t retVal = 0;
173  uint8_t rtx = reg;
174  PRINTFDEBUG("READ_REG 0x%02X\n", reg);
175 
176  /* transmit the register to read */
177  i2c_transmitinit(ADXL345_ADDR);
178  while (i2c_busy());
179  i2c_transmit_n(1, &rtx);
180  while (i2c_busy());
181 
182  /* receive the data */
183  i2c_receiveinit(ADXL345_ADDR);
184  while (i2c_busy());
185  i2c_receive_n(1, &retVal);
186  while (i2c_busy());
187 
188  return retVal;
189 }
190 
191 /*---------------------------------------------------------------------------*/
192 /* Read several registers in a stream.
193  args:
194  reg what register to start reading from
195  len number of bytes to read
196  whereto pointer to where the data is saved
197 */
198 
199 void
200 accm_read_stream(uint8_t reg, uint8_t len, uint8_t *whereto) {
201  uint8_t rtx = reg;
202  PRINTFDEBUG("READ_STR %u B from 0x%02X\n", len, reg);
203 
204  /* transmit the register to start reading from */
205  i2c_transmitinit(ADXL345_ADDR);
206  while (i2c_busy());
207  i2c_transmit_n(1, &rtx);
208  while (i2c_busy());
209 
210  /* receive the data */
211  i2c_receiveinit(ADXL345_ADDR);
212  while (i2c_busy());
213  i2c_receive_n(len, whereto);
214  while (i2c_busy());
215 }
216 
217 /*---------------------------------------------------------------------------*/
218 /* Read an axis of the accelerometer (x, y or z). Return value is a signed 10 bit int.
219  The resolution of the acceleration measurement can be increased up to 13 bit, but
220  will change the data format of this read out. Refer to the data sheet if so is
221  wanted/needed. */
222 
223 int16_t
224 accm_read_axis(enum ADXL345_AXIS axis){
225  int16_t rd = 0;
226  uint8_t tmp[2];
227  if(axis > Z_AXIS){
228  return 0;
229  }
230  accm_read_stream(ADXL345_DATAX0 + axis, 2, &tmp[0]);
231  rd = (int16_t)(tmp[0] | (tmp[1]<<8));
232  return rd;
233 }
234 
235 /*---------------------------------------------------------------------------*/
236 /* Sets the g-range, ie the range the accelerometer measures (ie 2g means -2 to +2 g
237  on every axis). Possible values:
238  ADXL345_RANGE_2G
239  ADXL345_RANGE_4G
240  ADXL345_RANGE_8G
241  ADXL345_RANGE_16G
242  Example:
243  accm_set_grange(ADXL345_RANGE_4G);
244  */
245 
246 void
247 accm_set_grange(uint8_t grange){
248  if(grange > ADXL345_RANGE_16G) {
249  // invalid g-range.
250  PRINTFDEBUG("ADXL grange invalid: %u\n", grange);
251  return;
252  }
253  uint8_t tempreg = 0;
254 
255  /* preserve the previous contents of the register */
256  tempreg = (accm_read_reg(ADXL345_DATA_FORMAT) & 0xFC); // zero out the last two bits (grange)
257  tempreg |= grange; // set new range
258  accm_write_reg(ADXL345_DATA_FORMAT, tempreg);
259 }
260 
261 /*---------------------------------------------------------------------------*/
262 /* Init the accelerometer: ports, pins, registers, interrupts (none enabled), I2C,
263  default threshold values etc. */
264 
265 void
266 accm_init(void) {
267  if(!(_ADXL345_STATUS & INITED)){
268  PRINTFDEBUG("ADXL345 init\n");
269  _ADXL345_STATUS |= INITED;
270  accm_int1_cb = NULL;
271  accm_int2_cb = NULL;
272  int1_event = process_alloc_event();
273  int2_event = process_alloc_event();
274 
275  /* Set up ports and pins for interrups. */
276  ADXL345_DIR &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
277  ADXL345_SEL &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
278  ADXL345_SEL2 &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
279 
280  /* Set up ports and pins for I2C communication */
281  i2c_enable();
282 
283  /* set default register values. */
284  accm_write_stream(15, &adxl345_default_settings[0]);
285  accm_write_stream(5, &adxl345_default_settings[15]);
286  accm_write_reg(ADXL345_DATA_FORMAT, adxl345_default_settings[20]);
287  accm_write_reg(ADXL345_FIFO_CTL, adxl345_default_settings[21]);
288 
289  process_start(&accmeter_process, NULL);
290 
291  /* Enable msp430 interrupts on the two interrupt pins. */
292  dint();
293  ADXL345_IES &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN); // low to high transition interrupts
294  ADXL345_IE |= (ADXL345_INT1_PIN | ADXL345_INT2_PIN); // enable interrupts
295  eint();
296  }
297 }
298 
299 /*---------------------------------------------------------------------------*/
300 /* Map interrupt (FF, tap, dbltap etc) to interrupt pin (IRQ_INT1, IRQ_INT2).
301  This must come after accm_init() as the registers will otherwise be overwritten. */
302 
303 void
304 accm_set_irq(uint8_t int1, uint8_t int2){
305  /* Set the corresponding interrupt mapping to INT1 or INT2 */
306  PRINTFDEBUG("IRQs set to INT1: 0x%02X IRQ2: 0x%02X\n", int1, int2);
307 
308  int1_mask = int1;
309  int2_mask = int2;
310 
311  accm_write_reg(ADXL345_INT_ENABLE, (int1 | int2));
312  accm_write_reg(ADXL345_INT_MAP, int2); // int1 bits are zeroes in the map register so this is for both ints
313 }
314 
315 /*---------------------------------------------------------------------------*/
316 #if 0
317 /* now unused code that is later supposed to be turned into keeping track of every
318  interrupt by themselves instead of only one per INT1/2 */
319 
320 /* XXX MUST HAVE some way of resetting the time so that we are not suppressing
321  erronous due to clock overflow.... XXX XXX XXX */
322 /* Table with back off time periods */
323 static volatile clock_time_t ints_backoffs[] = {ADXL345_INT_OVERRUN_BACKOFF, ADXL345_INT_WATERMARK_BACKOFF,
324  ADXL345_INT_FREEFALL_BACKOFF, ADXL345_INT_INACTIVITY_BACKOFF,
325  ADXL345_INT_ACTIVITY_BACKOFF, ADXL345_INT_DOUBLETAP_BACKOFF,
326  ADXL345_INT_TAP_BACKOFF, ADXL345_INT_DATAREADY_BACKOFF};
327 
328 /*---------------------------------------------------------------------------*/
329 /* Checks to see if an event occurred after backoff period (returns time period
330  past since) or not (returns 0) */
331 
332 static clocktime_t
333 backoff_passed(clocktime_t happenedAt, const clocktime_t backoff){
334  if(timenow-lasttime >= backoff) {
335  return 0;
336  } else {
337  return (timenow-lasttime);
338  }
339 }
340 #endif
341 /*---------------------------------------------------------------------------*/
342 /* Invoked after an interrupt happened. Reads the interrupt source reg at the
343  accelerometer, which resets the interrupts, and invokes the corresponding
344  callback. It passes the source register value so the callback can determine
345  what interrupt happened, if several interrupts are mapped to the same pin. */
346 
347 static void
348 poll_handler(void){
349  uint8_t ireg = 0;
350  ireg = accm_read_reg(ADXL345_INT_SOURCE);
351  //printf("0x%02X, 0x%02X, 0x%02X, 0x%02X\n", ireg, ireg2, int1_mask, int2_mask);
352 
353  /* Invoke callbacks for the corresponding interrupts */
354  if(ireg & int1_mask){
355  if(accm_int1_cb != NULL){
356  PRINTFDEBUG("INT1 cb invoked\n");
357  accm_int1_cb(ireg);
358  }
359  } else if(ireg & int2_mask){
360  if(accm_int2_cb != NULL){
361  PRINTFDEBUG("INT2 cb invoked\n");
362  accm_int2_cb(ireg);
363  }
364  }
365 }
366 
367 /*---------------------------------------------------------------------------*/
368 /* This process is sleeping until an interrupt from the accelerometer occurs, which
369  polls this process from the interrupt service routine. */
370 
371 PROCESS_THREAD(accmeter_process, ev, data) {
372  PROCESS_POLLHANDLER(poll_handler());
374  PROCESS_BEGIN();
375  while(1){
376  PROCESS_WAIT_EVENT_UNTIL(0); // should do nothing in while loop.
377  }
378  PROCESS_END();
379 }
380 
381 /*---------------------------------------------------------------------------*/
382 /* XXX This interrupt vector is shared with the interrupts from CC1120, so that
383  was moved here but should find a better home. XXX */
384 
385 #if 1
386 static struct timer suppressTimer1, suppressTimer2;
387 
388 ISR(PORT1, port1_isr)
389 {
390  ENERGEST_ON(ENERGEST_TYPE_IRQ);
391  /* ADXL345_IFG.x goes high when interrupt occurs, use to check what interrupted */
392  if ((ADXL345_IFG & ADXL345_INT1_PIN) && !(CC1120_GDO0_PORT(IFG) & BV(CC1120_GDO0_PIN))){
393  /* Check if this should be suppressed or not */
394  if(timer_expired(&suppressTimer1)) {
395  timer_set(&suppressTimer1, SUPPRESS_TIME_INT1);
396  ADXL345_IFG &= ~ADXL345_INT1_PIN; // clear interrupt flag
397  process_poll(&accmeter_process);
398  LPM4_EXIT;
399  }
400  } else if ((ADXL345_IFG & ADXL345_INT2_PIN) && !(CC1120_GDO0_PORT(IFG) & BV(CC1120_GDO0_PIN))){
401  /* Check if this should be suppressed or not */
402  if(timer_expired(&suppressTimer2)) {
403  timer_set(&suppressTimer2, SUPPRESS_TIME_INT2);
404  ADXL345_IFG &= ~ADXL345_INT2_PIN; // clear interrupt flag
405  process_poll(&accmeter_process);
406  LPM4_EXIT;
407  }
408  } else {
409  /* CC1120 interrupt */
410  if(cc1120_interrupt_handler()) {
411  LPM4_EXIT;
412  }
413  }
414  ENERGEST_OFF(ENERGEST_TYPE_IRQ);
415 }
416 
417 /*---------------------------------------------------------------------------*/
418 
419 #endif
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
void timer_set(struct timer *t, clock_time_t interval)
Set a timer.
Definition: timer.c:64
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
A timer.
Definition: timer.h:86
I2C communication device driver header file for Zolertia Z1 sensor node.
#define PROCESS_POLLHANDLER(handler)
Specify an action when a process is polled.
Definition: process.h:242
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition: process.h:157
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:93
#define PROCESS_EXITHANDLER(handler)
Specify an action when a process exits.
Definition: process.h:254
void i2c_enable(void)
Configure serial controller in I2C mode and set I2C speed.
Definition: i2c.c:52
Device drivers header file for adxl345 accelerometer in Zolertia Z1.
#define NULL
The null pointer.
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
int timer_expired(struct timer *t)
Check if a timer has expired.
Definition: timer.c:122
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120