Merge pull request #1523 from Zolertia/pull/z1-apify-sensors

Adapt Z1 on-board sensors to Contiki's API
This commit is contained in:
Nicolas Tsiftes 2016-03-14 17:10:46 +01:00
commit 862e43d9b0
6 changed files with 442 additions and 511 deletions

View file

@ -42,10 +42,7 @@
#include <stdio.h> #include <stdio.h>
#include "contiki.h" #include "contiki.h"
#include "serial-shell.h" #include "dev/leds.h"
#include "shell-ps.h"
#include "shell-file.h"
#include "shell-text.h"
#include "dev/adxl345.h" #include "dev/adxl345.h"
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#define LED_INT_ONTIME (CLOCK_SECOND / 2) #define LED_INT_ONTIME (CLOCK_SECOND / 2)
@ -91,7 +88,7 @@ print_int(uint16_t reg)
void void
accm_ff_cb(uint8_t reg) accm_ff_cb(uint8_t reg)
{ {
L_ON(LEDS_B); leds_on(LEDS_BLUE);
process_post(&led_process, led_off_event, NULL); process_post(&led_process, led_off_event, NULL);
printf("~~[%u] Freefall detected! (0x%02X) -- ", printf("~~[%u] Freefall detected! (0x%02X) -- ",
((uint16_t)clock_time()) / 128, reg); ((uint16_t)clock_time()) / 128, reg);
@ -105,11 +102,11 @@ accm_tap_cb(uint8_t reg)
{ {
process_post(&led_process, led_off_event, NULL); process_post(&led_process, led_off_event, NULL);
if(reg & ADXL345_INT_DOUBLETAP) { if(reg & ADXL345_INT_DOUBLETAP) {
L_ON(LEDS_G); leds_on(LEDS_GREEN);
printf("~~[%u] DoubleTap detected! (0x%02X) -- ", printf("~~[%u] DoubleTap detected! (0x%02X) -- ",
((uint16_t)clock_time()) / 128, reg); ((uint16_t)clock_time()) / 128, reg);
} else { } else {
L_ON(LEDS_R); leds_on(LEDS_RED);
printf("~~[%u] Tap detected! (0x%02X) -- ", printf("~~[%u] Tap detected! (0x%02X) -- ",
((uint16_t)clock_time()) / 128, reg); ((uint16_t)clock_time()) / 128, reg);
} }
@ -122,46 +119,46 @@ PROCESS_THREAD(led_process, ev, data) {
PROCESS_WAIT_EVENT_UNTIL(ev == led_off_event); PROCESS_WAIT_EVENT_UNTIL(ev == led_off_event);
etimer_set(&led_etimer, LED_INT_ONTIME); etimer_set(&led_etimer, LED_INT_ONTIME);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&led_etimer)); PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&led_etimer));
L_OFF(LEDS_R + LEDS_G + LEDS_B); leds_off(LEDS_RED + LEDS_GREEN + LEDS_BLUE);
} }
PROCESS_END(); PROCESS_END();
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Main process, setups */ /* Main process, setups */
PROCESS_THREAD(accel_process, ev, data) { PROCESS_THREAD(accel_process, ev, data)
{
PROCESS_BEGIN(); PROCESS_BEGIN();
{
int16_t x, y, z;
serial_shell_init(); int16_t x, y, z;
shell_ps_init();
shell_file_init(); /* for printing out files */
shell_text_init(); /* for binprint */
/* Register the event used for lighting up an LED when interrupt strikes. */ /* Register the event used for lighting up an LED when interrupt strikes. */
led_off_event = process_alloc_event(); led_off_event = process_alloc_event();
/* Start and setup the accelerometer with default values, eg no interrupts enabled. */ /* Start and setup the accelerometer with default values, eg no interrupts
accm_init(); * enabled.
*/
SENSORS_ACTIVATE(adxl345);
/* Register the callback functions for each interrupt */ /* Register the callback functions for each interrupt */
ACCM_REGISTER_INT1_CB(accm_ff_cb); ACCM_REGISTER_INT1_CB(accm_ff_cb);
ACCM_REGISTER_INT2_CB(accm_tap_cb); ACCM_REGISTER_INT2_CB(accm_tap_cb);
/* Set what strikes the corresponding interrupts. Several interrupts per pin is /* Set what strikes the corresponding interrupts. Several interrupts per
possible. For the eight possible interrupts, see adxl345.h and adxl345 datasheet. */ * pin is possible. For the eight possible interrupts, see adxl345.h and
* adxl345 datasheet.
*/
accm_set_irq(ADXL345_INT_FREEFALL, ADXL345_INT_TAP + ADXL345_INT_DOUBLETAP); accm_set_irq(ADXL345_INT_FREEFALL, ADXL345_INT_TAP + ADXL345_INT_DOUBLETAP);
while(1) { while(1) {
x = accm_read_axis(X_AXIS); x = adxl345.value(X_AXIS);
y = accm_read_axis(Y_AXIS); y = adxl345.value(Y_AXIS);
z = accm_read_axis(Z_AXIS); z = adxl345.value(Z_AXIS);
printf("x: %d y: %d z: %d\n", x, y, z); printf("x: %d y: %d z: %d\n", x, y, z);
etimer_set(&et, ACCM_READ_INTERVAL); etimer_set(&et, ACCM_READ_INTERVAL);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
} }
}
PROCESS_END(); PROCESS_END();
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, Zolertia(TM) is a trademark of Advancare,SL * Copyright (c) 2010-2016, Zolertia <http://www.zolertia.com>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -32,9 +32,10 @@
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/** /**
* \file * \file
* A quick program for testing the tmp102 driver in the Z1 platform * A quick program for testing the tmp102 sensor in the Z1 platform
* \author * \author
* Enric M. Calvo <ecalvo@zolertia.com> * Enric M. Calvo <ecalvo@zolertia.com>
* Antonio Lignan <alinan@zolertia.com>
*/ */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#include <stdio.h> #include <stdio.h>
@ -44,7 +45,7 @@
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#define TMP102_READ_INTERVAL (CLOCK_SECOND / 2) #define TMP102_READ_INTERVAL (CLOCK_SECOND / 2)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
PROCESS(temp_process, "Test Temperature process"); PROCESS(temp_process, "TMP102 Temperature sensor process");
AUTOSTART_PROCESSES(&temp_process); AUTOSTART_PROCESSES(&temp_process);
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static struct etimer et; static struct etimer et;
@ -55,12 +56,12 @@ PROCESS_THREAD(temp_process, ev, data)
int16_t temp; int16_t temp;
tmp102_init(); SENSORS_ACTIVATE(tmp102);
while(1) { while(1) {
etimer_set(&et, TMP102_READ_INTERVAL); etimer_set(&et, TMP102_READ_INTERVAL);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
temp = tmp102_read_temp_x100(); temp = tmp102.value(TMP102_READ);
printf("Temp = %d\n", temp); printf("Temp = %d\n", temp);
} }
PROCESS_END(); PROCESS_END();

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2010, Swedish Institute of Computer Science. * Copyright (c) 2010, Swedish Institute of Computer Science.
* Copyright (c) 2016, Zolertia <http://www.zolertia.com>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -29,59 +30,52 @@
* This file is part of the Contiki operating system. * This file is part of the Contiki operating system.
* *
*/ */
/*---------------------------------------------------------------------------*/
/** /**
* \file * \file
* Device drivers for adxl345 accelerometer in Zolertia Z1. * Device drivers for adxl345 accelerometer in Zolertia Z1.
* \author * \author
* Marcus Lundén, SICS <mlunden@sics.se> * Marcus Lundén, SICS <mlunden@sics.se>
* Enric M. Calvo, Zolertia <ecalvo@zolertia.com> * Enric M. Calvo, Zolertia <ecalvo@zolertia.com>
* Antonio Lignan, Zolertia <alinan@zolertia.com>
*/ */
/*---------------------------------------------------------------------------*/
#include <stdio.h> #include <stdio.h>
#include "contiki.h" #include "contiki.h"
#include "adxl345.h" #include "adxl345.h"
#include "cc2420.h" #include "cc2420.h"
#include "i2cmaster.h" #include "i2cmaster.h"
#include "isr_compat.h" #include "isr_compat.h"
#include "lib/sensors.h"
/*---------------------------------------------------------------------------*/
#define DEBUG 0
#if DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
/*---------------------------------------------------------------------------*/
static uint8_t enabled;
/*---------------------------------------------------------------------------*/
/* Callback pointers when interrupt occurs */ /* Callback pointers when interrupt occurs */
void (*accm_int1_cb)(uint8_t reg); void (*accm_int1_cb)(uint8_t reg);
void (*accm_int2_cb)(uint8_t reg); void (*accm_int2_cb)(uint8_t reg);
/*---------------------------------------------------------------------------*/
process_event_t int1_event, int2_event;
/* Bitmasks for the interrupts */ /* Bitmasks for the interrupts */
static uint16_t int1_mask = 0, int2_mask = 0; static uint16_t int1_mask = 0, int2_mask = 0;
/* Keep track of when the interrupt was last seen in order to reduce the amount /* Default values for adxl345 at startup.
of interrupts. Kind of like button debouncing. This can't be per int-pin, as * This will be sent to the adxl345 in a
there can be several very different int per pin (eg tap && freefall). */ * stream at init to set it up in a default state
// XXX Not used now, only one global timer. */
//static volatile clock_time_t ints_lasttime[] = {0, 0, 0, 0, 0, 0, 0, 0};
/* Bitmasks and bit flag variable for keeping track of adxl345 status. */
enum ADXL345_STATUSTYPES {
/* must be a bit and not more, not using 0x00. */
INITED = 0x01,
RUNNING = 0x02,
STOPPED = 0x04,
LOW_POWER = 0x08,
AAA = 0x10, // available to extend this...
BBB = 0x20, // available to extend this...
CCC = 0x40, // available to extend this...
DDD = 0x80, // available to extend this...
};
static enum ADXL345_STATUSTYPES _ADXL345_STATUS = 0x00;
/* Default values for adxl345 at startup. This will be sent to the adxl345 in a
stream at init to set it up in a default state */
static uint8_t adxl345_default_settings[] = { static uint8_t adxl345_default_settings[] = {
/* Note, as the two first two bulks are to be written in a stream, they contain /* Note, as the two first two bulks are to be written in a stream, they contain
the register address as first byte in that section. */ * the register address as first byte in that section.
/* 0--14 are in one stream, start at ADXL345_THRESH_TAP */ * 0--14 are in one stream, start at ADXL345_THRESH_TAP
ADXL345_THRESH_TAP, // XXX NB Register address, not register value!! */
/* XXX NB Register address, not register value!! */
ADXL345_THRESH_TAP,
ADXL345_THRESH_TAP_DEFAULT, ADXL345_THRESH_TAP_DEFAULT,
ADXL345_OFSX_DEFAULT, ADXL345_OFSX_DEFAULT,
ADXL345_OFSY_DEFAULT, ADXL345_OFSY_DEFAULT,
@ -98,7 +92,8 @@ static uint8_t adxl345_default_settings[] = {
ADXL345_TAP_AXES_DEFAULT, ADXL345_TAP_AXES_DEFAULT,
/* 15--19 start at ADXL345_BW_RATE */ /* 15--19 start at ADXL345_BW_RATE */
ADXL345_BW_RATE, // XXX NB Register address, not register value!! /* XXX NB Register address, not register value!! */
ADXL345_BW_RATE,
ADXL345_BW_RATE_DEFAULT, ADXL345_BW_RATE_DEFAULT,
ADXL345_POWER_CTL_DEFAULT, ADXL345_POWER_CTL_DEFAULT,
ADXL345_INT_ENABLE_DEFAULT, ADXL345_INT_ENABLE_DEFAULT,
@ -108,61 +103,45 @@ static uint8_t adxl345_default_settings[] = {
ADXL345_DATA_FORMAT_DEFAULT, ADXL345_DATA_FORMAT_DEFAULT,
ADXL345_FIFO_CTL_DEFAULT ADXL345_FIFO_CTL_DEFAULT
}; };
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
PROCESS(accmeter_process, "Accelerometer process"); PROCESS(accmeter_process, "Accelerometer process");
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Write to a register. static void
args: accm_write_reg(uint8_t reg, uint8_t val)
reg register to write to {
val value to write
*/
void
accm_write_reg(uint8_t reg, uint8_t val) {
uint8_t tx_buf[] = {reg, val}; uint8_t tx_buf[] = {reg, val};
i2c_transmitinit(ADXL345_ADDR); i2c_transmitinit(ADXL345_ADDR);
while (i2c_busy()); while (i2c_busy());
PRINTFDEBUG("I2C Ready to TX\n"); PRINTF("ADXL345: I2C Ready to TX\n");
i2c_transmit_n(2, tx_buf); i2c_transmit_n(2, tx_buf);
while (i2c_busy()); while (i2c_busy());
PRINTFDEBUG("WRITE_REG 0x%02X @ reg 0x%02X\n", val, reg); PRINTF("ADXL345: WRITE_REG 0x%02X @ reg 0x%02X\n", val, reg);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Write several registers from a stream. /* First byte in stream must be the register address to begin writing to.
args: * The data is then written from second byte and increasing.
len number of bytes to read */
data pointer to where the data is read from static void
accm_write_stream(uint8_t len, uint8_t *data)
First byte in stream must be the register address to begin writing to. {
The data is then written from second byte and increasing. */
void
accm_write_stream(uint8_t len, uint8_t *data) {
i2c_transmitinit(ADXL345_ADDR); i2c_transmitinit(ADXL345_ADDR);
while (i2c_busy()); while (i2c_busy());
PRINTFDEBUG("I2C Ready to TX(stream)\n"); PRINTF("ADXL345: I2C Ready to TX(stream)\n");
i2c_transmit_n(len, data); // start tx and send conf reg i2c_transmit_n(len, data); // start tx and send conf reg
while (i2c_busy()); while (i2c_busy());
PRINTFDEBUG("WRITE_STR %u B to 0x%02X\n", len, data[0]); PRINTF("ADXL345: WRITE_STR %u B to 0x%02X\n", len, data[0]);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Read one register. static uint8_t
args: accm_read_reg(uint8_t reg)
reg what register to read {
returns the value of the read register
*/
uint8_t
accm_read_reg(uint8_t reg) {
uint8_t retVal = 0; uint8_t retVal = 0;
uint8_t rtx = reg; uint8_t rtx = reg;
PRINTFDEBUG("READ_REG 0x%02X\n", reg); PRINTF("ADXL345: READ_REG 0x%02X\n", reg);
/* transmit the register to read */ /* transmit the register to read */
i2c_transmitinit(ADXL345_ADDR); i2c_transmitinit(ADXL345_ADDR);
@ -178,19 +157,12 @@ accm_read_reg(uint8_t reg) {
return retVal; return retVal;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Read several registers in a stream. static void
args: accm_read_stream(uint8_t reg, uint8_t len, uint8_t *whereto)
reg what register to start reading from {
len number of bytes to read
whereto pointer to where the data is saved
*/
void
accm_read_stream(uint8_t reg, uint8_t len, uint8_t *whereto) {
uint8_t rtx = reg; uint8_t rtx = reg;
PRINTFDEBUG("READ_STR %u B from 0x%02X\n", len, reg); PRINTF("ADXL345: READ_STR %u B from 0x%02X\n", len, reg);
/* transmit the register to start reading from */ /* transmit the register to start reading from */
i2c_transmitinit(ADXL345_ADDR); i2c_transmitinit(ADXL345_ADDR);
@ -206,13 +178,15 @@ accm_read_stream(uint8_t reg, uint8_t len, uint8_t *whereto) {
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Read an axis of the accelerometer (x, y or z). Return value is a signed 10 bit int. /* Read an axis of the accelerometer (x, y or z). Return value is a signed
The resolution of the acceleration measurement can be increased up to 13 bit, but * 10 bit int.
will change the data format of this read out. Refer to the data sheet if so is * The resolution of the acceleration measurement can be increased up to 13 bit,
wanted/needed. */ * but will change the data format of this read out. Refer to the data sheet if
* so is wanted/needed.
*/
int16_t int16_t
accm_read_axis(enum ADXL345_AXIS axis){ accm_read_axis(enum ADXL345_AXIS axis)
{
int16_t rd = 0; int16_t rd = 0;
uint8_t tmp[2]; uint8_t tmp[2];
if(axis > Z_AXIS){ if(axis > Z_AXIS){
@ -222,46 +196,35 @@ accm_read_axis(enum ADXL345_AXIS axis){
rd = (int16_t)(tmp[0] | (tmp[1]<<8)); rd = (int16_t)(tmp[0] | (tmp[1]<<8));
return rd; return rd;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Sets the g-range, ie the range the accelerometer measures (ie 2g means -2 to +2 g int
on every axis). Possible values: accm_set_grange(uint8_t grange)
ADXL345_RANGE_2G {
ADXL345_RANGE_4G
ADXL345_RANGE_8G
ADXL345_RANGE_16G
Example:
accm_set_grange(ADXL345_RANGE_4G);
*/
void
accm_set_grange(uint8_t grange){
if(grange > ADXL345_RANGE_16G) {
// invalid g-range.
PRINTFDEBUG("ADXL grange invalid: %u\n", grange);
return;
}
uint8_t tempreg = 0; uint8_t tempreg = 0;
/* preserve the previous contents of the register */ if(grange > ADXL345_RANGE_16G) {
tempreg = (accm_read_reg(ADXL345_DATA_FORMAT) & 0xFC); // zero out the last two bits (grange) PRINTF("ADXL345: grange invalid: %u\n", grange);
tempreg |= grange; // set new range return ADXL345_ERROR;
}
if(!enabled) {
return ADXL345_ERROR;
}
/* Keep the previous contents of the register, zero out the last two bits */
tempreg = (accm_read_reg(ADXL345_DATA_FORMAT) & 0xFC);
tempreg |= grange;
accm_write_reg(ADXL345_DATA_FORMAT, tempreg); accm_write_reg(ADXL345_DATA_FORMAT, tempreg);
return ADXL345_SUCCESS;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Init the accelerometer: ports, pins, registers, interrupts (none enabled), I2C,
default threshold values etc. */
void void
accm_init(void) { accm_init(void)
if(!(_ADXL345_STATUS & INITED)){ {
PRINTFDEBUG("ADXL345 init\n"); PRINTF("ADXL345: init\n");
_ADXL345_STATUS |= INITED;
accm_int1_cb = NULL; accm_int1_cb = NULL;
accm_int2_cb = NULL; accm_int2_cb = NULL;
int1_event = process_alloc_event();
int2_event = process_alloc_event();
/* Set up ports and pins for interrups. */ /* Set up ports and pins for interrups. */
ADXL345_DIR &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN); ADXL345_DIR &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
@ -281,106 +244,96 @@ accm_init(void) {
/* Enable msp430 interrupts on the two interrupt pins. */ /* Enable msp430 interrupts on the two interrupt pins. */
dint(); dint();
ADXL345_IES &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN); // low to high transition interrupts /* low to high transition interrupts */
ADXL345_IE |= (ADXL345_INT1_PIN | ADXL345_INT2_PIN); // enable interrupts ADXL345_IES &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
/* enable interrupts */
ADXL345_IE |= (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
eint(); eint();
}
enabled = 1;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Map interrupt (FF, tap, dbltap etc) to interrupt pin (IRQ_INT1, IRQ_INT2).
This must come after accm_init() as the registers will otherwise be overwritten. */
void void
accm_set_irq(uint8_t int1, uint8_t int2){ accm_stop(void)
{
dint();
ADXL345_IE &= ~(ADXL345_INT1_PIN | ADXL345_INT2_PIN);
accm_write_reg(ADXL345_INT_ENABLE, ~(int1_mask | int2_mask));
accm_write_reg(ADXL345_INT_MAP, ~int2_mask);
eint();
enabled = 0;
}
/*---------------------------------------------------------------------------*/
int
accm_set_irq(uint8_t int1, uint8_t int2)
{
if(!enabled) {
return ADXL345_ERROR;
}
/* Set the corresponding interrupt mapping to INT1 or INT2 */ /* Set the corresponding interrupt mapping to INT1 or INT2 */
PRINTFDEBUG("IRQs set to INT1: 0x%02X IRQ2: 0x%02X\n", int1, int2); PRINTF("ADXL345: IRQs set to INT1: 0x%02X IRQ2: 0x%02X\n", int1, int2);
int1_mask = int1; int1_mask = int1;
int2_mask = int2; int2_mask = int2;
accm_write_reg(ADXL345_INT_ENABLE, (int1 | int2)); accm_write_reg(ADXL345_INT_ENABLE, (int1 | int2));
accm_write_reg(ADXL345_INT_MAP, int2); // int1 bits are zeroes in the map register so this is for both ints /* int1 bits are zeroes in the map register so this is for both ints */
accm_write_reg(ADXL345_INT_MAP, int2);
return ADXL345_SUCCESS;
} }
/*---------------------------------------------------------------------------*/
#if 0
/* now unused code that is later supposed to be turned into keeping track of every
interrupt by themselves instead of only one per INT1/2 */
/* XXX MUST HAVE some way of resetting the time so that we are not suppressing
erronous due to clock overflow.... XXX XXX XXX */
/* Table with back off time periods */
static volatile clock_time_t ints_backoffs[] = {ADXL345_INT_OVERRUN_BACKOFF, ADXL345_INT_WATERMARK_BACKOFF,
ADXL345_INT_FREEFALL_BACKOFF, ADXL345_INT_INACTIVITY_BACKOFF,
ADXL345_INT_ACTIVITY_BACKOFF, ADXL345_INT_DOUBLETAP_BACKOFF,
ADXL345_INT_TAP_BACKOFF, ADXL345_INT_DATAREADY_BACKOFF};
/*---------------------------------------------------------------------------*/
/* Checks to see if an event occurred after backoff period (returns time period
past since) or not (returns 0) */
static clocktime_t
backoff_passed(clocktime_t happenedAt, const clocktime_t backoff){
if(timenow-lasttime >= backoff) {
return 0;
} else {
return (timenow-lasttime);
}
}
#endif
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Invoked after an interrupt happened. Reads the interrupt source reg at the /* Invoked after an interrupt happened. Reads the interrupt source reg at the
accelerometer, which resets the interrupts, and invokes the corresponding * accelerometer, which resets the interrupts, and invokes the corresponding
callback. It passes the source register value so the callback can determine * callback. It passes the source register value so the callback can determine
what interrupt happened, if several interrupts are mapped to the same pin. */ * what interrupt happened, if several interrupts are mapped to the same pin.
*/
static void static void
poll_handler(void){ poll_handler(void)
{
uint8_t ireg = 0; uint8_t ireg = 0;
ireg = accm_read_reg(ADXL345_INT_SOURCE); ireg = accm_read_reg(ADXL345_INT_SOURCE);
//printf("0x%02X, 0x%02X, 0x%02X, 0x%02X\n", ireg, ireg2, int1_mask, int2_mask);
/* Invoke callbacks for the corresponding interrupts */ /* Invoke callbacks for the corresponding interrupts */
if(ireg & int1_mask){ if(ireg & int1_mask){
if(accm_int1_cb != NULL){ if(accm_int1_cb != NULL){
PRINTFDEBUG("INT1 cb invoked\n"); PRINTF("ADXL345: INT1 cb invoked\n");
accm_int1_cb(ireg); accm_int1_cb(ireg);
} }
} else if(ireg & int2_mask){ } else if(ireg & int2_mask){
if(accm_int2_cb != NULL){ if(accm_int2_cb != NULL){
PRINTFDEBUG("INT2 cb invoked\n"); PRINTF("ADXL345: INT2 cb invoked\n");
accm_int2_cb(ireg); accm_int2_cb(ireg);
} }
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* This process is sleeping until an interrupt from the accelerometer occurs, which /* This process is sleeping until an interrupt from the accelerometer occurs,
polls this process from the interrupt service routine. */ * which polls this process from the interrupt service routine. */
PROCESS_THREAD(accmeter_process, ev, data)
PROCESS_THREAD(accmeter_process, ev, data) { {
PROCESS_POLLHANDLER(poll_handler()); PROCESS_POLLHANDLER(poll_handler());
PROCESS_EXITHANDLER(); PROCESS_EXITHANDLER();
PROCESS_BEGIN(); PROCESS_BEGIN();
while(1){ while(1){
PROCESS_WAIT_EVENT_UNTIL(0); // should do nothing in while loop. PROCESS_WAIT_EVENT_UNTIL(0);
} }
PROCESS_END(); PROCESS_END();
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* XXX This interrupt vector is shared with the interrupts from CC2420, so that /* This interrupt vector is shared with the interrupts from CC2420, so that
was moved here but should find a better home. XXX */ * was moved here
*/
#if 1
static struct timer suppressTimer1, suppressTimer2; static struct timer suppressTimer1, suppressTimer2;
ISR(PORT1, port1_isr) ISR(PORT1, port1_isr)
{ {
ENERGEST_ON(ENERGEST_TYPE_IRQ); ENERGEST_ON(ENERGEST_TYPE_IRQ);
/* ADXL345_IFG.x goes high when interrupt occurs, use to check what interrupted */
if ((ADXL345_IFG & ADXL345_INT1_PIN) && !(ADXL345_IFG & BV(CC2420_FIFOP_PIN))){ /* ADXL345_IFG.x goes high when interrupt occurs, use to check what
* interrupted
*/
if((ADXL345_IFG & ADXL345_INT1_PIN) && !(ADXL345_IFG & BV(CC2420_FIFOP_PIN))){
/* Check if this should be suppressed or not */ /* Check if this should be suppressed or not */
if(timer_expired(&suppressTimer1)) { if(timer_expired(&suppressTimer1)) {
timer_set(&suppressTimer1, SUPPRESS_TIME_INT1); timer_set(&suppressTimer1, SUPPRESS_TIME_INT1);
@ -388,11 +341,13 @@ ISR(PORT1, port1_isr)
process_poll(&accmeter_process); process_poll(&accmeter_process);
LPM4_EXIT; LPM4_EXIT;
} }
} else if ((ADXL345_IFG & ADXL345_INT2_PIN) && !(ADXL345_IFG & BV(CC2420_FIFOP_PIN))){ } else if((ADXL345_IFG & ADXL345_INT2_PIN) &&
!(ADXL345_IFG & BV(CC2420_FIFOP_PIN))){
/* Check if this should be suppressed or not */ /* Check if this should be suppressed or not */
if(timer_expired(&suppressTimer2)) { if(timer_expired(&suppressTimer2)) {
timer_set(&suppressTimer2, SUPPRESS_TIME_INT2); timer_set(&suppressTimer2, SUPPRESS_TIME_INT2);
ADXL345_IFG &= ~ADXL345_INT2_PIN; // clear interrupt flag /* clear interrupt flag */
ADXL345_IFG &= ~ADXL345_INT2_PIN;
process_poll(&accmeter_process); process_poll(&accmeter_process);
LPM4_EXIT; LPM4_EXIT;
} }
@ -404,7 +359,56 @@ ISR(PORT1, port1_isr)
} }
ENERGEST_OFF(ENERGEST_TYPE_IRQ); ENERGEST_OFF(ENERGEST_TYPE_IRQ);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static int
configure(int type, int value)
{
if(type != SENSORS_ACTIVE) {
return ADXL345_ERROR;
}
#endif if(value) {
accm_init();
} else {
accm_stop();
}
enabled = value;
return ADXL345_SUCCESS;
}
/*---------------------------------------------------------------------------*/
static int
status(int type)
{
switch(type) {
case SENSORS_ACTIVE:
case SENSORS_READY:
return enabled;
}
return ADXL345_SUCCESS;
}
/*---------------------------------------------------------------------------*/
static int
value(int type)
{
if(!enabled) {
return ADXL345_ERROR;
}
if((type != X_AXIS) && (type != Y_AXIS) && (type != Z_AXIS)) {
return ADXL345_ERROR;
}
switch(type) {
case X_AXIS:
return accm_read_axis(X_AXIS);
case Y_AXIS:
return accm_read_axis(Y_AXIS);
case Z_AXIS:
return accm_read_axis(Z_AXIS);
default:
return ADXL345_ERROR;
}
}
/*---------------------------------------------------------------------------*/
SENSORS_SENSOR(adxl345, ADXL345_SENSOR, value, configure, status);
/*---------------------------------------------------------------------------*/

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2010, Swedish Institute of Computer Science. * Copyright (c) 2010, Swedish Institute of Computer Science.
* Copyright (c) 2016, Zolertia <http://www.zolertia.com>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -29,158 +30,106 @@
* This file is part of the Contiki operating system. * This file is part of the Contiki operating system.
* *
*/ */
/*---------------------------------------------------------------------------*/
/** /**
* \file * \file
* Device drivers header file for adxl345 accelerometer in Zolertia Z1. * Device drivers header file for adxl345 accelerometer in Zolertia Z1.
* \author * \author
* Marcus Lundén, SICS <mlunden@sics.se> * Marcus Lundén, SICS <mlunden@sics.se>
* Enric Calvo, Zolertia <ecalvo@zolertia.com> * Enric Calvo, Zolertia <ecalvo@zolertia.com>
* Antonio Lignan, Zolertia <alinan@zolertia.com>
*/ */
/*---------------------------------------------------------------------------*/
#ifndef ADXL345_H_ #ifndef ADXL345_H_
#define ADXL345_H_ #define ADXL345_H_
#include <stdio.h> #include <stdio.h>
#include "dev/i2cmaster.h" #include "dev/i2cmaster.h"
#include "lib/sensors.h"
#define DEBUGLEDS 0 /*---------------------------------------------------------------------------*/
#if DEBUGLEDS /* Used in accm_read_axis(), eg accm_read_axis(X_AXIS) */
#undef LEDS_ON(x)
#undef LEDS_OFF(x)
#define LEDS_ON(x) (LEDS_PxOUT &= ~x)
#define LEDS_OFF(x) (LEDS_PxOUT |= x)
#else
#undef LEDS_ON
#undef LEDS_OFF
#define LEDS_ON(x)
#define LEDS_OFF(x)
#endif
#define LEDS_R 0x10
#define LEDS_G 0x40
#define LEDS_B 0x20
#define L_ON(x) (LEDS_PxOUT &= ~x)
#define L_OFF(x) (LEDS_PxOUT |= x)
/* Used in accm_read_axis(), eg accm_read_axis(X_AXIS);*/
enum ADXL345_AXIS { enum ADXL345_AXIS {
X_AXIS = 0, X_AXIS = 0,
Y_AXIS = 2, Y_AXIS = 2,
Z_AXIS = 4, Z_AXIS = 4,
}; };
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Init the accelerometer: ports, pins, registers, interrupts (none enabled), I2C, /* Init the accelerometer: ports, pins, registers, interrupts (none enabled),
default threshold values etc. */ * I2C, default threshold values etc.
*/
void accm_init(void); void accm_init(void);
/* Write to a register. /* Read an axis of the accelerometer (x, y or z). Return value is a signed 10
args: * bit int.
reg register to write to * The resolution of the acceleration measurement can be increased up to 13 bit,
val value to write * but will change the data format of this read out. Refer to the data sheet if
*/ * so is wanted/needed.
void accm_write_reg(uint8_t reg, uint8_t val); */
/* Write several registers from a stream.
args:
len number of bytes to read
data pointer to where the data is read from
First byte in stream must be the register address to begin writing to.
The data is then written from the second byte and increasing. The address byte
is not included in length len. */
void accm_write_stream(uint8_t len, uint8_t *data);
/* Read one register.
args:
reg what register to read
returns the value of the read register
*/
uint8_t accm_read_reg(uint8_t reg);
/* Read several registers in a stream.
args:
reg what register to start reading from
len number of bytes to read
whereto pointer to where the data is saved
*/
void accm_read_stream(uint8_t reg, uint8_t len, uint8_t *whereto);
/* Read an axis of the accelerometer (x, y or z). Return value is a signed 10 bit int.
The resolution of the acceleration measurement can be increased up to 13 bit, but
will change the data format of this read out. Refer to the data sheet if so is
wanted/needed. */
int16_t accm_read_axis(enum ADXL345_AXIS axis); int16_t accm_read_axis(enum ADXL345_AXIS axis);
/* Sets the g-range, ie the range the accelerometer measures (ie 2g means -2 to +2 g /* Sets the g-range, ie the range the accelerometer measures (ie 2g means -2 to
on every axis). Possible values: * +2 g on every axis). Possible values:
ADXL345_RANGE_2G * - ADXL345_RANGE_2G
ADXL345_RANGE_4G * - ADXL345_RANGE_4G
ADXL345_RANGE_8G * - ADXL345_RANGE_8G
ADXL345_RANGE_16G * - ADXL345_RANGE_16G
Example:
accm_set_grange(ADXL345_RANGE_4G);
*/ */
void accm_set_grange(uint8_t grange); int accm_set_grange(uint8_t grange);
/* Map interrupt (FF, tap, dbltap etc) to interrupt pin (IRQ_INT1, IRQ_INT2). /* Map interrupt (FF, tap, dbltap etc) to interrupt pin (IRQ_INT1, IRQ_INT2).
This must come after accm_init() as the registers will otherwise be overwritten. */ * This must come after accm_init() as the registers will otherwise be
void accm_set_irq(uint8_t int1, uint8_t int2); * overwritten.
*/
int accm_set_irq(uint8_t int1, uint8_t int2);
/* Macros for setting the pointers to callback functions from the interrupts. /* Macros for setting the pointers to callback functions from the interrupts.
The function will be called with an uint8_t as parameter, containing the interrupt * The function will be called with an uint8_t as parameter, containing the
flag register from the ADXL345. That way, several interrupts can be mapped to * interrupt flag register from the ADXL345. That way, several interrupts can be
the same pin and be read from the */ * mapped to the same pin and be read
*/
#define ACCM_REGISTER_INT1_CB(ptr) accm_int1_cb = ptr; #define ACCM_REGISTER_INT1_CB(ptr) accm_int1_cb = ptr;
#define ACCM_REGISTER_INT2_CB(ptr) accm_int2_cb = ptr; #define ACCM_REGISTER_INT2_CB(ptr) accm_int2_cb = ptr;
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Application definitions, change if required by application. */ /* Application definitions, change if required by application. */
/* Interrupt suppress periods */ /* Time after an interrupt that subsequent interrupts are suppressed. Should
/* * later be turned into one specific time per type of interrupt (tap, freefall.
// XXX Not used yet. * etc)
#define ADXL345_INT_OVERRUN_BACKOFF CLOCK_SECOND/8 */
#define ADXL345_INT_WATERMARK_BACKOFF CLOCK_SECOND/8
#define ADXL345_INT_FREEFALL_BACKOFF CLOCK_SECOND/8
#define ADXL345_INT_INACTIVITY_BACKOFF CLOCK_SECOND/8
#define ADXL345_INT_ACTIVITY_BACKOFF CLOCK_SECOND/8
#define ADXL345_INT_DOUBLETAP_BACKOFF CLOCK_SECOND/8
#define ADXL345_INT_TAP_BACKOFF CLOCK_SECOND/8
#define ADXL345_INT_DATAREADY_BACKOFF CLOCK_SECOND/8
*/
/* Time after an interrupt that subsequent interrupts are suppressed. Should later
be turned into one specific time per type of interrupt (tap, freefall etc) */
#define SUPPRESS_TIME_INT1 CLOCK_SECOND/4 #define SUPPRESS_TIME_INT1 CLOCK_SECOND/4
#define SUPPRESS_TIME_INT2 CLOCK_SECOND/4 #define SUPPRESS_TIME_INT2 CLOCK_SECOND/4
/* Suggested defaults according to the data sheet etc */ /* Suggested defaults according to the data sheet etc */
#define ADXL345_THRESH_TAP_DEFAULT 0x48 // 4.5g (0x30 == 3.0g) (datasheet: 3g++) #define ADXL345_THRESH_TAP_DEFAULT 0x48 /* 4.5g (0x30 == 3.0g) */
#define ADXL345_OFSX_DEFAULT 0x00 // for individual units calibration purposes #define ADXL345_OFSX_DEFAULT 0x00 /* for calibration only */
#define ADXL345_OFSY_DEFAULT 0x00 #define ADXL345_OFSY_DEFAULT 0x00
#define ADXL345_OFSZ_DEFAULT 0x00 #define ADXL345_OFSZ_DEFAULT 0x00
#define ADXL345_DUR_DEFAULT 0x20 // 20 ms (datasheet: 10ms++) #define ADXL345_DUR_DEFAULT 0x20 /* 20 ms (datasheet: 10ms++) */
#define ADXL345_LATENT_DEFAULT 0x50 // 100 ms (datasheet: 20ms++) #define ADXL345_LATENT_DEFAULT 0x50 /* 100 ms (datasheet: 20ms++) */
#define ADXL345_WINDOW_DEFAULT 0xFF // 320 ms (datasheet: 80ms++) #define ADXL345_WINDOW_DEFAULT 0xFF /* 320 ms (datasheet: 80ms++) */
#define ADXL345_THRESH_ACT_DEFAULT 0x15 // 1.3g (62.5 mg/LSB) #define ADXL345_THRESH_ACT_DEFAULT 0x15 /* 1.3g (62.5 mg/LSB) */
#define ADXL345_THRESH_INACT_DEFAULT 0x08 // 0.5g (62.5 mg/LSB) #define ADXL345_THRESH_INACT_DEFAULT 0x08 /* 0.5g (62.5 mg/LSB) */
#define ADXL345_TIME_INACT_DEFAULT 0x02 // 2 s (1 s/LSB) #define ADXL345_TIME_INACT_DEFAULT 0x02 /* 2 s (1 s/LSB) */
#define ADXL345_ACT_INACT_CTL_DEFAULT 0xFF // all axis involved, ac-coupled #define ADXL345_ACT_INACT_CTL_DEFAULT 0xFF /* all axis, ac-coupled */
#define ADXL345_THRESH_FF_DEFAULT 0x09 // 563 mg #define ADXL345_THRESH_FF_DEFAULT 0x09 /* 563 mg */
#define ADXL345_TIME_FF_DEFAULT 0x20 // 160 ms #define ADXL345_TIME_FF_DEFAULT 0x20 /* 60 ms */
#define ADXL345_TAP_AXES_DEFAULT 0x07 // all axis, no suppression #define ADXL345_TAP_AXES_DEFAULT 0x07 /* all axis, no suppression */
#define ADXL345_BW_RATE_DEFAULT (0x00|ADXL345_SRATE_100) // 100 Hz, normal operation #define ADXL345_BW_RATE_DEFAULT (0x00 | ADXL345_SRATE_100) /* 100 Hz */
#define ADXL345_POWER_CTL_DEFAULT 0x28 // link bit set, no autosleep, start normal measuring /* link bit set, no autosleep, start normal measuring */
#define ADXL345_INT_ENABLE_DEFAULT 0x00 // no interrupts enabled #define ADXL345_POWER_CTL_DEFAULT 0x28
#define ADXL345_INT_MAP_DEFAULT 0x00 // all mapped to int_1 #define ADXL345_INT_ENABLE_DEFAULT 0x00 /* no interrupts enabled */
#define ADXL345_INT_MAP_DEFAULT 0x00 /* all mapped to int_1 */
/* XXX NB: In the data format register, data format of axis readings is chosen /* XXX NB: In the data format register, data format of axis readings is chosen
between left or right justify. This affects the position of the MSB/LSB and is * between left or right justify. This affects the position of the MSB/LSB and is
different depending on g-range and resolution. If changed, make sure this is * different depending on g-range and resolution. If changed, make sure this is
reflected in the _read_axis() function. Also, the resolution can be increased * reflected in the _read_axis() function. Also, the resolution can be increased
from 10 bit to at most 13 bit, but this also changes position of MSB etc on data * from 10 bit to at most 13 bit, but this also changes position of MSB etc on data
format so check this in read_axis() too. */ * format so check this in read_axis() too.
#define ADXL345_DATA_FORMAT_DEFAULT (0x00|ADXL345_RANGE_2G) // right-justify, 2g, 10-bit mode, int is active high */
#define ADXL345_FIFO_CTL_DEFAULT 0x00 // FIFO bypass mode /* right-justify, 2g, 10-bit mode, int is active high */
#define ADXL345_DATA_FORMAT_DEFAULT (0x00 | ADXL345_RANGE_2G)
#define ADXL345_FIFO_CTL_DEFAULT 0x00 /* FIFO bypass mode */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Reference definitions, should not be changed */ /* Reference definitions, should not be changed */
@ -188,7 +137,7 @@ void accm_set_irq(uint8_t int1, uint8_t int2);
#define ADXL345_ADDR 0x53 #define ADXL345_ADDR 0x53
/* ADXL345 registers */ /* ADXL345 registers */
#define ADXL345_DEVID 0x00 // read only #define ADXL345_DEVID 0x00
/* registers 0x01 to 0x1C are reserved, do not access */ /* registers 0x01 to 0x1C are reserved, do not access */
#define ADXL345_THRESH_TAP 0x1D #define ADXL345_THRESH_TAP 0x1D
#define ADXL345_OFSX 0x1E #define ADXL345_OFSX 0x1E
@ -204,24 +153,24 @@ void accm_set_irq(uint8_t int1, uint8_t int2);
#define ADXL345_THRESH_FF 0x28 #define ADXL345_THRESH_FF 0x28
#define ADXL345_TIME_FF 0x29 #define ADXL345_TIME_FF 0x29
#define ADXL345_TAP_AXES 0x2A #define ADXL345_TAP_AXES 0x2A
#define ADXL345_ACT_TAP_STATUS 0x2B // read only #define ADXL345_ACT_TAP_STATUS 0x2B
#define ADXL345_BW_RATE 0x2C #define ADXL345_BW_RATE 0x2C
#define ADXL345_POWER_CTL 0x2D #define ADXL345_POWER_CTL 0x2D
#define ADXL345_INT_ENABLE 0x2E #define ADXL345_INT_ENABLE 0x2E
#define ADXL345_INT_MAP 0x2F #define ADXL345_INT_MAP 0x2F
#define ADXL345_INT_SOURCE 0x30 // read only #define ADXL345_INT_SOURCE 0x30
#define ADXL345_DATA_FORMAT 0x31 #define ADXL345_DATA_FORMAT 0x31
#define ADXL345_DATAX0 0x32 // read only, LSByte X, two's complement #define ADXL345_DATAX0 0x32 /* read only, LSByte X, two's complement */
#define ADXL345_DATAX1 0x33 // read only, MSByte X #define ADXL345_DATAX1 0x33 /* read only, MSByte X */
#define ADXL345_DATAY0 0x34 // read only, LSByte Y #define ADXL345_DATAY0 0x34 /* read only, LSByte Y */
#define ADXL345_DATAY1 0x35 // read only, MSByte X #define ADXL345_DATAY1 0x35 /* read only, MSByte X */
#define ADXL345_DATAZ0 0x36 // read only, LSByte Z #define ADXL345_DATAZ0 0x36 /* read only, LSByte Z */
#define ADXL345_DATAZ1 0x37 // read only, MSByte X #define ADXL345_DATAZ1 0x37 /* read only, MSByte X */
#define ADXL345_FIFO_CTL 0x38 #define ADXL345_FIFO_CTL 0x38
#define ADXL345_FIFO_STATUS 0x39 // read only #define ADXL345_FIFO_STATUS 0x39 /* read only */
/* ADXL345 interrupts */ /* ADXL345 interrupts */
#define ADXL345_INT_DISABLE 0X00 // used for disabling interrupts #define ADXL345_INT_DISABLE 0X00 /* used for disabling interrupts */
#define ADXL345_INT_OVERRUN 0X01 #define ADXL345_INT_OVERRUN 0X01
#define ADXL345_INT_WATERMARK 0X02 #define ADXL345_INT_WATERMARK 0X02
#define ADXL345_INT_FREEFALL 0X04 #define ADXL345_INT_FREEFALL 0X04
@ -237,8 +186,8 @@ void accm_set_irq(uint8_t int1, uint8_t int2);
#define ADXL345_REN P1REN #define ADXL345_REN P1REN
#define ADXL345_SEL P1SEL #define ADXL345_SEL P1SEL
#define ADXL345_SEL2 P1SEL2 #define ADXL345_SEL2 P1SEL2
#define ADXL345_INT1_PIN (1<<6) // P1.6 #define ADXL345_INT1_PIN (1<<6) /* P1.6 */
#define ADXL345_INT2_PIN (1<<7) // P1.7 #define ADXL345_INT2_PIN (1<<7) /* P1.7 */
#define ADXL345_IES P1IES #define ADXL345_IES P1IES
#define ADXL345_IE P1IE #define ADXL345_IE P1IE
#define ADXL345_IFG P1IFG #define ADXL345_IFG P1IFG
@ -251,43 +200,47 @@ void accm_set_irq(uint8_t int1, uint8_t int2);
#define ADXL345_RANGE_16G 0x03 #define ADXL345_RANGE_16G 0x03
/* The adxl345 has programmable sample rates, but unexpected results may occur if the wrong /* The adxl345 has programmable sample rates, but unexpected results may occur
rate and I2C bus speed is used (see datasheet p 17). Sample rates in Hz. This * if the wrong rate and I2C bus speed is used (see datasheet p 17). Sample
setting does not change the internal sampling rate, just how often it is piped * rates in Hz. This setting does not change the internal sampling rate, just
to the output registers (ie the interrupt features use the full sample rate * how often it is piped to the output registers (ie the interrupt features use
internally). * the full sample rate internally).
* Example use:
Example use: * adxl345_set_reg(ADXL345_BW_RATE, ((_ADXL345_STATUS & LOW_POWER)
adxl345_set_reg(ADXL345_BW_RATE, ((_ADXL345_STATUS & LOW_POWER) | ADXL345_SRATE_50)); * | ADXL345_SRATE_50));
*/ */
#define ADXL345_SRATE_3200 0x0F // XXX NB don't use at all as I2C data rate<= 400kHz (see datasheet)
#define ADXL345_SRATE_1600 0x0E // XXX NB don't use at all as I2C data rate<= 400kHz (see datasheet)
#define ADXL345_SRATE_800 0x0D // when I2C data rate == 400 kHz
#define ADXL345_SRATE_400 0x0C // when I2C data rate == 400 kHz
#define ADXL345_SRATE_200 0x0B // when I2C data rate >= 100 kHz
#define ADXL345_SRATE_100 0x0A // when I2C data rate >= 100 kHz
#define ADXL345_SRATE_50 0x09 // when I2C data rate >= 100 kHz
#define ADXL345_SRATE_25 0x08 // when I2C data rate >= 100 kHz
#define ADXL345_SRATE_12_5 0x07 // 12.5 Hz, when I2C data rate >= 100 kHz
#define ADXL345_SRATE_6_25 0x06 // when I2C data rate >= 100 kHz
#define ADXL345_SRATE_3_13 0x05 // when I2C data rate >= 100 kHz
#define ADXL345_SRATE_1_56 0x04 // when I2C data rate >= 100 kHz
#define ADXL345_SRATE_0_78 0x03 // when I2C data rate >= 100 kHz
#define ADXL345_SRATE_0_39 0x02 // when I2C data rate >= 100 kHz
#define ADXL345_SRATE_0_20 0x01 // when I2C data rate >= 100 kHz
#define ADXL345_SRATE_0_10 0x00 // 0.10 Hz, when I2C data rate >= 100 kHz
/* XXX NB don't use at all as I2C data rate<= 400kHz */
#define ADXL345_SRATE_3200 0x0F
/* XXX NB don't use at all as I2C data rate<= 400kHz */
#define ADXL345_SRATE_1600 0x0E
#define ADXL345_SRATE_800 0x0D /* when I2C data rate == 400 kHz */
#define ADXL345_SRATE_400 0x0C /* when I2C data rate == 400 kHz */
#define ADXL345_SRATE_200 0x0B /* when I2C data rate >= 100 kHz */
#define ADXL345_SRATE_100 0x0A /* when I2C data rate >= 100 kHz */
#define ADXL345_SRATE_50 0x09 /* when I2C data rate >= 100 kHz */
#define ADXL345_SRATE_25 0x08 /* when I2C data rate >= 100 kHz */
#define ADXL345_SRATE_12_5 0x07 /* 12.5 Hz, when I2C data rate >= 100 kHz */
#define ADXL345_SRATE_6_25 0x06 /* when I2C data rate >= 100 kHz */
#define ADXL345_SRATE_3_13 0x05 /* when I2C data rate >= 100 kHz */
#define ADXL345_SRATE_1_56 0x04 /* when I2C data rate >= 100 kHz */
#define ADXL345_SRATE_0_78 0x03 /* when I2C data rate >= 100 kHz */
#define ADXL345_SRATE_0_39 0x02 /* when I2C data rate >= 100 kHz */
#define ADXL345_SRATE_0_20 0x01 /* when I2C data rate >= 100 kHz */
#define ADXL345_SRATE_0_10 0x00 /* 0.10 Hz, when I2C data rate >= 100 kHz */
/* -------------------------------------------------------------------------- */
/* Callback pointers for the interrupts */ /* Callback pointers for the interrupts */
extern void (*accm_int1_cb)(uint8_t reg); extern void (*accm_int1_cb)(uint8_t reg);
extern void (*accm_int2_cb)(uint8_t reg); extern void (*accm_int2_cb)(uint8_t reg);
/* -------------------------------------------------------------------------- */
/* Interrupt 1 and 2 events; ADXL345 signals interrupt on INT1 or INT2 pins,
ISR is invoked and polls the accelerometer process which invokes the callbacks. */
extern process_event_t int1_event, int2_event; // static ?
#define ACCM_INT1 0x01 #define ACCM_INT1 0x01
#define ACCM_INT2 0x02 #define ACCM_INT2 0x02
#define ADXL345_SUCCESS 0x00
#define ADXL345_ERROR (-1)
/* -------------------------------------------------------------------------- */
#define ADXL345_SENSOR "ADXL345 sensor"
/* -------------------------------------------------------------------------- */
extern const struct sensors_sensor adxl345;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
#endif /* ifndef ADXL345_H_ */ #endif /* ifndef ADXL345_H_ */

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2010, Swedish Institute of Computer Science. * Copyright (c) 2010, Swedish Institute of Computer Science.
* Copyright (c) 2016, Zolertia <http://www.zolertia.com>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -29,47 +30,34 @@
* This file is part of the Contiki operating system. * This file is part of the Contiki operating system.
* *
*/ */
/*---------------------------------------------------------------------------*/
/** /**
* \file * \file
* Device drivers for tmp102 temperature sensor in Zolertia Z1. * Device drivers for tmp102 temperature sensor in Zolertia Z1.
* \author * \author
* Enric M. Calvo, Zolertia <ecalvo@zolertia.com> * Enric M. Calvo, Zolertia <ecalvo@zolertia.com>
* Marcus Lundén, SICS <mlunden@sics.se> * Marcus Lundén, SICS <mlunden@sics.se>
* Antonio Lignan, Zolertia <alinan@zolertia.com>
*/ */
/*---------------------------------------------------------------------------*/
#include <stdio.h> #include <stdio.h>
#include "contiki.h" #include "contiki.h"
#include "i2cmaster.h" #include "i2cmaster.h"
#include "tmp102.h" #include "tmp102.h"
#include "lib/sensors.h"
/* Bitmasks and bit flag variable for keeping track of tmp102 status. */
enum TMP102_STATUSTYPES {
/* must be a bit and not more, not using 0x00. */
INITED = 0x01,
RUNNING = 0x02,
STOPPED = 0x04,
LOW_POWER = 0x08,
AAA = 0x10, /* available to extend this... */
BBB = 0x20, /* available to extend this... */
CCC = 0x40, /* available to extend this... */
DDD = 0x80 /* available to extend this... */
};
static enum TMP102_STATUSTYPES _TMP102_STATUS = 0x00;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* PROCESS(tmp102_process, "Temperature Sensor process"); */ #define DEBUG 0
#if DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
/*---------------------------------------------------------------------------*/
static uint8_t enabled;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Init the temperature sensor: ports, pins, registers, interrupts (none enabled), I2C,
default threshold values etc. */
void void
tmp102_init(void) tmp102_init(void)
{ {
if(!(_TMP102_STATUS & INITED)) {
PRINTFDEBUG("TMP102 init\n");
_TMP102_STATUS |= INITED;
/* Power Up TMP102 via pin */ /* Power Up TMP102 via pin */
TMP102_PWR_DIR |= TMP102_PWR_PIN; TMP102_PWR_DIR |= TMP102_PWR_PIN;
TMP102_PWR_SEL &= ~TMP102_PWR_SEL; TMP102_PWR_SEL &= ~TMP102_PWR_SEL;
@ -79,15 +67,18 @@ tmp102_init(void)
/* Set up ports and pins for I2C communication */ /* Set up ports and pins for I2C communication */
i2c_enable(); i2c_enable();
}
enabled = 1;
}
/*---------------------------------------------------------------------------*/
void
tmp102_stop(void)
{
/* Power off */
TMP102_PWR_OUT &= ~TMP102_PWR_PIN;
enabled = 0;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Write to a 16-bit register.
args:
reg register to write to
val value to write
*/
void void
tmp102_write_reg(uint8_t reg, uint16_t val) tmp102_write_reg(uint8_t reg, uint16_t val)
{ {
@ -98,26 +89,20 @@ tmp102_write_reg(uint8_t reg, uint16_t val)
i2c_transmitinit(TMP102_ADDR); i2c_transmitinit(TMP102_ADDR);
while(i2c_busy()); while(i2c_busy());
PRINTFDEBUG("I2C Ready to TX\n"); PRINTF("I2C Ready to TX\n");
i2c_transmit_n(3, tx_buf); i2c_transmit_n(3, tx_buf);
while(i2c_busy()); while(i2c_busy());
PRINTFDEBUG("WRITE_REG 0x%04X @ reg 0x%02X\n", val, reg); PRINTF("WRITE_REG 0x%04X @ reg 0x%02X\n", val, reg);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Read register.
args:
reg what register to read
returns the value of the read register type uint16_t
*/
uint16_t uint16_t
tmp102_read_reg(uint8_t reg) tmp102_read_reg(uint8_t reg)
{ {
uint8_t buf[] = { 0x00, 0x00 }; uint8_t buf[] = { 0x00, 0x00 };
uint16_t retVal = 0; uint16_t retVal = 0;
uint8_t rtx = reg; uint8_t rtx = reg;
PRINTFDEBUG("READ_REG 0x%02X\n", reg); PRINTF("READ_REG 0x%02X\n", reg);
/* transmit the register to read */ /* transmit the register to read */
i2c_transmitinit(TMP102_ADDR); i2c_transmitinit(TMP102_ADDR);
@ -136,19 +121,14 @@ tmp102_read_reg(uint8_t reg)
return retVal; return retVal;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Read temperature in a raw format. Further processing will be needed
to make an interpretation of these 12 or 13-bit data, depending on configuration
*/
uint16_t uint16_t
tmp102_read_temp_raw(void) tmp102_read_temp_raw(void)
{ {
uint16_t rd = 0; uint16_t rd = 0;
rd = tmp102_read_reg(TMP102_TEMP); rd = tmp102_read_reg(TMP102_TEMP);
return rd; return rd;
} }
/*---------------------------------------------------------------------------*/
int16_t int16_t
tmp102_read_temp_x100(void) tmp102_read_temp_x100(void)
{ {
@ -167,24 +147,47 @@ tmp102_read_temp_x100(void)
/* Integer part of the temperature value and percents*/ /* Integer part of the temperature value and percents*/
temp_int = (abstemp >> 8) * sign * 100; temp_int = (abstemp >> 8) * sign * 100;
temp_int += ((abstemp & 0xff) * 100) / 0x100; temp_int += ((abstemp & 0xff) * 100) / 0x100;
/* See test-tmp102.c on how to print values of temperature with decimals
fractional part in 1/10000 of degree
temp_frac = ((abstemp >>4) % 16) * 625;
Data could be multiplied by 63 to have less bit-growth and 1/1000 precision
Data could be multiplied by 64 (<< 6) to trade-off precision for speed
*/
return temp_int; return temp_int;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Simple Read temperature. Return is an integer with temperature in 1deg. precision
Return value is a signed 8 bit integer.
*/
int8_t int8_t
tmp102_read_temp_simple(void) tmp102_read_temp_simple(void)
{ {
/* Casted to int8_t: We don't expect temperatures outside -128 to 127 C */ /* Casted to int8_t: We don't expect temperatures outside -128 to 127 C */
return tmp102_read_temp_x100() / 100; return tmp102_read_temp_x100() / 100;
} }
/*---------------------------------------------------------------------------*/
static int
configure(int type, int value)
{
if(type != SENSORS_ACTIVE) {
return TMP102_ERROR;
}
if(value) {
tmp102_init();
} else {
tmp102_stop();
}
enabled = value;
return TMP102_SUCCESS;
}
/*---------------------------------------------------------------------------*/
static int
status(int type)
{
switch(type) {
case SENSORS_ACTIVE:
case SENSORS_READY:
return enabled;
}
return TMP102_SUCCESS;
}
/*---------------------------------------------------------------------------*/
static int
value(int type)
{
return (int)tmp102_read_temp_x100();
}
/*---------------------------------------------------------------------------*/
SENSORS_SENSOR(tmp102, TMP102_SENSOR, value, configure, status);
/*---------------------------------------------------------------------------*/

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2010, Swedish Institute of Computer Science. * Copyright (c) 2010, Swedish Institute of Computer Science.
* Copyright (c) 2016, Zolertia <http://www.zolertia.com>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -32,75 +33,47 @@
/** /**
* \file * \file
* Device drivers header file for tmp102 temperature sensor in Zolertia Z1 WSN Platform. * Device drivers header file for tmp102 temperature sensor in Zolertia
* Z1 WSN Platform.
* \author * \author
* Enric M. Calvo, Zolertia <ecalvo@zolertia.com> * Enric M. Calvo, Zolertia <ecalvo@zolertia.com>
* Marcus Lundén, SICS <mlunden@sics.se> * Marcus Lundén, SICS <mlunden@sics.se>
* Antonio Lignan, Zolertia <alinan@zolertia.com>
*/ */
/* -------------------------------------------------------------------------- */
#ifndef TMP102_H_ #ifndef TMP102_H_
#define TMP102_H_ #define TMP102_H_
#include <stdio.h> #include <stdio.h>
#include "lib/sensors.h"
#include "i2cmaster.h" #include "i2cmaster.h"
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Init the temperature sensor: ports, pins, I2C, interrupts (XXX none so far),
*/
void tmp102_init(void); void tmp102_init(void);
/* Write to a register.
args:
reg register to write to
val value to write
*/
void tmp102_write_reg(uint8_t reg, uint16_t val); void tmp102_write_reg(uint8_t reg, uint16_t val);
/* Read one register.
args:
reg what register to read
returns the value of the read register
*/
uint16_t tmp102_read_reg(uint8_t reg); uint16_t tmp102_read_reg(uint8_t reg);
/* Read temperature in raw format
no args needed
*/
uint16_t tmp102_read_temp_raw(); uint16_t tmp102_read_temp_raw();
/* Read only integer part of the temperature in 1deg. precision.
no args needed
*/
int8_t tmp102_read_temp_simple(); int8_t tmp102_read_temp_simple();
/* Read only integer part of the temperature in 1deg. precision.
no args needed
*/
int16_t tmp102_read_temp_x100(); int16_t tmp102_read_temp_x100();
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Reference definitions */
/* TMP102 slave address */
#define TMP102_ADDR 0x48 #define TMP102_ADDR 0x48
#define TMP102_TEMP 0x00
/* TMP102 registers */
#define TMP102_TEMP 0x00 // read only
#define TMP102_CONF 0x01 #define TMP102_CONF 0x01
#define TMP102_TLOW 0x02 #define TMP102_TLOW 0x02
#define TMP102_THIGH 0x03 #define TMP102_THIGH 0x03
/* TMP102 Ports */ /* TMP102 pin-out */
/* Accelerometer hardware ports, pins and registers on the msp430 µC */
#define TMP102_PWR_DIR P5DIR #define TMP102_PWR_DIR P5DIR
#define TMP102_PWR_SEL P5SEL #define TMP102_PWR_SEL P5SEL
#define TMP102_PWR_SEL2 P5SEL2 #define TMP102_PWR_SEL2 P5SEL2
#define TMP102_PWR_REN P5REN #define TMP102_PWR_REN P5REN
#define TMP102_PWR_OUT P5OUT #define TMP102_PWR_OUT P5OUT
#define TMP102_PWR_PIN (1<<0) // P5.0 #define TMP102_PWR_PIN (1<<0) /* P5.0 */
//#define TMP102_INT_PIN (1<<7) // P1.7 /* -------------------------------------------------------------------------- */
#define TMP102_SUCCESS 0
#define TMP102_ERROR (-1)
#define TMP102_READ 0x01
/* -------------------------------------------------------------------------- */
#define TMP102_SENSOR "TMP102 sensor"
/* -------------------------------------------------------------------------- */
extern const struct sensors_sensor tmp102;
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
#endif /* ifndef TMP102_H_ */ #endif /* ifndef TMP102_H_ */