Contiki-NG
Loading...
Searching...
No Matches
adxl345.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010, Swedish Institute of Computer Science.
3 * Copyright (c) 2016, Zolertia <http://www.zolertia.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the Institute nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * This file is part of the Contiki operating system.
31 *
32 */
33/*---------------------------------------------------------------------------*/
34/**
35 * \file
36 * Device drivers for adxl345 accelerometer in Zolertia Z1.
37 * \author
38 * Marcus Lundén, SICS <mlunden@sics.se>
39 * Enric M. Calvo, Zolertia <ecalvo@zolertia.com>
40 * Antonio Lignan, Zolertia <alinan@zolertia.com>
41 */
42/*---------------------------------------------------------------------------*/
43#include <stdio.h>
44#include "contiki.h"
45#include "adxl345.h"
46#include "cc2420.h"
47#include "i2cmaster.h"
48#include "isr_compat.h"
49#include "lib/sensors.h"
50/*---------------------------------------------------------------------------*/
51#define DEBUG 0
52#if DEBUG
53#define PRINTF(...) printf(__VA_ARGS__)
54#else
55#define PRINTF(...)
56#endif
57/*---------------------------------------------------------------------------*/
58static uint8_t enabled;
59/*---------------------------------------------------------------------------*/
60/* Callback pointers when interrupt occurs */
61void (*accm_int1_cb)(uint8_t reg);
62void (*accm_int2_cb)(uint8_t reg);
63/*---------------------------------------------------------------------------*/
64/* Bitmasks for the interrupts */
65static uint16_t int1_mask = 0, int2_mask = 0;
66
67/* Default values for adxl345 at startup.
68 * This will be sent to the adxl345 in a
69 * stream at init to set it up in a default state
70 */
71
72static uint8_t adxl345_default_settings[] = {
73 /* Note, as the two first two bulks are to be written in a stream, they contain
74 * the register address as first byte in that section.
75 * 0--14 are in one stream, start at ADXL345_THRESH_TAP
76 */
77 /* XXX NB Register address, not register value!! */
78 ADXL345_THRESH_TAP,
79 ADXL345_THRESH_TAP_DEFAULT,
80 ADXL345_OFSX_DEFAULT,
81 ADXL345_OFSY_DEFAULT,
82 ADXL345_OFSZ_DEFAULT,
83 ADXL345_DUR_DEFAULT,
84 ADXL345_LATENT_DEFAULT,
85 ADXL345_WINDOW_DEFAULT,
86 ADXL345_THRESH_ACT_DEFAULT,
87 ADXL345_THRESH_INACT_DEFAULT,
88 ADXL345_TIME_INACT_DEFAULT,
89 ADXL345_ACT_INACT_CTL_DEFAULT,
90 ADXL345_THRESH_FF_DEFAULT,
91 ADXL345_TIME_FF_DEFAULT,
92 ADXL345_TAP_AXES_DEFAULT,
93
94 /* 15--19 start at ADXL345_BW_RATE */
95 /* XXX NB Register address, not register value!! */
96 ADXL345_BW_RATE,
97 ADXL345_BW_RATE_DEFAULT,
98 ADXL345_POWER_CTL_DEFAULT,
99 ADXL345_INT_ENABLE_DEFAULT,
100 ADXL345_INT_MAP_DEFAULT,
101
102 /* These two: 20, 21 write separately */
103 ADXL345_DATA_FORMAT_DEFAULT,
104 ADXL345_FIFO_CTL_DEFAULT
105};
106/*---------------------------------------------------------------------------*/
107PROCESS(accmeter_process, "Accelerometer process");
108/*---------------------------------------------------------------------------*/
109static void
110accm_write_reg(uint8_t reg, uint8_t val)
111{
112 uint8_t tx_buf[] = {reg, val};
113
114 i2c_transmitinit(ADXL345_ADDR);
115 while (i2c_busy());
116 PRINTF("ADXL345: I2C Ready to TX\n");
117
118 i2c_transmit_n(2, tx_buf);
119 while (i2c_busy());
120 PRINTF("ADXL345: WRITE_REG 0x%02X @ reg 0x%02X\n", val, reg);
121}
122/*---------------------------------------------------------------------------*/
123/* First byte in stream must be the register address to begin writing to.
124 * The data is then written from second byte and increasing.
125 */
126static void
127accm_write_stream(uint8_t len, uint8_t *data)
128{
129 i2c_transmitinit(ADXL345_ADDR);
130 while (i2c_busy());
131 PRINTF("ADXL345: I2C Ready to TX(stream)\n");
132
133 i2c_transmit_n(len, data); // start tx and send conf reg
134 while (i2c_busy());
135 PRINTF("ADXL345: WRITE_STR %u B to 0x%02X\n", len, data[0]);
136}
137
138/*---------------------------------------------------------------------------*/
139static uint8_t
140accm_read_reg(uint8_t reg)
141{
142 uint8_t retVal = 0;
143 uint8_t rtx = reg;
144 PRINTF("ADXL345: READ_REG 0x%02X\n", reg);
145
146 /* transmit the register to read */
147 i2c_transmitinit(ADXL345_ADDR);
148 while (i2c_busy());
149 i2c_transmit_n(1, &rtx);
150 while (i2c_busy());
151
152 /* receive the data */
153 i2c_receiveinit(ADXL345_ADDR);
154 while (i2c_busy());
155 i2c_receive_n(1, &retVal);
156 while (i2c_busy());
157
158 return retVal;
159}
160/*---------------------------------------------------------------------------*/
161static void
162accm_read_stream(uint8_t reg, uint8_t len, uint8_t *whereto)
163{
164 uint8_t rtx = reg;
165 PRINTF("ADXL345: READ_STR %u B from 0x%02X\n", len, reg);
166
167 /* transmit the register to start reading from */
168 i2c_transmitinit(ADXL345_ADDR);
169 while (i2c_busy());
170 i2c_transmit_n(1, &rtx);
171 while (i2c_busy());
172
173 /* receive the data */
174 i2c_receiveinit(ADXL345_ADDR);
175 while (i2c_busy());
176 i2c_receive_n(len, whereto);
177 while (i2c_busy());
178}
179
180/*---------------------------------------------------------------------------*/
181/* Read an axis of the accelerometer (x, y or z). Return value is a signed
182 * 10 bit int.
183 * The resolution of the acceleration measurement can be increased up to 13 bit,
184 * but will change the data format of this read out. Refer to the data sheet if
185 * so is wanted/needed.
186 */
187int16_t
188accm_read_axis(enum ADXL345_AXIS axis)
189{
190 int16_t rd = 0;
191 uint8_t tmp[2];
192 if(axis > Z_AXIS){
193 return 0;
194 }
195 accm_read_stream(ADXL345_DATAX0 + axis, 2, &tmp[0]);
196 rd = (int16_t)(tmp[0] | (tmp[1]<<8));
197 return rd;
198}
199/*---------------------------------------------------------------------------*/
200int
201accm_set_grange(uint8_t grange)
202{
203 uint8_t tempreg = 0;
204
205 if(grange > ADXL345_RANGE_16G) {
206 PRINTF("ADXL345: grange invalid: %u\n", grange);
207 return ADXL345_ERROR;
208 }
209
210 if(!enabled) {
211 return ADXL345_ERROR;
212 }
213
214 /* Keep the previous contents of the register, zero out the last two bits */
215 tempreg = (accm_read_reg(ADXL345_DATA_FORMAT) & 0xFC);
216 tempreg |= grange;
217 accm_write_reg(ADXL345_DATA_FORMAT, tempreg);
218 return ADXL345_SUCCESS;
219}
220
221/*---------------------------------------------------------------------------*/
222void
223accm_init(void)
224{
225 PRINTF("ADXL345: init\n");
226 accm_int1_cb = NULL;
227 accm_int2_cb = NULL;
228
229 /* Set up ports and pins for interrups. */
230 ADXL345_DIR &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
231 ADXL345_SEL &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
232 ADXL345_SEL2 &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
233
234 /* Set up ports and pins for I2C communication */
235 i2c_enable();
236
237 /* set default register values. */
238 accm_write_stream(15, &adxl345_default_settings[0]);
239 accm_write_stream(5, &adxl345_default_settings[15]);
240 accm_write_reg(ADXL345_DATA_FORMAT, adxl345_default_settings[20]);
241 accm_write_reg(ADXL345_FIFO_CTL, adxl345_default_settings[21]);
242
243 process_start(&accmeter_process, NULL);
244
245 /* Enable msp430 interrupts on the two interrupt pins. */
246 dint();
247 /* low to high transition interrupts */
248 ADXL345_IES &=~ (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
249 /* enable interrupts */
250 ADXL345_IE |= (ADXL345_INT1_PIN | ADXL345_INT2_PIN);
251 eint();
252
253 enabled = 1;
254}
255/*---------------------------------------------------------------------------*/
256void
257accm_stop(void)
258{
259 dint();
260 ADXL345_IE &= ~(ADXL345_INT1_PIN | ADXL345_INT2_PIN);
261 accm_write_reg(ADXL345_INT_ENABLE, ~(int1_mask | int2_mask));
262 accm_write_reg(ADXL345_INT_MAP, ~int2_mask);
263 eint();
264 enabled = 0;
265}
266/*---------------------------------------------------------------------------*/
267int
268accm_set_irq(uint8_t int1, uint8_t int2)
269{
270 if(!enabled) {
271 return ADXL345_ERROR;
272 }
273
274 /* Set the corresponding interrupt mapping to INT1 or INT2 */
275 PRINTF("ADXL345: IRQs set to INT1: 0x%02X IRQ2: 0x%02X\n", int1, int2);
276
277 int1_mask = int1;
278 int2_mask = int2;
279
280 accm_write_reg(ADXL345_INT_ENABLE, (int1 | int2));
281 /* int1 bits are zeroes in the map register so this is for both ints */
282 accm_write_reg(ADXL345_INT_MAP, int2);
283 return ADXL345_SUCCESS;
284}
285/*---------------------------------------------------------------------------*/
286/* Invoked after an interrupt happened. Reads the interrupt source reg at the
287 * accelerometer, which resets the interrupts, and invokes the corresponding
288 * callback. It passes the source register value so the callback can determine
289 * what interrupt happened, if several interrupts are mapped to the same pin.
290 */
291static void
292poll_handler(void)
293{
294 uint8_t ireg = 0;
295 ireg = accm_read_reg(ADXL345_INT_SOURCE);
296
297 /* Invoke callbacks for the corresponding interrupts */
298 if(ireg & int1_mask){
299 if(accm_int1_cb != NULL){
300 PRINTF("ADXL345: INT1 cb invoked\n");
301 accm_int1_cb(ireg);
302 }
303 } else if(ireg & int2_mask){
304 if(accm_int2_cb != NULL){
305 PRINTF("ADXL345: INT2 cb invoked\n");
306 accm_int2_cb(ireg);
307 }
308 }
309}
310/*---------------------------------------------------------------------------*/
311/* This process is sleeping until an interrupt from the accelerometer occurs,
312 * which polls this process from the interrupt service routine. */
313PROCESS_THREAD(accmeter_process, ev, data)
314{
315 PROCESS_POLLHANDLER(poll_handler());
318 while(1){
320 }
321 PROCESS_END();
322}
323/*---------------------------------------------------------------------------*/
324/* This interrupt vector is shared with the interrupts from CC2420, so that
325 * was moved here
326 */
327static struct timer suppressTimer1, suppressTimer2;
328
329ISR(PORT1, port1_isr)
330{
331 /* ADXL345_IFG.x goes high when interrupt occurs, use to check what
332 * interrupted
333 */
334 if((ADXL345_IFG & ADXL345_INT1_PIN) && !(ADXL345_IFG & BV(CC2420_FIFOP_PIN))){
335 /* Check if this should be suppressed or not */
336 if(timer_expired(&suppressTimer1)) {
337 timer_set(&suppressTimer1, SUPPRESS_TIME_INT1);
338 ADXL345_IFG &= ~ADXL345_INT1_PIN; // clear interrupt flag
339 process_poll(&accmeter_process);
340 LPM4_EXIT;
341 }
342 } else if((ADXL345_IFG & ADXL345_INT2_PIN) &&
343 !(ADXL345_IFG & BV(CC2420_FIFOP_PIN))){
344 /* Check if this should be suppressed or not */
345 if(timer_expired(&suppressTimer2)) {
346 timer_set(&suppressTimer2, SUPPRESS_TIME_INT2);
347 /* clear interrupt flag */
348 ADXL345_IFG &= ~ADXL345_INT2_PIN;
349 process_poll(&accmeter_process);
350 LPM4_EXIT;
351 }
352 } else {
353 /* CC2420 interrupt */
354 if(cc2420_interrupt()) {
355 LPM4_EXIT;
356 }
357 }
358}
359/*---------------------------------------------------------------------------*/
360static int
361configure(int type, int value)
362{
363 if(type != SENSORS_ACTIVE) {
364 return ADXL345_ERROR;
365 }
366
367 if(value) {
368 accm_init();
369 } else {
370 accm_stop();
371 }
372 enabled = value;
373 return ADXL345_SUCCESS;
374}
375/*---------------------------------------------------------------------------*/
376static int
377status(int type)
378{
379 switch(type) {
380 case SENSORS_ACTIVE:
381 case SENSORS_READY:
382 return enabled;
383 }
384 return ADXL345_SUCCESS;
385}
386/*---------------------------------------------------------------------------*/
387static int
388value(int type)
389{
390 if(!enabled) {
391 return ADXL345_ERROR;
392 }
393
394 if((type != X_AXIS) && (type != Y_AXIS) && (type != Z_AXIS)) {
395 return ADXL345_ERROR;
396 }
397
398 switch(type) {
399 case X_AXIS:
400 return accm_read_axis(X_AXIS);
401 case Y_AXIS:
402 return accm_read_axis(Y_AXIS);
403 case Z_AXIS:
404 return accm_read_axis(Z_AXIS);
405 default:
406 return ADXL345_ERROR;
407 }
408}
409/*---------------------------------------------------------------------------*/
410SENSORS_SENSOR(adxl345, ADXL345_SENSOR, value, configure, status);
411/*---------------------------------------------------------------------------*/
Device drivers header file for adxl345 accelerometer in Zolertia Z1.
CC2420 driver header file.
#define PROCESS(name, strname)
Declare a process.
Definition process.h:307
#define PROCESS_EXITHANDLER(handler)
Specify an action when a process exits.
Definition process.h:254
#define PROCESS_POLLHANDLER(handler)
Specify an action when a process is polled.
Definition process.h:242
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition process.h:120
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition process.h:157
#define PROCESS_END()
Define the end of a process.
Definition process.h:131
void process_start(struct process *p, process_data_t data)
Start a process.
Definition process.c:107
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition process.h:273
void process_poll(struct process *p)
Request a process to be polled.
Definition process.c:375
void timer_set(struct timer *t, clock_time_t interval)
Set a timer.
Definition timer.c:64
bool timer_expired(struct timer *t)
Check if a timer has expired.
Definition timer.c:123
I2C communication device driver header file for Zolertia Z1 sensor node.
A timer.
Definition timer.h:84