Added I2C Master drivers and accelerometer drivers

This commit is contained in:
enricmcalvo 2010-11-07 08:38:51 +00:00
parent 47e7fd35c2
commit 59bdebe842
5 changed files with 1074 additions and 0 deletions

404
platform/z1/dev/adxl345.c Normal file
View file

@ -0,0 +1,404 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* Device drivers for adxl345 accelerometer in Zolertia Z1.
* \author
* Marcus Lundén, SICS <mlunden@sics.se>
* Enric M. Calvo, Zolertia <ecalvo@zolertia.com>
*/
#include <stdio.h>
#include <signal.h>
#include "contiki.h"
#include "adxl345.h"
#include "cc2420-arch.c"
#include "i2cmaster.h"
/* Callback pointers when interrupt occurs */
extern void (*accm_int1_cb)(u8_t reg);
extern void (*accm_int2_cb)(u8_t reg);
/* Bitmasks for the interrupts */
static uint16_t int1_mask = 0, int2_mask = 0;
/* Keep track of when the interrupt was last seen in order to reduce the amount
of interrupts. Kind of like button debouncing. This can't be per int-pin, as
there can be several very different int per pin (eg tap && freefall). */
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[] = {
/* 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. */
/* 0--14 are in one stream, start at ADXL345_THRESH_TAP */
ADXL345_THRESH_TAP, // XXX NB Register address, not register value!!
ADXL345_THRESH_TAP_DEFAULT,
ADXL345_OFSX_DEFAULT,
ADXL345_OFSY_DEFAULT,
ADXL345_OFSZ_DEFAULT,
ADXL345_DUR_DEFAULT,
ADXL345_LATENT_DEFAULT,
ADXL345_WINDOW_DEFAULT,
ADXL345_THRESH_ACT_DEFAULT,
ADXL345_THRESH_INACT_DEFAULT,
ADXL345_TIME_INACT_DEFAULT,
ADXL345_ACT_INACT_CTL_DEFAULT,
ADXL345_THRESH_FF_DEFAULT,
ADXL345_TIME_FF_DEFAULT,
ADXL345_TAP_AXES_DEFAULT,
/* 15--19 start at ADXL345_BW_RATE */
ADXL345_BW_RATE, // XXX NB Register address, not register value!!
ADXL345_BW_RATE_DEFAULT,
ADXL345_POWER_CTL_DEFAULT,
ADXL345_INT_ENABLE_DEFAULT,
ADXL345_INT_MAP_DEFAULT,
/* These two: 20, 21 write separately */
ADXL345_DATA_FORMAT_DEFAULT,
ADXL345_FIFO_CTL_DEFAULT
};
/*---------------------------------------------------------------------------*/
PROCESS(accmeter_process, "Accelerometer process");
/*---------------------------------------------------------------------------*/
/* Write to a register.
args:
reg register to write to
val value to write
*/
void
accm_write_reg(u8_t reg, u8_t val) {
u8_t tx_buf[] = {reg, val};
i2c_transmitinit(ADXL345_ADDR);
while (i2c_busy());
PRINTFDEBUG("I2C Ready to TX\n");
i2c_transmit_n(2, tx_buf);
while (i2c_busy());
PRINTFDEBUG("WRITE_REG 0x%02X @ reg 0x%02X\n", val, reg);
}
/*---------------------------------------------------------------------------*/
/* Read several registers in 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 second byte and increasing. */
void
accm_write_stream(u8_t len, u8_t *data) {
i2c_transmitinit(ADXL345_ADDR);
while (i2c_busy());
PRINTFDEBUG("I2C Ready to TX(stream)\n");
i2c_transmit_n(len, data); // start tx and send conf reg
while (i2c_busy());
PRINTFDEBUG("WRITE_STR %u B to 0x%02X\n", len, data[0]);
}
/*---------------------------------------------------------------------------*/
/* Read one register.
args:
reg what register to read
returns the value of the read register
*/
u8_t
accm_read_reg(u8_t reg) {
u8_t retVal = 0;
u8_t rtx = reg;
PRINTFDEBUG("READ_REG 0x%02X\n", reg);
/* transmit the register to read */
i2c_transmitinit(ADXL345_ADDR);
while (i2c_busy());
i2c_transmit_n(1, &rtx);
while (i2c_busy());
/* receive the data */
i2c_receiveinit(ADXL345_ADDR);
while (i2c_busy());
i2c_receive_n(1, &retVal);
while (i2c_busy());
return retVal;
}
/*---------------------------------------------------------------------------*/
/* 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(u8_t reg, u8_t len, u8_t *whereto) {
u8_t rtx = reg;
PRINTFDEBUG("READ_STR %u B from 0x%02X\n", len, reg);
/* transmit the register to start reading from */
i2c_transmitinit(ADXL345_ADDR);
while (i2c_busy());
i2c_transmit_n(1, &rtx);
while (i2c_busy());
/* receive the data */
i2c_receiveinit(ADXL345_ADDR);
while (i2c_busy());
i2c_receive_n(len, whereto);
while (i2c_busy());
}
/*---------------------------------------------------------------------------*/
/* 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 rd = 0;
u8_t tmp[2];
if(axis > Z_AXIS){
return 0;
}
accm_read_stream(ADXL345_DATAX0 + axis, 2, &tmp[0]);
rd = (int16_t)(tmp[0] | (tmp[1]<<8));
return rd;
}
/*---------------------------------------------------------------------------*/
/* Sets the g-range, ie the range the accelerometer measures (ie 2g means -2 to +2 g
on every axis). Possible values:
ADXL345_RANGE_2G
ADXL345_RANGE_4G
ADXL345_RANGE_8G
ADXL345_RANGE_16G
Example:
accm_set_grange(ADXL345_RANGE_4G);
*/
void
accm_set_grange(u8_t grange){
if(grange > ADXL345_RANGE_16G) {
// invalid g-range.
PRINTFDEBUG("ADXL grange invalid: %u\n", grange);
return;
}
u8_t tempreg = 0;
/* preserve the previous contents of the register */
tempreg = (accm_read_reg(ADXL345_DATA_FORMAT) & 0xFC); // zero out the last two bits (grange)
tempreg |= grange; // set new range
accm_write_reg(ADXL345_DATA_FORMAT, tempreg);
}
/*---------------------------------------------------------------------------*/
/* Init the accelerometer: ports, pins, registers, interrupts (none enabled), I2C,
default threshold values etc. */
void
accm_init(void) {
if(!(_ADXL345_STATUS & INITED)){
PRINTFDEBUG("ADXL345 init\n");
_ADXL345_STATUS |= INITED;
accm_int1_cb = NULL;
accm_int2_cb = NULL;
int1_event = process_alloc_event();
int2_event = process_alloc_event();
/* Set up ports and pins for interrups. */
ADXL345_DIR &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
ADXL345_SEL &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
ADXL345_SEL2 &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
/* Set up ports and pins for I2C communication */
i2c_enable();
/* set default register values. */
accm_write_stream(15, &adxl345_default_settings[0]);
accm_write_stream(5, &adxl345_default_settings[15]);
accm_write_reg(ADXL345_DATA_FORMAT, adxl345_default_settings[20]);
accm_write_reg(ADXL345_FIFO_CTL, adxl345_default_settings[21]);
process_start(&accmeter_process, NULL);
/* Enable msp430 interrupts on the two interrupt pins. */
dint();
ADXL345_IES &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN); // low to high transition interrupts
ADXL345_IE |= (ADXL345_INT1_PIN | ADXL345_INT2_PIN); // enable interrupts
eint();
}
}
/*---------------------------------------------------------------------------*/
/* 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
accm_set_irq(uint8_t int1, uint8_t int2){
/* Set the corresponding interrupt mapping to INT1 or INT2 */
PRINTFDEBUG("IRQs set to INT1: 0x%02X IRQ2: 0x%02X\n", int1, int2);
int1_mask = int1;
int2_mask = 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
}
/*---------------------------------------------------------------------------*/
#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
accelerometer, which resets the interrupts, and invokes the corresponding
callback. It passes the source register value so the callback can determine
what interrupt happened, if several interrupts are mapped to the same pin. */
static void
poll_handler(void){
uint8_t ireg = 0;
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 */
if(ireg & int1_mask){
if(accm_int1_cb != NULL){
PRINTFDEBUG("INT1 cb invoked\n");
accm_int1_cb(ireg);
}
} else if(ireg & int2_mask){
if(accm_int2_cb != NULL){
PRINTFDEBUG("INT2 cb invoked\n");
accm_int2_cb(ireg);
}
}
}
/*---------------------------------------------------------------------------*/
/* This process is sleeping until an interrupt from the accelerometer occurs, which
polls this process from the interrupt service routine. */
PROCESS_THREAD(accmeter_process, ev, data) {
PROCESS_POLLHANDLER(poll_handler());
PROCESS_EXITHANDLER();
PROCESS_BEGIN();
while(1){
PROCESS_WAIT_EVENT_UNTIL(0); // should do nothing in while loop.
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/* XXX This interrupt vector is shared with the interrupts from CC2420, so that
was moved here but should find a better home. XXX */
static struct timer suppressTimer1, suppressTimer2;
interrupt(PORT1_VECTOR) port1_isr (void) {
ENERGEST_ON(ENERGEST_TYPE_IRQ);
/* ADXL345_IFG.x goes high when interrupt occurs, use to check what interrupted */
if (ADXL345_IFG & ADXL345_INT1_PIN){
/* Check if this should be suppressed or not */
if(timer_expired(&suppressTimer1)) {
timer_set(&suppressTimer1, SUPPRESS_TIME_INT1);
ADXL345_IFG &= ~ADXL345_INT1_PIN; // clear interrupt flag
process_poll(&accmeter_process);
LPM4_EXIT;
}
} else if (ADXL345_IFG & ADXL345_INT2_PIN){
/* Check if this should be suppressed or not */
if(timer_expired(&suppressTimer2)) {
timer_set(&suppressTimer2, SUPPRESS_TIME_INT2);
ADXL345_IFG &= ~ADXL345_INT2_PIN; // clear interrupt flag
process_poll(&accmeter_process);
LPM4_EXIT;
}
} else {
/* CC2420 interrupt */
if(cc2420_interrupt()) {
LPM4_EXIT;
}
}
ENERGEST_OFF(ENERGEST_TYPE_IRQ);
}
/*---------------------------------------------------------------------------*/

249
platform/z1/dev/adxl345.h Normal file
View file

@ -0,0 +1,249 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* Device drivers header file for adxl345 accelerometer in Zolertia Z1.
* \author
* Marcus Lundén, SICS <mlunden@sics.se>
* Enric Calvo, Zolertia <ecalvo@zolertia.com>
*/
#ifndef __ADXL345_H__
#define __ADXL345_H__
#include <stdio.h>
#include "i2cmaster.h"
//XXX Temporary place for defines that are lacking in mspgcc4's gpio.h
#ifndef P1SEL2_
#define P1SEL2_ 0x0041 /* Port 1 Selection 2 */
sfrb(P1SEL2, P1SEL2_);
#endif
#define DEBUGLEDS 0
#if DEBUGLEDS
#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 {
X_AXIS = 0,
Y_AXIS = 2,
Z_AXIS = 4,
};
void accm_init(void);
void accm_write_reg(u8_t reg, u8_t val);
void accm_write_stream(u8_t len, u8_t *data);
u8_t accm_read_reg(u8_t reg);
void accm_read_stream(u8_t reg, u8_t len, u8_t *whereto);
int16_t accm_read_axis(enum ADXL345_AXIS axis);
void accm_set_grange(u8_t grange);
void accm_set_irq(uint8_t int1, uint8_t int2);
/* -------------------------------------------------------------------------- */
/* Application definitions, change if required by application. */
/* Interrupt suppress periods */
/*
// XXX Not used yet.
#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
#define SUPPRESS_TIME_INT2 CLOCK_SECOND
/* Suggested defaults according to the data sheet etc */
#define ADXL345_THRESH_TAP_DEFAULT 0x48 // 4.5g (0x30 == 3.0g) (datasheet: 3g++)
#define ADXL345_OFSX_DEFAULT 0x00 // for calibration, set 0 for long...
#define ADXL345_OFSY_DEFAULT 0x00
#define ADXL345_OFSZ_DEFAULT 0x00
#define ADXL345_DUR_DEFAULT 0x20 // 20 ms (datasheet: 10ms++)
#define ADXL345_LATENT_DEFAULT 0x50 // 100 ms (datasheet: 20ms++)
#define ADXL345_WINDOW_DEFAULT 0xFF // 320 ms (datasheet: 80ms++)
#define ADXL345_THRESH_ACT_DEFAULT 0x20 // 2g
#define ADXL345_THRESH_INACT_DEFAULT 0x13 // 1.2g
#define ADXL345_TIME_INACT_DEFAULT 0x02 // 2 s
#define ADXL345_ACT_INACT_CTL_DEFAULT 0xFF // all axis involved, ac-coupled
#define ADXL345_THRESH_FF_DEFAULT 0x09 // 563 mg
#define ADXL345_TIME_FF_DEFAULT 0x20 // 160 ms
#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_POWER_CTL_DEFAULT 0x08 // no link, no autosleep, start normal measuring
#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
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
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
format so check this in read_axis() too. */
#define ADXL345_DATA_FORMAT_DEFAULT (0x00|ADXL345_RANGE_2G) // right-justify, 4g, 10-bit mode, int is active high
#define ADXL345_FIFO_CTL_DEFAULT 0x00 // FIFO bypass mode
/* -------------------------------------------------------------------------- */
/* Reference definitions, should not be changed */
/* adxl345 slave address */
#define ADXL345_ADDR 0x53
/* ADXL345 registers */
#define ADXL345_DEVID 0x00 // read only
/* registers 0x01 to 0x1C are reserved, do not access */
#define ADXL345_THRESH_TAP 0x1D
#define ADXL345_OFSX 0x1E
#define ADXL345_OFSY 0x1F
#define ADXL345_OFSZ 0x20
#define ADXL345_DUR 0x21
#define ADXL345_LATENT 0x22
#define ADXL345_WINDOW 0x23
#define ADXL345_THRESH_ACT 0x24
#define ADXL345_THRESH_INACT 0x25
#define ADXL345_TIME_INACT 0x26
#define ADXL345_ACT_INACT_CTL 0x27
#define ADXL345_THRESH_FF 0x28
#define ADXL345_TIME_FF 0x29
#define ADXL345_TAP_AXES 0x2A
#define ADXL345_ACT_TAP_STATUS 0x2B // read only
#define ADXL345_BW_RATE 0x2C
#define ADXL345_POWER_CTL 0x2D
#define ADXL345_INT_ENABLE 0x2E
#define ADXL345_INT_MAP 0x2F
#define ADXL345_INT_SOURCE 0x30 // read only
#define ADXL345_DATA_FORMAT 0x31
#define ADXL345_DATAX0 0x32 // read only, LSByte X, two's complement
#define ADXL345_DATAX1 0x33 // read only, MSByte X
#define ADXL345_DATAY0 0x34 // read only, LSByte Y
#define ADXL345_DATAY1 0x35 // read only, MSByte X
#define ADXL345_DATAZ0 0x36 // read only, LSByte Z
#define ADXL345_DATAZ1 0x37 // read only, MSByte X
#define ADXL345_FIFO_CTL 0x38
#define ADXL345_FIFO_STATUS 0x39 // read only
/* ADXL345 interrupts */
#define ADXL345_INT_DISABLE 0X00 // used for disabling interrupts
#define ADXL345_INT_OVERRUN 0X01
#define ADXL345_INT_WATERMARK 0X02
#define ADXL345_INT_FREEFALL 0X04
#define ADXL345_INT_INACTIVITY 0X08
#define ADXL345_INT_ACTIVITY 0X10
#define ADXL345_INT_DOUBLETAP 0X20
#define ADXL345_INT_TAP 0X40
#define ADXL345_INT_DATAREADY 0X80
/* Accelerometer hardware ports, pins and registers on the msp430 µC */
#define ADXL345_DIR P1DIR
#define ADXL345_PIN P1PIN
#define ADXL345_REN P1REN
#define ADXL345_SEL P1SEL
#define ADXL345_SEL2 P1SEL2
#define ADXL345_INT1_PIN (1<<6) // P1.6
#define ADXL345_INT2_PIN (1<<7) // P1.7
#define ADXL345_IES P1IES
#define ADXL345_IE P1IE
#define ADXL345_IFG P1IFG
#define ADXL345_VECTOR PORT1_VECTOR
/* g-range for DATA_FORMAT register */
#define ADXL345_RANGE_2G 0x00
#define ADXL345_RANGE_4G 0x01
#define ADXL345_RANGE_8G 0x02
#define ADXL345_RANGE_16G 0x03
/* The adxl345 has programmable sample rates, but unexpected results may occur if the wrong
rate and I2C bus speed is used (see datasheet p 17). Sample rates in Hz.
Example use:
adxl345_set_reg(ADXL345_BW_RATE, ((_ADXL345_STATUS & LOW_POWER) | 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
/* Callback pointers for the interrupts */
void (*accm_int1_cb)(u8_t reg);
void (*accm_int2_cb)(u8_t reg);
/* Macros for setting the callback pointers */
#define ACCM_REGISTER_INT1_CB(ptr) accm_int1_cb = ptr;
#define ACCM_REGISTER_INT2_CB(ptr) accm_int2_cb = ptr;
/* 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. */
process_event_t int1_event, int2_event; // static ?
#define ACCM_INT1 0x01
#define ACCM_INT2 0x02
/* -------------------------------------------------------------------------- */
#endif /* ifndef __ADXL345_H__ */

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2006, Swedish Institute of Computer Science
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)$Id: cc2420-arch.c,v 1.1 2010/11/07 08:38:51 enricmcalvo Exp $
*/
#include <io.h>
#include <signal.h>
#include "contiki.h"
#include "contiki-net.h"
#include "dev/spi.h"
#include "dev/cc2420.h"
#ifndef CONF_SFD_TIMESTAMPS
#define CONF_SFD_TIMESTAMPS 0
#endif /* CONF_SFD_TIMESTAMPS */
#ifdef CONF_SFD_TIMESTAMPS
#include "cc2420-arch-sfd.h"
#endif
/*---------------------------------------------------------------------------*/
#if 0
// this is now handled in the ADXL345 accelerometer code as it uses irq on port1 too.
interrupt(CC2420_IRQ_VECTOR)
cc24240_port1_interrupt(void)
{
ENERGEST_ON(ENERGEST_TYPE_IRQ);
if(cc2420_interrupt()) {
LPM4_EXIT;
}
ENERGEST_OFF(ENERGEST_TYPE_IRQ);
}
#endif
/*---------------------------------------------------------------------------*/
void
cc2420_arch_init(void)
{
spi_init();
/* all input by default, set these as output */
CC2420_CSN_PORT(DIR) |= BV(CC2420_CSN_PIN);
CC2420_VREG_PORT(DIR) |= BV(CC2420_VREG_PIN);
CC2420_RESET_PORT(DIR) |= BV(CC2420_RESET_PIN);
#if CONF_SFD_TIMESTAMPS
cc2420_arch_sfd_init();
#endif
CC2420_SPI_DISABLE(); /* Unselect radio. */
}
/*---------------------------------------------------------------------------*/

244
platform/z1/dev/i2cmaster.c Normal file
View file

@ -0,0 +1,244 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* I2C communication device drivers for Zolertia Z1 sensor node.
* \author
* Enric M. Calvo, Zolertia <ecalvo@zolertia.com>
* Marcus Lundén, SICS <mlunden@sics.se>
*/
#include "i2cmaster.h"
signed char tx_byte_ctr, rx_byte_ctr;
unsigned char rx_buf[2];
unsigned char* tx_buf_ptr;
unsigned char* rx_buf_ptr;
unsigned char receive_data;
unsigned char transmit_data1;
unsigned char transmit_data2;
volatile unsigned int i; // volatile to prevent optimization
//------------------------------------------------------------------------------
// void i2c_receiveinit(unsigned char slave_address,
// unsigned char prescale)
//
// This function initializes the USCI module for master-receive operation.
//
// IN: unsigned char slave_address => Slave Address
// unsigned char prescale => SCL clock adjustment
//-----------------------------------------------------------------------------
void
i2c_receiveinit(u8_t slave_address) {
UCB1CTL1 = UCSWRST; // Enable SW reset
UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB1CTL1 = UCSSEL_2 | UCSWRST; // Use SMCLK, keep SW reset
UCB1BR0 = I2C_PRESC_400KHZ_LSB; // prescaler for 400 kHz data rate
UCB1BR1 = I2C_PRESC_400KHZ_MSB;
UCB1I2CSA = slave_address; // set slave address
UCB1CTL1 &= ~UCTR; // I2C Receiver
UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB1I2CIE = UCNACKIE;
#if I2C_RX_WITH_INTERRUPT
UC1IE = UCB1RXIE; // Enable RX interrupt if desired
#endif
}
//------------------------------------------------------------------------------
// void i2c_transmitinit(unsigned char slave_address,
// unsigned char prescale)
//
// Initializes USCI for master-transmit operation.
//
// IN: unsigned char slave_address => Slave Address
// unsigned char prescale => SCL clock adjustment
//------------------------------------------------------------------------------
void
i2c_transmitinit(u8_t slave_address) {
UCB1CTL1 |= UCSWRST; // Enable SW reset
UCB1CTL0 |= (UCMST | UCMODE_3 | UCSYNC); // I2C Master, synchronous mode
UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB1BR0 = I2C_PRESC_400KHZ_LSB; // prescaler for 400 kHz data rate
UCB1BR1 = I2C_PRESC_400KHZ_MSB;
UCB1I2CSA = slave_address; // Set slave address
UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB1I2CIE = UCNACKIE;
UC1IE = UCB1TXIE; // Enable TX ready interrupt
}
//------------------------------------------------------------------------------
// void i2c_receive_n(unsigned char byte_ctr, unsigned char * rx_buf)
// This function is used to start an I2C communication in master-receiver mode WITHOUT INTERRUPTS
// for more than 1 byte
// IN: unsigned char byte_ctr => number of bytes to be read
// OUT: unsigned char rx_buf => receive data buffer
// OUT: int n_received => number of bytes read
//------------------------------------------------------------------------------
static volatile u8_t rx_byte_tot = 0;
u8_t
i2c_receive_n(u8_t byte_ctr, u8_t *rx_buf) {
rx_byte_tot = byte_ctr;
rx_byte_ctr = byte_ctr;
rx_buf_ptr = rx_buf;
while ((UCB1CTL1 & UCTXSTT) || (UCB1STAT & UCNACKIFG)) // Slave acks address or not?
PRINTFDEBUG ("____ UCTXSTT not clear OR NACK received\n");
#if I2C_RX_WITH_INTERRUPT
PRINTFDEBUG(" RX Interrupts: YES \n");
// SPECIAL-CASE: Stop condition must be sent while receiving the 1st byte for 1-byte only read operations
if(rx_byte_tot == 1){ // See page 537 of slau144e.pdf
dint();
UCB1CTL1 |= UCTXSTT; // I2C start condition
while(UCB1CTL1 & UCTXSTT) // Waiting for Start bit to clear
PRINTFDEBUG ("____ STT clear wait\n");
UCB1CTL1 |= UCTXSTP; // I2C stop condition
eint();
}
else{ // all other cases
UCB1CTL1 |= UCTXSTT; // I2C start condition
}
return 0;
#else
u8_t n_received = 0;
PRINTFDEBUG(" RX Interrupts: NO \n");
UCB1CTL1 |= UCTXSTT; // I2C start condition
while (rx_byte_ctr > 0){
if (UC1IFG & UCB1RXIFG) { // Waiting for Data
rx_buf[rx_byte_tot - rx_byte_ctr] = UCB1RXBUF;
rx_byte_ctr--;
UC1IFG &= ~UCB1RXIFG; // Clear USCI_B1 RX int flag
n_received++;
}
}
UCB1CTL1 |= UCTXSTP; // I2C stop condition
return n_received;
#endif
}
//------------------------------------------------------------------------------
// u8_t i2c_busy()
//
// This function is used to check if there is communication in progress.
//
// OUT: unsigned char => 0: I2C bus is idle,
// 1: communication is in progress
//------------------------------------------------------------------------------
u8_t
i2c_busy(void) {
return (UCB1STAT & UCBBUSY);
}
/*----------------------------------------------------------------------------*/
/* Setup ports and pins for I2C use. */
void
i2c_enable(void) {
I2C_PxSEL |= (I2C_SDA | I2C_SCL); // Secondary function (USCI) selected
I2C_PxSEL2 |= (I2C_SDA | I2C_SCL); // Secondary function (USCI) selected
I2C_PxDIR |= I2C_SCL; // SCL is output (not needed?)
I2C_PxDIR &= ~I2C_SDA; // SDA is input (not needed?)
I2C_PxREN |= (I2C_SDA | I2C_SCL); // Activate internal pull-up/-down resistors
I2C_PxOUT |= (I2C_SDA | I2C_SCL); // Select pull-up resistors
}
/*----------------------------------------------------------------------------*/
//------------------------------------------------------------------------------
// void i2c_transmit_n(unsigned char byte_ctr, unsigned char *field)
//
// This function is used to start an I2C communication in master-transmit mode.
//
// IN: unsigned char byte_ctr => number of bytes to be transmitted
// unsigned char *tx_buf => Content to transmit. Read and transmitted from [0] to [byte_ctr]
//------------------------------------------------------------------------------
static volatile u8_t tx_byte_tot = 0;
void
i2c_transmit_n(u8_t byte_ctr, u8_t *tx_buf) {
tx_byte_tot = byte_ctr;
tx_byte_ctr = byte_ctr;
tx_buf_ptr = tx_buf;
UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
}
/*----------------------------------------------------------------------------*/
interrupt (USCIAB1TX_VECTOR)
i2c_tx_interrupt (void) {
// TX Part
if (UC1IFG & UCB1TXIFG) { // TX int. condition
if (tx_byte_ctr == 0) {
UCB1CTL1 |= UCTXSTP; // I2C stop condition
UC1IFG &= ~UCB1TXIFG; // Clear USCI_B1 TX int flag
}
else {
UCB1TXBUF = tx_buf_ptr[tx_byte_tot - tx_byte_ctr];
tx_byte_ctr--;
}
}
// RX Part
#if I2C_RX_WITH_INTERRUPT
else if (UC1IFG & UCB1RXIFG){ // RX int. condition
if (rx_byte_ctr == 0){
// Only for 1-byte transmissions, STOP is handled in receive_n_int
if (rx_byte_tot != 1)
UCB1CTL1 |= UCTXSTP; // I2C stop condition
UC1IFG &= ~UCB1RXIFG; // Clear USCI_B1 RX int flag. XXX Just in case, check if necessary
}
else {
rx_buf_ptr[rx_byte_tot - rx_byte_ctr] = UCB1RXBUF;
rx_byte_ctr--;
}
}
#endif
}
interrupt(USCIAB1RX_VECTOR)
i2c_rx_interrupt(void) {
if (UCB1STAT & UCNACKIFG){
PRINTFDEBUG("!!! NACK received in RX\n");
UCB1CTL1 |= UCTXSTP;
UCB1STAT &= ~UCNACKIFG;
}
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* I2C communication device driver header file for Zolertia Z1 sensor node.
* \author
* Enric Calvo, Zolertia <ecalvo@zolertia.com>
* Marcus Lundén, SICS <mlunden@sics.se>
*/
#ifndef __I2CMASTER_H__
#define __I2CMASTER_H__
#include <stdio.h>
#include <signal.h>
#include <io.h>
#include <contiki.h>
#include <dev/spi.h>
#include <dev/leds.h>
void i2c_enable(void);
void i2c_receiveinit(u8_t slave_address);
u8_t i2c_receive_n(u8_t byte_ctr, u8_t *rx_buf);
void i2c_transmitinit(u8_t slave_address);
void i2c_transmit_n(u8_t byte_ctr, u8_t *tx_buf);
u8_t i2c_busy(void);
//XXX Temporary place for defines that are lacking in mspgcc4's gpio.h
#ifndef P5SEL2_
#define P5SEL2_ 0x0045 /* Port 5 Selection 2*/
sfrb(P5SEL2, P5SEL2_);
#endif
//XXX Should these defines be in the contiki-conf.h to make it more platform-independent?
#define I2C_PxDIR P5DIR
#define I2C_PxIN P5IN
#define I2C_PxOUT P5OUT
#define I2C_PxSEL P5SEL
#define I2C_PxSEL2 P5SEL2
#define I2C_PxREN P5REN
#define I2C_SDA (1 << 1) //SDA == P5.1
#define I2C_SCL (1 << 2) //SCL == P5.2
#define I2C_PRESC_1KHZ_LSB 0x00
#define I2C_PRESC_1KHZ_MSB 0x20
#define I2C_PRESC_100KHZ_LSB 0x50
#define I2C_PRESC_100KHZ_MSB 0x00
#define I2C_PRESC_400KHZ_LSB 0x14
#define I2C_PRESC_400KHZ_MSB 0x00
// I2C configuration with RX interrupts
#ifdef I2C_CONF_RX_WITH_INTERRUPT
#define I2C_RX_WITH_INTERRUPT I2C_CONF_RX_WITH_INTERRUPT // XXX Move I2C_CONF_RX_WITH_INTERRUPT to contiki-conf.h or platform-conf.h
#else /* I2C_CONF_RX_WITH_INTERRUPT */
#define I2C_RX_WITH_INTERRUPT 1
#endif /* I2C_CONF_RX_WITH_INTERRUPT */
#if 0
#define PRINTFDEBUG(...) printf(__VA_ARGS__)
#else
#define PRINTFDEBUG(...)
#endif
#endif /* #ifdef __I2CMASTER_H__ */