adxl345.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010, Swedish Institute of Computer Science.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * This file is part of the Contiki operating system.
00030  *
00031  */
00032 
00033 /**
00034  * \file
00035  *         Device drivers for adxl345 accelerometer in Zolertia Z1.
00036  * \author
00037  *         Marcus Lundén, SICS <mlunden@sics.se>
00038  *         Enric M. Calvo, Zolertia <ecalvo@zolertia.com>
00039  */
00040 
00041 
00042 #include <stdio.h>
00043 #include <signal.h>
00044 #include "contiki.h"
00045 #include "adxl345.h"
00046 #include "cc2420.h"
00047 #include "i2cmaster.h"
00048 
00049 /* Callback pointers when interrupt occurs */
00050 extern void (*accm_int1_cb)(u8_t reg);
00051 extern void (*accm_int2_cb)(u8_t reg);
00052 
00053 /* Bitmasks for the interrupts */
00054 static uint16_t int1_mask = 0, int2_mask = 0;
00055 
00056 /* Keep track of when the interrupt was last seen in order to reduce the amount
00057   of interrupts. Kind of like button debouncing. This can't be per int-pin, as
00058   there can be several very different int per pin (eg tap && freefall). */
00059 // XXX Not used now, only one global timer.
00060 //static volatile clock_time_t ints_lasttime[] = {0, 0, 0, 0, 0, 0, 0, 0};
00061 
00062 /* Bitmasks and bit flag variable for keeping track of adxl345 status. */
00063 enum ADXL345_STATUSTYPES {
00064     /* must be a bit and not more, not using 0x00. */
00065     INITED = 0x01,
00066     RUNNING = 0x02,
00067     STOPPED = 0x04,
00068     LOW_POWER = 0x08,
00069     AAA = 0x10,   // available to extend this...
00070     BBB = 0x20,   // available to extend this...
00071     CCC = 0x40,   // available to extend this...
00072     DDD = 0x80,   // available to extend this...
00073 };
00074 static enum ADXL345_STATUSTYPES _ADXL345_STATUS = 0x00;
00075 
00076 /* Default values for adxl345 at startup. This will be sent to the adxl345 in a
00077     stream at init to set it up in a default state */
00078 static uint8_t adxl345_default_settings[] = {
00079   /* Note, as the two first two bulks are to be written in a stream, they contain
00080     the register address as first byte in that section. */
00081   /* 0--14 are in one stream, start at ADXL345_THRESH_TAP */
00082   ADXL345_THRESH_TAP,         // XXX NB Register address, not register value!!
00083   ADXL345_THRESH_TAP_DEFAULT,
00084   ADXL345_OFSX_DEFAULT,
00085   ADXL345_OFSY_DEFAULT,
00086   ADXL345_OFSZ_DEFAULT,
00087   ADXL345_DUR_DEFAULT,
00088   ADXL345_LATENT_DEFAULT,
00089   ADXL345_WINDOW_DEFAULT,
00090   ADXL345_THRESH_ACT_DEFAULT,
00091   ADXL345_THRESH_INACT_DEFAULT,
00092   ADXL345_TIME_INACT_DEFAULT,
00093   ADXL345_ACT_INACT_CTL_DEFAULT,
00094   ADXL345_THRESH_FF_DEFAULT,
00095   ADXL345_TIME_FF_DEFAULT,
00096   ADXL345_TAP_AXES_DEFAULT,
00097 
00098   /* 15--19 start at ADXL345_BW_RATE */
00099   ADXL345_BW_RATE,    // XXX NB Register address, not register value!!
00100   ADXL345_BW_RATE_DEFAULT,
00101   ADXL345_POWER_CTL_DEFAULT,
00102   ADXL345_INT_ENABLE_DEFAULT,
00103   ADXL345_INT_MAP_DEFAULT,
00104 
00105   /* These two: 20, 21 write separately */
00106   ADXL345_DATA_FORMAT_DEFAULT,
00107   ADXL345_FIFO_CTL_DEFAULT
00108 };
00109 
00110 
00111 /*---------------------------------------------------------------------------*/
00112 PROCESS(accmeter_process, "Accelerometer process");
00113 /*---------------------------------------------------------------------------*/
00114 /* Write to a register.
00115     args:
00116       reg       register to write to
00117       val       value to write
00118 */
00119 
00120 void
00121 accm_write_reg(u8_t reg, u8_t val) {
00122   u8_t tx_buf[] = {reg, val};
00123 
00124   i2c_transmitinit(ADXL345_ADDR);
00125   while (i2c_busy());
00126   PRINTFDEBUG("I2C Ready to TX\n");
00127 
00128   i2c_transmit_n(2, tx_buf);
00129   while (i2c_busy());
00130   PRINTFDEBUG("WRITE_REG 0x%02X @ reg 0x%02X\n", val, reg);
00131 }
00132 /*---------------------------------------------------------------------------*/
00133 /* Write several registers from a stream.
00134     args:
00135       len       number of bytes to read
00136       data      pointer to where the data is read from
00137 
00138   First byte in stream must be the register address to begin writing to.
00139   The data is then written from second byte and increasing. */
00140 
00141 void
00142 accm_write_stream(u8_t len, u8_t *data) {
00143   i2c_transmitinit(ADXL345_ADDR);
00144   while (i2c_busy());
00145   PRINTFDEBUG("I2C Ready to TX(stream)\n");
00146 
00147   i2c_transmit_n(len, data);    // start tx and send conf reg 
00148   while (i2c_busy());
00149   PRINTFDEBUG("WRITE_STR %u B to 0x%02X\n", len, data[0]);
00150 }
00151 
00152 /*---------------------------------------------------------------------------*/
00153 /* Read one register.
00154     args:
00155       reg       what register to read
00156     returns the value of the read register
00157 */
00158 
00159 u8_t
00160 accm_read_reg(u8_t reg) {
00161   u8_t retVal = 0;
00162   u8_t rtx = reg;
00163   PRINTFDEBUG("READ_REG 0x%02X\n", reg);
00164 
00165   /* transmit the register to read */
00166   i2c_transmitinit(ADXL345_ADDR);
00167   while (i2c_busy());
00168   i2c_transmit_n(1, &rtx);
00169   while (i2c_busy());
00170 
00171   /* receive the data */
00172   i2c_receiveinit(ADXL345_ADDR);
00173   while (i2c_busy());
00174   i2c_receive_n(1, &retVal);
00175   while (i2c_busy());
00176 
00177   return retVal;
00178 }
00179 
00180 /*---------------------------------------------------------------------------*/
00181 /* Read several registers in a stream.
00182     args:
00183       reg       what register to start reading from
00184       len       number of bytes to read
00185       whereto   pointer to where the data is saved
00186 */
00187 
00188 void
00189 accm_read_stream(u8_t reg, u8_t len, u8_t *whereto) {
00190   u8_t rtx = reg;
00191   PRINTFDEBUG("READ_STR %u B from 0x%02X\n", len, reg);
00192 
00193   /* transmit the register to start reading from */
00194   i2c_transmitinit(ADXL345_ADDR);
00195   while (i2c_busy());
00196   i2c_transmit_n(1, &rtx);
00197   while (i2c_busy());
00198 
00199   /* receive the data */
00200   i2c_receiveinit(ADXL345_ADDR);
00201   while (i2c_busy());
00202   i2c_receive_n(len, whereto);
00203   while (i2c_busy());
00204 }
00205 
00206 /*---------------------------------------------------------------------------*/
00207 /* Read an axis of the accelerometer (x, y or z). Return value is a signed 10 bit int.
00208   The resolution of the acceleration measurement can be increased up to 13 bit, but
00209   will change the data format of this read out. Refer to the data sheet if so is
00210   wanted/needed. */
00211 
00212 int16_t
00213 accm_read_axis(enum ADXL345_AXIS axis){
00214   int16_t rd = 0;
00215   u8_t tmp[2];
00216   if(axis > Z_AXIS){
00217     return 0;
00218   }
00219   accm_read_stream(ADXL345_DATAX0 + axis, 2, &tmp[0]);
00220   rd = (int16_t)(tmp[0] | (tmp[1]<<8));  
00221   return rd;
00222 }
00223 
00224 /*---------------------------------------------------------------------------*/
00225 /* Sets the g-range, ie the range the accelerometer measures (ie 2g means -2 to +2 g
00226     on every axis). Possible values:
00227         ADXL345_RANGE_2G
00228         ADXL345_RANGE_4G
00229         ADXL345_RANGE_8G
00230         ADXL345_RANGE_16G
00231     Example:
00232         accm_set_grange(ADXL345_RANGE_4G);
00233     */
00234 
00235 void
00236 accm_set_grange(u8_t grange){
00237   if(grange > ADXL345_RANGE_16G) {
00238     // invalid g-range.
00239     PRINTFDEBUG("ADXL grange invalid: %u\n", grange);
00240     return;
00241   }
00242   u8_t tempreg = 0;
00243 
00244   /* preserve the previous contents of the register */
00245   tempreg = (accm_read_reg(ADXL345_DATA_FORMAT) & 0xFC);  // zero out the last two bits (grange)
00246   tempreg |= grange;                                      // set new range
00247   accm_write_reg(ADXL345_DATA_FORMAT, tempreg);
00248 }
00249 
00250 /*---------------------------------------------------------------------------*/
00251 /* Init the accelerometer: ports, pins, registers, interrupts (none enabled), I2C,
00252     default threshold values etc. */
00253 
00254 void
00255 accm_init(void) {
00256   if(!(_ADXL345_STATUS & INITED)){
00257     PRINTFDEBUG("ADXL345 init\n");
00258     _ADXL345_STATUS |= INITED;
00259     accm_int1_cb = NULL;
00260     accm_int2_cb = NULL;
00261     int1_event = process_alloc_event();
00262     int2_event = process_alloc_event();
00263 
00264     /* Set up ports and pins for interrups. */
00265     ADXL345_DIR  &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
00266     ADXL345_SEL  &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
00267     ADXL345_SEL2 &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
00268 
00269     /* Set up ports and pins for I2C communication */
00270     i2c_enable();
00271 
00272     /* set default register values. */
00273     accm_write_stream(15, &adxl345_default_settings[0]);
00274     accm_write_stream(5, &adxl345_default_settings[15]);
00275     accm_write_reg(ADXL345_DATA_FORMAT, adxl345_default_settings[20]);
00276     accm_write_reg(ADXL345_FIFO_CTL, adxl345_default_settings[21]);
00277 
00278     process_start(&accmeter_process, NULL);
00279 
00280     /* Enable msp430 interrupts on the two interrupt pins. */
00281     dint();
00282     ADXL345_IES &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);   // low to high transition interrupts
00283     ADXL345_IE |= (ADXL345_INT1_PIN | ADXL345_INT2_PIN);     // enable interrupts
00284     eint();
00285   }
00286 }
00287 
00288 /*---------------------------------------------------------------------------*/
00289 /* Map interrupt (FF, tap, dbltap etc) to interrupt pin (IRQ_INT1, IRQ_INT2).
00290     This must come after accm_init() as the registers will otherwise be overwritten. */
00291     
00292 void
00293 accm_set_irq(uint8_t int1, uint8_t int2){
00294   /* Set the corresponding interrupt mapping to INT1 or INT2 */
00295   PRINTFDEBUG("IRQs set to INT1: 0x%02X IRQ2: 0x%02X\n", int1, int2);
00296 
00297   int1_mask = int1;
00298   int2_mask = int2;
00299 
00300   accm_write_reg(ADXL345_INT_ENABLE, (int1 | int2));
00301   accm_write_reg(ADXL345_INT_MAP, int2);  // int1 bits are zeroes in the map register so this is for both ints
00302 }
00303 
00304 /*---------------------------------------------------------------------------*/
00305 #if 0
00306 /* now unused code that is later supposed to be turned into keeping track of every
00307     interrupt by themselves instead of only one per INT1/2 */
00308 
00309 /* XXX MUST HAVE some way of resetting the time so that we are not suppressing
00310         erronous due to clock overflow.... XXX XXX XXX */
00311 /* Table with back off time periods */
00312 static volatile clock_time_t ints_backoffs[] = {ADXL345_INT_OVERRUN_BACKOFF, ADXL345_INT_WATERMARK_BACKOFF,
00313                                                 ADXL345_INT_FREEFALL_BACKOFF, ADXL345_INT_INACTIVITY_BACKOFF,
00314                                                 ADXL345_INT_ACTIVITY_BACKOFF, ADXL345_INT_DOUBLETAP_BACKOFF,
00315                                                 ADXL345_INT_TAP_BACKOFF, ADXL345_INT_DATAREADY_BACKOFF};
00316 
00317 /*---------------------------------------------------------------------------*/
00318 /* Checks to see if an event occurred after backoff period (returns time period
00319     past since) or not (returns 0) */
00320 
00321 static clocktime_t
00322 backoff_passed(clocktime_t happenedAt, const clocktime_t backoff){
00323   if(timenow-lasttime >= backoff) {
00324     return 0;
00325   } else {
00326     return (timenow-lasttime);
00327   }
00328 }
00329 #endif
00330 /*---------------------------------------------------------------------------*/
00331 /* Invoked after an interrupt happened. Reads the interrupt source reg at the
00332   accelerometer, which resets the interrupts, and invokes the corresponding
00333   callback. It passes the source register value so the callback can determine
00334   what interrupt happened, if several interrupts are mapped to the same pin. */
00335 
00336 static void
00337 poll_handler(void){
00338   uint8_t ireg = 0;
00339   ireg = accm_read_reg(ADXL345_INT_SOURCE);
00340   //printf("0x%02X, 0x%02X, 0x%02X, 0x%02X\n", ireg, ireg2, int1_mask, int2_mask);
00341 
00342   /* Invoke callbacks for the corresponding interrupts */
00343   if(ireg & int1_mask){
00344     if(accm_int1_cb != NULL){
00345       PRINTFDEBUG("INT1 cb invoked\n");
00346       accm_int1_cb(ireg);
00347     }
00348   } else if(ireg & int2_mask){
00349     if(accm_int2_cb != NULL){
00350       PRINTFDEBUG("INT2 cb invoked\n");
00351       accm_int2_cb(ireg);
00352     }
00353   }
00354 }
00355 
00356 /*---------------------------------------------------------------------------*/
00357 /* This process is sleeping until an interrupt from the accelerometer occurs, which
00358     polls this process from the interrupt service routine. */
00359 
00360 PROCESS_THREAD(accmeter_process, ev, data) {
00361   PROCESS_POLLHANDLER(poll_handler());
00362   PROCESS_EXITHANDLER();
00363   PROCESS_BEGIN();
00364   while(1){
00365     PROCESS_WAIT_EVENT_UNTIL(0);    // should do nothing in while loop.
00366   }
00367   PROCESS_END();
00368 }
00369 
00370 /*---------------------------------------------------------------------------*/
00371 /* XXX This interrupt vector is shared with the interrupts from CC2420, so that
00372   was moved here but should find a better home. XXX */
00373 
00374 #if 1
00375 static struct timer suppressTimer1, suppressTimer2;
00376 
00377 interrupt(PORT1_VECTOR) port1_isr (void) {
00378   ENERGEST_ON(ENERGEST_TYPE_IRQ);
00379   /* ADXL345_IFG.x goes high when interrupt occurs, use to check what interrupted */
00380   if ((ADXL345_IFG & ADXL345_INT1_PIN) && !(ADXL345_IFG & BV(CC2420_FIFOP_PIN))){
00381     /* Check if this should be suppressed or not */
00382     if(timer_expired(&suppressTimer1)) {
00383       timer_set(&suppressTimer1, SUPPRESS_TIME_INT1);
00384       ADXL345_IFG &= ~ADXL345_INT1_PIN;   // clear interrupt flag
00385       process_poll(&accmeter_process);
00386       LPM4_EXIT;
00387     }
00388   } else if ((ADXL345_IFG & ADXL345_INT2_PIN) && !(ADXL345_IFG & BV(CC2420_FIFOP_PIN))){
00389     /* Check if this should be suppressed or not */
00390     if(timer_expired(&suppressTimer2)) {
00391       timer_set(&suppressTimer2, SUPPRESS_TIME_INT2);
00392       ADXL345_IFG &= ~ADXL345_INT2_PIN;   // clear interrupt flag
00393       process_poll(&accmeter_process);
00394       LPM4_EXIT;
00395     }
00396   } else {
00397     /* CC2420 interrupt */
00398     if(cc2420_interrupt()) {
00399       LPM4_EXIT;
00400     }
00401   }
00402   ENERGEST_OFF(ENERGEST_TYPE_IRQ);
00403 }
00404 
00405 /*---------------------------------------------------------------------------*/
00406 
00407 #endif

Generated on Mon Apr 11 14:23:45 2011 for Contiki 2.5 by  doxygen 1.6.1