Contiki 2.6
|
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