Contiki-NG
Loading...
Searching...
No Matches
grove-gyro.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016, Zolertia <http://www.zolertia.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 *
31 */
32/*---------------------------------------------------------------------------*/
33/**
34 * \addtogroup zoul-grove-gyro-sensor
35 * @{
36 *
37 * \file
38 * Grove's 3-axis gyroscope driver
39 * \author
40 * Antonio Lignan <alinan@zolertia.com>
41 */
42/*---------------------------------------------------------------------------*/
43#include <stdio.h>
44#include "contiki.h"
45#include "dev/i2c.h"
46#include "dev/grove-gyro.h"
47#include "dev/gpio-hal.h"
48#include "lib/sensors.h"
49#include "dev/watchdog.h"
50/*---------------------------------------------------------------------------*/
51#define DEBUG 0
52#if DEBUG
53#define PRINTF(...) printf(__VA_ARGS__)
54#else
55#define PRINTF(...)
56#endif
57/*---------------------------------------------------------------------------*/
58#define GROVE_GYRO_INT_PORT_BASE GPIO_PORT_TO_BASE(I2C_INT_PORT)
59#define GROVE_GYRO_INT_PIN_MASK GPIO_PIN_MASK(I2C_INT_PIN)
60/*---------------------------------------------------------------------------*/
61static uint8_t enabled;
62static uint8_t power_mgmt;
63static uint8_t int_en;
64/*---------------------------------------------------------------------------*/
65grove_gyro_values_t gyro_values;
66/*---------------------------------------------------------------------------*/
67void (*grove_gyro_int_callback)(uint8_t value);
68/*---------------------------------------------------------------------------*/
69static int
70grove_gyro_read_reg(uint8_t reg, uint8_t *buf, uint8_t num)
71{
72 if((buf == NULL) || (num <= 0)) {
73 return GROVE_GYRO_ERROR;
74 }
75
77 if(i2c_single_send(GROVE_GYRO_ADDR, reg) == I2C_MASTER_ERR_NONE) {
78 if(i2c_burst_receive(GROVE_GYRO_ADDR, buf, num) == I2C_MASTER_ERR_NONE) {
79 return GROVE_GYRO_SUCCESS;
80 }
81 }
82
83 PRINTF("Gyro: failed to read from sensor\n");
84 return GROVE_GYRO_ERROR;
85}
86/*---------------------------------------------------------------------------*/
87static int
88grove_gyro_write_reg(uint8_t *buf, uint8_t num)
89{
90 if((buf == NULL) || (num <= 0)) {
91 PRINTF("Gyro: invalid write values\n");
92 return GROVE_GYRO_ERROR;
93 }
94
96 if(i2c_burst_send(GROVE_GYRO_ADDR, buf, num) == I2C_MASTER_ERR_NONE) {
97 return GROVE_GYRO_SUCCESS;
98 }
99 return GROVE_GYRO_ERROR;
100}
101/*---------------------------------------------------------------------------*/
102static int
103grove_gyro_sampdiv(uint8_t value)
104{
105 uint8_t buf[2];
106 buf[0] = GROVE_GYRO_SMPLRT_DIV;
107 buf[1] = value;
108 if(grove_gyro_write_reg(buf, 2) == GROVE_GYRO_SUCCESS) {
109 PRINTF("Gyro: new sampdiv 0x%02X\n", value);
110 return GROVE_GYRO_SUCCESS;
111 }
112 PRINTF("Gyro: failed to set sampdiv\n");
113 return GROVE_GYRO_ERROR;
114}
115/*---------------------------------------------------------------------------*/
116static uint8_t
117grove_gyro_clear_interrupt(void)
118{
119 uint8_t aux = 0;
120
121 /* Clear interrupt */
122 grove_gyro_read_reg(GROVE_GYRO_INT_STATUS, &aux, 1);
123
124 if(aux & GROVE_GYRO_INT_STATUS_DATA_RDY_MASK) {
125 return GROVE_GYRO_INT_STATUS_DATA_RDY_MASK;
126 }
127
128 return 0;
129}
130/*---------------------------------------------------------------------------*/
131static int
132grove_gyro_interrupt(uint8_t value)
133{
134 uint8_t buf[2];
135 buf[0] = GROVE_GYRO_INT_CFG;
136 buf[1] = value;
137 if(grove_gyro_write_reg(buf, 2) == GROVE_GYRO_SUCCESS){
138 PRINTF("Gyro: interrupt cfg 0x%02X\n", value);
139 return GROVE_GYRO_SUCCESS;
140 }
141 PRINTF("Gyro: failed to change interrupt config\n");
142 return GROVE_GYRO_ERROR;
143}
144/*---------------------------------------------------------------------------*/
145static int
146grove_gyro_reset(void)
147{
148 uint8_t buf[2];
149 buf[0] = GROVE_GYRO_PWR_MGMT;
150
151 /* Read the power management status as well to force sync */
152 if(grove_gyro_read_reg(GROVE_GYRO_PWR_MGMT, &power_mgmt, 1) ==
153 GROVE_GYRO_SUCCESS) {
154 PRINTF("Gyro: current power mgmt 0x%02X\n", power_mgmt);
155 buf[1] = power_mgmt + GROVE_GYRO_PWR_MGMT_RESET;
156 if(grove_gyro_write_reg(buf, 2) == GROVE_GYRO_SUCCESS) {
157 PRINTF("Gyro: restarted with 0x%02X, now with default values\n", buf[1]);
158 return GROVE_GYRO_SUCCESS;
159 }
160 }
161 PRINTF("Gyro: failed to restart\n");
162 return GROVE_GYRO_ERROR;
163}
164/*---------------------------------------------------------------------------*/
165static int
166grove_gyro_osc(uint8_t value)
167{
168 uint8_t buf[2];
169 buf[0] = GROVE_GYRO_PWR_MGMT;
170
171 /* Read the power management status as well to force sync */
172 if(grove_gyro_read_reg(GROVE_GYRO_PWR_MGMT, &power_mgmt, 1) ==
173 GROVE_GYRO_SUCCESS) {
174 PRINTF("Gyro: current power mgmt 0x%02X\n", power_mgmt);
175 power_mgmt &= ~GROVE_GYRO_PWR_MGMT_CLK_SEL_MASK;
176 buf[1] = power_mgmt + value;
177 if(grove_gyro_write_reg(buf, 2) == GROVE_GYRO_SUCCESS) {
178 PRINTF("Gyro: new clock source 0x%02X\n", buf[1]);
179 return GROVE_GYRO_SUCCESS;
180 }
181 }
182 PRINTF("Gyro: failed to change the clock source\n");
183 return GROVE_GYRO_ERROR;
184}
185/*---------------------------------------------------------------------------*/
186static int
187grove_gyro_power_mgmt(uint8_t value, uint8_t type)
188{
189 uint8_t buf[2];
190 buf[0] = GROVE_GYRO_PWR_MGMT;
191
192 if((type != GROVE_GYRO_POWER_ON) && (type != GROVE_GYRO_POWER_OFF)) {
193 PRINTF("Gyro: invalid power command type\n");
194 return GROVE_GYRO_ERROR;
195 }
196
197 /* Read the power management status as well to force sync */
198 if(grove_gyro_read_reg(GROVE_GYRO_PWR_MGMT, &power_mgmt, 1) ==
199 GROVE_GYRO_SUCCESS) {
200 PRINTF("Gyro: current power mgmt 0x%02X\n", power_mgmt);
201
202 if(type == GROVE_GYRO_POWER_ON) {
203 power_mgmt &= ~value;
204 } else {
205 power_mgmt |= value;
206 }
207
208 buf[1] = power_mgmt;
209 if(grove_gyro_write_reg(buf, 2) == GROVE_GYRO_SUCCESS) {
210 PRINTF("Gyro: new power management register value 0x%02X\n", power_mgmt);
211
212 /* Power-up delay */
213 if(type == GROVE_GYRO_POWER_ON) {
214 clock_delay_usec(25000);
215 }
216
217 return GROVE_GYRO_SUCCESS;
218 }
219 }
220 PRINTF("Gyro: power management fail\n");
221
222 return GROVE_GYRO_ERROR;
223}
224/*---------------------------------------------------------------------------*/
225static int
226grove_gyro_dlpf(uint8_t value)
227{
228 uint8_t buf[2];
229 buf[0] = GROVE_GYRO_DLPF_FS;
230 buf[1] = GROVE_GYRO_DLPF_FS_SEL + value;
231
232 if(grove_gyro_write_reg(buf, 2) == GROVE_GYRO_SUCCESS) {
233 /* Double-check */
234 if(grove_gyro_read_reg(GROVE_GYRO_DLPF_FS, &buf[0], 1) ==
235 GROVE_GYRO_SUCCESS) {
236 if(buf[0] == buf[1]) {
237 PRINTF("Gyro: updated lp/sr 0x%02X\n", buf[0]);
238 return GROVE_GYRO_SUCCESS;
239 } else {
240 PRINTF("Gyro: DLPF register value mismatch\n");
241 return GROVE_GYRO_ERROR;
242 }
243 }
244 }
245
246 PRINTF("Gyro: failed to change the lp/sr\n");
247 return GROVE_GYRO_ERROR;
248}
249/*---------------------------------------------------------------------------*/
250static uint16_t
251grove_gyro_convert_to_value(uint16_t val)
252{
253 uint32_t aux;
254
255 /* Convert from 2C's to 10's, as we care about º/s negative quantifier doesn't
256 * matter, so we ommit flaging the sign
257 */
258 if(val & 0x8000) {
259 val = (~val + 1);
260 }
261
262 /* ITG-3200 datasheet: sensitivity 14.375 LSB/(º/s) to get º/s */
263 aux = val * 6956;
264 aux /= 1000;
265
266 return (uint16_t)aux;
267}
268/*---------------------------------------------------------------------------*/
269static void
270grove_gyro_convert(uint8_t *buf, uint8_t type)
271{
272 uint16_t aux;
273
274 if(type & GROVE_GYRO_X) {
275 aux = (buf[0] << 8) + buf[1];
276 PRINTF("Gyro: X_axis (raw) 0x%02X\n", aux);
277 gyro_values.x = grove_gyro_convert_to_value(aux);
278 }
279
280 if(type & GROVE_GYRO_Y) {
281 aux = (buf[2] << 8) + buf[3];
282 PRINTF("Gyro: Y_axis (raw) 0x%02X\n", aux);
283 gyro_values.y = grove_gyro_convert_to_value(aux);
284 }
285
286 if(type & GROVE_GYRO_Z) {
287 aux = (buf[4] << 8) + buf[5];
288 PRINTF("Gyro: Z_axis (raw) 0x%02X\n", aux);
289 gyro_values.z = grove_gyro_convert_to_value(aux);
290 }
291
292 if(type == GROVE_GYRO_TEMP) {
293 aux = (buf[0] << 8) + buf[1];
294 PRINTF("Gyro: Temp (raw) 0x%02X\n", aux);
295 /* ITG-3200 datasheet: offset -13200, sensitivity 280 LSB/ºC */
296 aux = (aux + 13200) / 28;
297 aux += 350;
298 gyro_values.temp = (int16_t)aux;
299 }
300}
301/*---------------------------------------------------------------------------*/
302static int
303grove_gyro_read(int type)
304{
305 uint8_t reg;
306 uint8_t len;
307 uint8_t buf_ptr;
308 uint8_t buf[GROVE_GYRO_MAX_DATA];
309
310 len = (type == GROVE_GYRO_XYZ) ? GROVE_GYRO_MAX_DATA : 2;
311
312 switch(type) {
313 case GROVE_GYRO_X:
314 case GROVE_GYRO_XYZ:
315 buf_ptr = 0;
316 reg = GROVE_GYRO_XOUT_H;
317 break;
318 case GROVE_GYRO_Y:
319 buf_ptr = 2;
320 reg = GROVE_GYRO_YOUT_H;
321 break;
322 case GROVE_GYRO_Z:
323 buf_ptr = 4;
324 reg = GROVE_GYRO_ZOUT_H;
325 break;
326 case GROVE_GYRO_TEMP:
327 buf_ptr = 0;
328 reg = GROVE_GYRO_TEMP_OUT_H;
329 break;
330 case GROVE_GYRO_ADDR:
331 buf_ptr = 0;
332 len = 1;
333 reg = GROVE_GYRO_WHO_AM_I;
334 break;
335 default:
336 PRINTF("Gyro: invalid value requested\n");
337 return GROVE_GYRO_ERROR;
338 }
339
340 if(grove_gyro_read_reg(reg, &buf[buf_ptr], len) == GROVE_GYRO_SUCCESS) {
341 if(type == GROVE_GYRO_ADDR) {
342 PRINTF("Gyro: I2C_addr 0x%02X\n", buf[0]);
343 return buf[0];
344 }
345 grove_gyro_convert(buf, type);
346 return GROVE_GYRO_SUCCESS;
347 }
348
349 PRINTF("Gyro: failed to change the lp/sr\n");
350 return GROVE_GYRO_ERROR;
351}
352/*---------------------------------------------------------------------------*/
353static int
354grove_gyro_calibrate(void)
355{
356 uint8_t i;
357 uint8_t buf[GROVE_GYRO_MAX_DATA];
358 uint8_t power_mgmt_backup;
359 uint32_t x, y, z;
360
361 /* Disable interrupts */
362 if(int_en) {
363 if(grove_gyro_interrupt(GROVE_GYRO_INT_CFG_DISABLE) == GROVE_GYRO_ERROR) {
364 PRINTF("Gyro: failed to disable the interrupts\n");
365 return GROVE_GYRO_ERROR;
366 }
367 GPIO_DISABLE_INTERRUPT(GROVE_GYRO_INT_PORT_BASE, GROVE_GYRO_INT_PIN_MASK);
368 }
369
370 /* Turn on the 3-axis, save the current config */
371 if(grove_gyro_read_reg(GROVE_GYRO_PWR_MGMT, &power_mgmt_backup, 1) ==
372 GROVE_GYRO_ERROR) {
373 PRINTF("Gyro: failed to read power mgmt config\n");
374 return GROVE_GYRO_ERROR;
375 }
376
377 if(grove_gyro_power_mgmt(GROVE_GYRO_ALL, GROVE_GYRO_POWER_ON) ==
378 GROVE_GYRO_ERROR) {
379 PRINTF("Gyro: failed to bring sensor up\n");
380 return GROVE_GYRO_ERROR;
381 }
382
383 x = 0;
384 y = 0;
385 z = 0;
386
387 for (i = 0; i < GROVE_GYRO_CALIB_SAMPLES; i++){
388 clock_delay_usec(GROVE_GYRO_CALIB_TIME_US);
390 if(grove_gyro_read_reg(GROVE_GYRO_XOUT_H, buf, GROVE_GYRO_MAX_DATA) ==
391 GROVE_GYRO_SUCCESS) {
392 x += (buf[0] << 8) + buf[1];
393 y += (buf[2] << 8) + buf[3];
394 z += (buf[4] << 8) + buf[5];
395 }
396 }
397
398 gyro_values.x_offset = ABS(x)/GROVE_GYRO_CALIB_SAMPLES;
399 gyro_values.y_offset = ABS(y)/GROVE_GYRO_CALIB_SAMPLES;
400 gyro_values.z_offset = ABS(z)/GROVE_GYRO_CALIB_SAMPLES;
401
402 PRINTF("Gyro: x_offset (RAW) 0x%02X\n", gyro_values.x_offset);
403 PRINTF("Gyro: y_offset (RAW) 0x%02X\n", gyro_values.y_offset);
404 PRINTF("Gyro: z_offset (RAW) 0x%02X\n", gyro_values.z_offset);
405
406 gyro_values.x_offset = grove_gyro_convert_to_value(gyro_values.x_offset);
407 gyro_values.y_offset = grove_gyro_convert_to_value(gyro_values.y_offset);
408 gyro_values.z_offset = grove_gyro_convert_to_value(gyro_values.z_offset);
409
410 PRINTF("Gyro: x_offset (converted) %d\n", gyro_values.x_offset);
411 PRINTF("Gyro: y_offset (converted) %d\n", gyro_values.y_offset);
412 PRINTF("Gyro: z_offset (converted) %d\n", gyro_values.z_offset);
413
414 /* Cleaning up */
415 buf[0] = GROVE_GYRO_PWR_MGMT;
416 buf[1] = power_mgmt_backup;
417
418 if(grove_gyro_write_reg(&buf[0], 2) != GROVE_GYRO_SUCCESS) {
419 PRINTF("Gyro: failed restoring power mgmt (0x%02X)\n", power_mgmt_backup);
420 return GROVE_GYRO_ERROR;
421 }
422
423 if(int_en) {
424 if(grove_gyro_interrupt(GROVE_GYRO_INT_CFG_RAW_READY_EN +
425 GROVE_GYRO_INT_CFG_LATCH_EN) == GROVE_GYRO_ERROR) {
426 PRINTF("Gyro: failed to enable the interrupt\n");
427 return GROVE_GYRO_ERROR;
428 }
429
430 GPIO_ENABLE_INTERRUPT(GROVE_GYRO_INT_PORT_BASE, GROVE_GYRO_INT_PIN_MASK);
431 }
432
433 return GROVE_GYRO_SUCCESS;
434}
435/*---------------------------------------------------------------------------*/
436PROCESS(grove_gyro_int_process, "Grove gyroscope interrupt process handler");
437/*---------------------------------------------------------------------------*/
438PROCESS_THREAD(grove_gyro_int_process, ev, data)
439{
442
443 static uint8_t axis_to_read = 0;
444
445 while(1) {
446 PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
447 if(grove_gyro_clear_interrupt() == GROVE_GYRO_INT_STATUS_DATA_RDY_MASK) {
448
449 axis_to_read += (power_mgmt & GROVE_GYRO_X) ? 0: GROVE_GYRO_X;
450 axis_to_read += (power_mgmt & GROVE_GYRO_Y) ? 0: GROVE_GYRO_Y;
451 axis_to_read += (power_mgmt & GROVE_GYRO_Z) ? 0: GROVE_GYRO_Z;
452
453 if(grove_gyro_read(axis_to_read) == GROVE_GYRO_SUCCESS) {
454 grove_gyro_int_callback(GROVE_GYRO_SUCCESS);
455 }
456 }
457 }
458 PROCESS_END();
459}
460/*---------------------------------------------------------------------------*/
461static void
462grove_gyro_interrupt_handler(gpio_hal_pin_mask_t pin_mask)
463{
464 process_poll(&grove_gyro_int_process);
465}
466/*---------------------------------------------------------------------------*/
467static gpio_hal_event_handler_t gyro_handler = {
468 .next = NULL,
469 .handler = grove_gyro_interrupt_handler,
470 .pin_mask = gpio_hal_pin_to_mask(I2C_INT_PIN) << (I2C_INT_PORT << 3),
471};
472/*---------------------------------------------------------------------------*/
473static int
474value(int type)
475{
476 if(!enabled) {
477 PRINTF("Gyro: sensor not started\n");
478 return GROVE_GYRO_ERROR;
479 }
480
481 if((type != GROVE_GYRO_X) && (type != GROVE_GYRO_Y) &&
482 (type != GROVE_GYRO_Z) && (type != GROVE_GYRO_XYZ) &&
483 (type != GROVE_GYRO_TEMP) && (type != GROVE_GYRO_ADDR)) {
484 PRINTF("Gyro: invalid value requested 0x%02X\n", type);
485 return GROVE_GYRO_ERROR;
486 }
487
488 if((type != GROVE_GYRO_TEMP) && (type != GROVE_GYRO_ADDR) &&
489 (type & power_mgmt)) {
490 PRINTF("Gyro: axis not enabled (0x%02X vs 0x%02X)\n", power_mgmt, type);
491 return GROVE_GYRO_ERROR;
492 }
493
494 return grove_gyro_read(type);
495}
496/*---------------------------------------------------------------------------*/
497static int
498configure(int type, int value)
499{
500 if((type != GROVE_GYRO_ACTIVE) && (type != GROVE_GYRO_SAMPLE_RATE) &&
501 (type != GROVE_GYRO_SAMPLE_RATE_DIVIDER) && (type != GROVE_GYRO_POWER_ON) &&
502 (type != GROVE_GYRO_POWER_OFF) && (type != GROVE_GYRO_DATA_INTERRUPT) &&
503 (type != GROVE_GYRO_CALIBRATE_ZERO)) {
504 PRINTF("Gyro: option not supported\n");
505 return GROVE_GYRO_ERROR;
506 }
507
508 switch(type) {
509 case GROVE_GYRO_ACTIVE:
510 if(value) {
511 i2c_init(I2C_SDA_PORT, I2C_SDA_PIN, I2C_SCL_PORT, I2C_SCL_PIN,
512 I2C_SCL_FAST_BUS_SPEED);
513
514 /* Initialize the data structure values */
515 gyro_values.x = 0;
516 gyro_values.y = 0;
517 gyro_values.z = 0;
518 gyro_values.temp = 0;
519 gyro_values.x_offset = 0;
520 gyro_values.y_offset = 0;
521 gyro_values.z_offset = 0;
522
523 /* Make sure the sensor is on */
524 if(grove_gyro_power_mgmt(GROVE_GYRO_ALL, GROVE_GYRO_POWER_ON) !=
525 GROVE_GYRO_SUCCESS) {
526 PRINTF("Gyro: failed to power on the sensor\n");
527 return GROVE_GYRO_ERROR;
528 }
529
530 /* Reset and configure as default with internal oscillator, 8KHz @ 2000
531 * degrees/s, no divider (full scale)
532 */
533 if(grove_gyro_reset() == GROVE_GYRO_SUCCESS) {
534 if(grove_gyro_osc(GROVE_GYRO_DEFAULT_OSC) == GROVE_GYRO_SUCCESS) {
535 if(grove_gyro_dlpf(GROVE_GYRO_DLPF_FS_CGF_8KHZ_LP256HZ) ==
536 GROVE_GYRO_SUCCESS) {
537 PRINTF("Gyro: started and configured\n");
538 /* Disable interrupts as default */
539 if(grove_gyro_interrupt(GROVE_GYRO_INT_CFG_DISABLE) ==
540 GROVE_GYRO_SUCCESS) {
541 PRINTF("Gyro: interrupts disabled\n");
542 /* And finally put the device in SLEEP mode, set also X, Y and Z
543 * in stand-by mode, whenever an axis is not used it should stay
544 * in this state to save power
545 */
546 if(grove_gyro_power_mgmt(GROVE_GYRO_ALL, GROVE_GYRO_POWER_OFF) ==
547 GROVE_GYRO_SUCCESS) {
548 enabled = 1;
549 PRINTF("Gyro: axis and gyroscope in low-power mode now\n");
550
551 return GROVE_GYRO_SUCCESS;
552 }
553 }
554 }
555 }
556 }
557 return GROVE_GYRO_ERROR;
558
559 } else {
560 enabled = 0;
561 int_en = 0;
562 GPIO_DISABLE_INTERRUPT(GROVE_GYRO_INT_PORT_BASE, GROVE_GYRO_INT_PIN_MASK);
563 grove_gyro_int_callback = NULL;
564 if(grove_gyro_interrupt(GROVE_GYRO_INT_CFG_DISABLE) ==
565 GROVE_GYRO_SUCCESS) {
566 return grove_gyro_power_mgmt(GROVE_GYRO_ALL, GROVE_GYRO_POWER_OFF);
567 }
568 PRINTF("Gyro: hw interrupt disabled but failed to disable sensor\n");
569 return GROVE_GYRO_ERROR;
570 }
571
572 if(!enabled) {
573 PRINTF("Gyro: sensor not started\n");
574 return GROVE_GYRO_ERROR;
575 }
576
577 case GROVE_GYRO_DATA_INTERRUPT:
578
579 if(!value) {
580
581 /* Ensure the GPIO doesn't generate more interrupts, this may affect others
582 * I2C digital sensors using the bus and sharing this pin, so an user may
583 * comment the line below
584 */
585 int_en = 0;
586 GPIO_DISABLE_INTERRUPT(GROVE_GYRO_INT_PORT_BASE, GROVE_GYRO_INT_PIN_MASK);
587 return grove_gyro_interrupt(GROVE_GYRO_INT_CFG_DISABLE);
588 }
589
590 /* Enable interrupt and latch the pin until cleared */
591 if(grove_gyro_interrupt(GROVE_GYRO_INT_CFG_RAW_READY_EN +
592 GROVE_GYRO_INT_CFG_LATCH_EN) == GROVE_GYRO_ERROR) {
593 PRINTF("Gyro: failed to enable the interrupt\n");
594 return GROVE_GYRO_ERROR;
595 }
596
597 /* Default register configuration is active high, push-pull */
598 GPIO_SOFTWARE_CONTROL(GROVE_GYRO_INT_PORT_BASE, GROVE_GYRO_INT_PIN_MASK);
599 GPIO_SET_INPUT(GROVE_GYRO_INT_PORT_BASE, GROVE_GYRO_INT_PIN_MASK);
600 GPIO_DETECT_EDGE(GROVE_GYRO_INT_PORT_BASE, GROVE_GYRO_INT_PIN_MASK);
601 GPIO_TRIGGER_SINGLE_EDGE(GROVE_GYRO_INT_PORT_BASE, GROVE_GYRO_INT_PIN_MASK);
602 GPIO_DETECT_FALLING(GROVE_GYRO_INT_PORT_BASE, GROVE_GYRO_INT_PIN_MASK);
603 gpio_hal_register_handler(&gyro_handler);
604
605 /* Spin process until an interrupt is received */
606 process_start(&grove_gyro_int_process, NULL);
607
608 /* Enable interrupts */
609 int_en = 1;
610 GPIO_ENABLE_INTERRUPT(GROVE_GYRO_INT_PORT_BASE, GROVE_GYRO_INT_PIN_MASK);
611 ioc_set_over(I2C_INT_PORT, I2C_INT_PIN, IOC_OVERRIDE_PUE);
612 NVIC_EnableIRQ(I2C_INT_VECTOR);
613
614 PRINTF("Gyro: Data interrupt configured\n");
615 return GROVE_GYRO_SUCCESS;
616
617 case GROVE_GYRO_SAMPLE_RATE:
618 if((value < GROVE_GYRO_DLPF_FS_CGF_8KHZ_LP256HZ) ||
619 (value > GROVE_GYRO_DLPF_FS_CGF_1KHZ_LP5HZ)) {
620 PRINTF("Gyro: invalid sample rate/filter configuration\n");
621 return GROVE_GYRO_ERROR;
622 }
623 return grove_gyro_dlpf(value);
624
625 case GROVE_GYRO_SAMPLE_RATE_DIVIDER:
626 if((value < 0) || (value > 0xFF)) {
627 PRINTF("Gyro: invalid sampling rate div, it must be an 8-bit value\n");
628 return GROVE_GYRO_ERROR;
629 }
630 return grove_gyro_sampdiv((uint8_t)value);
631
632 case GROVE_GYRO_POWER_ON:
633 case GROVE_GYRO_POWER_OFF:
634 /* We accept mask values to enable more than one axis at the same time */
635 if((value < GROVE_GYRO_Z) || (value > GROVE_GYRO_ALL)) {
636 PRINTF("Gyro: invalid power management setting\n");
637 return GROVE_GYRO_ERROR;
638 }
639 return grove_gyro_power_mgmt(value, type);
640
641 case GROVE_GYRO_CALIBRATE_ZERO:
642 return grove_gyro_calibrate();
643
644 default:
645 return GROVE_GYRO_ERROR;
646 }
647
648 return GROVE_GYRO_ERROR;
649}
650/*---------------------------------------------------------------------------*/
651SENSORS_SENSOR(grove_gyro, GROVE_GYRO_STRING, value, configure, NULL);
652/*---------------------------------------------------------------------------*/
653/** @} */
Header file for the GPIO HAL.
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Definition clock.c:150
#define GPIO_DETECT_FALLING(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to trigger an interrupt on falling edge.
Definition gpio.h:193
#define GPIO_SOFTWARE_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be software controlled with PIN_MASK of port with PORT_BASE.
Definition gpio.h:258
#define GPIO_DISABLE_INTERRUPT(PORT_BASE, PIN_MASK)
Disable interrupt triggering for pins with PIN_MASK of port with PORT_BASE.
Definition gpio.h:209
#define GPIO_SET_INPUT(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to input.
Definition gpio.h:78
#define GPIO_DETECT_EDGE(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to detect edge.
Definition gpio.h:154
#define GPIO_TRIGGER_SINGLE_EDGE(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to trigger an interrupt on single edge (controlled by G...
Definition gpio.h:177
#define GPIO_ENABLE_INTERRUPT(PORT_BASE, PIN_MASK)
Enable interrupt triggering for pins with PIN_MASK of port with PORT_BASE.
Definition gpio.h:201
uint8_t i2c_burst_send(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to send multiple bytes to a slave.
Definition i2c.c:188
void i2c_init(uint8_t port_sda, uint8_t pin_sda, uint8_t port_scl, uint8_t pin_scl, uint32_t bus_speed)
Initialize the I2C peripheral and pins.
Definition i2c.c:49
void i2c_master_enable(void)
Enable master I2C module.
Definition i2c.c:91
uint8_t i2c_burst_receive(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to receive multiple bytes from a slave.
Definition i2c.c:218
uint8_t i2c_single_send(uint8_t slave_addr, uint8_t data)
Perform all operations to send a byte to a slave.
Definition i2c.c:159
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
Definition ioc.c:54
#define IOC_OVERRIDE_PUE
Pull Up Enable.
Definition ioc.h:223
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition watchdog.c:85
void gpio_hal_register_handler(gpio_hal_event_handler_t *handler)
Register a function to be called whenever a pin triggers an event.
Definition gpio-hal.c:55
uint32_t gpio_hal_pin_mask_t
GPIO pin mask representation.
Definition gpio-hal.h:142
#define gpio_hal_pin_to_mask(pin)
Convert a pin to a pin mask.
Definition gpio-hal.h:255
#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_BEGIN()
Define the beginning of a process.
Definition process.h:120
#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
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition process.h:178
void process_poll(struct process *p)
Request a process to be polled.
Definition process.c:375
Grove 3-axis gyroscope header file.
Header file with declarations for the I2C Control module.
Datatype for GPIO event handlers.
Definition gpio-hal.h:180