Contiki 2.6

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