1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2011-07-13 onelife Initial creation for using EFM32 ADC module to
9 * interface the Freescale MMA7361L
10 * 2011-08-02 onelife Add digital interface support of using EFM32 IIC
11 * module for the Freescale MMA7455L
12 */
13
14 /***************************************************************************//**
15 * @addtogroup efm32
16 * @{
17 ******************************************************************************/
18
19 /* Includes ------------------------------------------------------------------*/
20 #include "board.h"
21
22 #if defined(EFM32_USING_ACCEL)
23 #if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
24 #include "drv_adc.h"
25 #elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
26 #include "drv_iic.h"
27 #include "hdl_interrupt.h"
28 #endif
29 #include "dev_accel.h"
30
31 /* Private typedef -----------------------------------------------------------*/
32 /* Private define ------------------------------------------------------------*/
33 /* Private macro -------------------------------------------------------------*/
34 #ifdef EFM32_ACCEL_DEBUG
35 #define accel_debug(format,args...) rt_kprintf(format, ##args)
36 #else
37 #define accel_debug(format,args...)
38 #endif
39
40 /* Private constants ---------------------------------------------------------*/
41 static rt_device_t accel;
42 #if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
43 static struct efm32_adc_control_t control = \
44 {ADC_MODE_SCAN, {3, ACCEL_USING_DMA}, {}};
45 static struct efm32_accel_result_t accelOffset = {0};
46 #elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
47 static const struct efm32_iic_control_t control = \
48 {IIC_STATE_MASTER, 0x0000};
49 #endif
50 static rt_bool_t accelInTime = true;
51 static rt_uint32_t accelConfig = 0;
52
53 /* Private variables ---------------------------------------------------------*/
54 /* Private function prototypes -----------------------------------------------*/
55 /* Private functions ---------------------------------------------------------*/
56 /***************************************************************************//**
57 * @brief
58 * Get accelerometer output
59 *
60 * @details
61 *
62 * @note
63 *
64 * @param[out] data
65 * Pointer to output buffer
66 *
67 * @param[in] lowResolution
68 * Resolution selection
69 *
70 * @return
71 * Error code
72 ******************************************************************************/
efm_accel_get_data(struct efm32_accel_result_t * data,rt_bool_t lowResolution)73 rt_err_t efm_accel_get_data(struct efm32_accel_result_t *data,
74 rt_bool_t lowResolution)
75 {
76 RT_ASSERT(accel != RT_NULL);
77
78 rt_err_t ret;
79
80 if (data == RT_NULL)
81 {
82 return -RT_ERROR;
83 }
84
85 ret = RT_EOK;
86 do
87 {
88 /* --------- ADC interface --------- */
89 #if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
90 struct efm32_adc_result_t result;
91
92 result.mode = control.mode;
93 result.buffer = (void *)data;
94 if ((ret = accel->control(accel, RT_DEVICE_CTRL_RESUME,
95 (void *)&result)) != RT_EOK)
96 {
97 break;
98 }
99 if ((ret = accel->control(accel, RT_DEVICE_CTRL_ADC_RESULT, \
100 (void *)&result)) != RT_EOK)
101 {
102 break;
103 }
104
105 data->x += accelOffset.x - 0x800;
106 data->y += accelOffset.y - 0x800;
107 data->z += accelOffset.z - 0x800;
108 if (lowResolution)
109 {
110 data->x >>= 4;
111 data->y >>= 4;
112 data->z >>= 4;
113 }
114
115 /* --------- IIC interface --------- */
116 #elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
117 if (lowResolution || \
118 ((accelConfig & ACCEL_MASK_RANGE) != MCTL_RANGE_8G))
119 {
120 rt_int8_t buf[3];
121
122 buf[0] = XOUT8;
123 if (accel->read(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, \
124 sizeof(buf)) == 0)
125 {
126 ret = -RT_ERROR;
127 break;
128 }
129 data->x = buf[0];
130 data->y = buf[1];
131 data->z = buf[2];
132 }
133 else
134 {
135 rt_uint8_t buf[6];
136 rt_uint16_t *temp = (rt_uint16_t *)&buf;
137
138 buf[0] = XOUTL;
139 if (accel->read(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, \
140 sizeof(buf)) == 0)
141 {
142 ret = -RT_ERROR;
143 break;
144 }
145 data->x = (*temp & 0x200) ? ((rt_uint32_t)*temp | ~0x3FF) : \
146 ((rt_uint32_t)*temp & 0x3FF);
147 data->y = (*++temp & 0x200) ? ((rt_uint32_t)*temp | ~0x3FF) : \
148 ((rt_uint32_t)*temp & 0x3FF);
149 data->z = (*++temp & 0x200) ? ((rt_uint32_t)*temp | ~0x3FF) : \
150 ((rt_uint32_t)*temp & 0x3FF);
151 }
152 #endif
153 return RT_EOK;
154 } while (0);
155
156 accel_debug("Accel err: Get data failed!\n");
157 return ret;
158 }
159
160 /***************************************************************************//**
161 * @brief
162 * Accelerometer timeout interrupt handler
163 *
164 * @details
165 *
166 * @note
167 *
168 * @param[in] parameter
169 * Parameter
170 ******************************************************************************/
efm_accel_timer(void * parameter)171 static void efm_accel_timer(void* parameter)
172 {
173 accelInTime = false;
174 }
175
176 #if (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
177 /***************************************************************************//**
178 * @brief
179 * Accelerometer level and pulse detection interrupts handler
180 *
181 * @details
182 *
183 * @note
184 *
185 * @param[in] device
186 * Pointer to device descriptor
187 ******************************************************************************/
efm_accel_isr(rt_device_t device)188 static void efm_accel_isr(rt_device_t device)
189 {
190 rt_uint8_t buf[2];
191
192 if ((accelConfig & ACCEL_MASK_MODE) != ACCEL_MODE_MEASUREMENT)
193 {
194 /* Read detection source */
195 buf[0] = DETSRC;
196 if (accel->read(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 1) != 1)
197 {
198 accel_debug("Accel: read error\n");
199 return;
200 }
201 accel_debug("Accel: DETSRC %x\n", buf[0]);
202
203 /* Reset the interrupt flags: Part 1 */
204 buf[0] = INTRST;
205 buf[1] = INTRST_INT_1 | INTRST_INT_2;
206 accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2);
207
208 /* Read status to waste some time */
209 buf[0] = STATUS;
210 if (accel->read(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 1) != 1)
211 {
212 accel_debug("Accel: read error\n");
213 return;
214 }
215 accel_debug("Accel: STATUS %x\n", buf[0]);
216
217 /* Reset the interrupt flags: Part 2 */
218 buf[0] = INTRST;
219 buf[1] = 0x00;
220 accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2);
221 }
222 }
223
224 /***************************************************************************//**
225 * @brief
226 * Accelerometer configuration function
227 *
228 * @details
229 *
230 * @note
231 *
232 * @param[in] config
233 * Configuration options
234 *
235 * @param[in] level_threshold
236 * Level detection threshold
237 *
238 * @param[in] pulse_threshold
239 * Pulse detection threshold
240 *
241 * @param[in] pulse_duration
242 * Time window for 1st pulse
243 *
244 * @param[in] pulse_latency
245 * Pulse latency Time
246 *
247 * @param[in] pulse_duration2
248 * Time window for 2nd pulse
249 *
250 * @return
251 * Error code
252 ******************************************************************************/
efm_accel_config(rt_uint32_t config,rt_uint8_t level_threshold,rt_uint8_t pulse_threshold,rt_uint8_t pulse_duration,rt_uint8_t pulse_latency,rt_uint8_t pulse_duration2)253 rt_err_t efm_accel_config(rt_uint32_t config,
254 rt_uint8_t level_threshold,
255 rt_uint8_t pulse_threshold,
256 rt_uint8_t pulse_duration,
257 rt_uint8_t pulse_latency,
258 rt_uint8_t pulse_duration2)
259 {
260 rt_err_t ret;
261 rt_uint8_t buf[2];
262 rt_uint8_t mode, mctl_reg, ctl1_reg, ctl2_reg;
263
264 ret = RT_EOK;
265 mctl_reg = 0;
266 ctl1_reg = 0;
267 ctl2_reg = 0;
268
269 /* Modify MCTL */
270 mode = config & ACCEL_MASK_MODE;
271 switch (mode)
272 {
273 case ACCEL_MODE_STANDBY:
274 mctl_reg |= MCTL_MODE_STANDBY;
275 break;
276 case ACCEL_MODE_MEASUREMENT:
277 mctl_reg |= MCTL_MODE_MEASUREMENT;
278 break;
279 case ACCEL_MODE_LEVEL:
280 mctl_reg |= MCTL_MODE_LEVEL;
281 break;
282 case ACCEL_MODE_PULSE:
283 mctl_reg |= MCTL_MODE_PULSE;
284 break;
285 default:
286 return -RT_ERROR;
287 }
288
289 switch (config & ACCEL_MASK_RANGE)
290 {
291 case ACCEL_RANGE_8G:
292 mctl_reg |= MCTL_RANGE_8G;
293 break;
294 case ACCEL_RANGE_4G:
295 mctl_reg |= MCTL_RANGE_4G;
296 break;
297 case ACCEL_RANGE_2G:
298 mctl_reg |= MCTL_RANGE_2G;
299 break;
300 default:
301 return -RT_ERROR;
302 }
303
304 if ((mode == ACCEL_MODE_LEVEL) || (mode == ACCEL_MODE_PULSE))
305 {
306 mctl_reg |= MCTL_PIN_INT1;
307 }
308
309 /* Modify CTL1 */
310 if (config & ACCEL_INTPIN_INVERSE)
311 {
312 ctl1_reg |= CTL1_INTPIN_INVERSE;
313 }
314
315 switch (config & ACCEL_MASK_INT)
316 {
317 case ACCEL_INT_LEVEL_PULSE:
318 ctl1_reg |= CTL1_INT_LEVEL_PULSE;
319 break;
320 case ACCEL_INT_PULSE_LEVEL:
321 ctl1_reg |= CTL1_INT_PULSE_LEVEL;
322 break;
323 case ACCEL_INT_SINGLE_DOUBLE:
324 ctl1_reg |= CTL1_INT_SINGLE_DOUBLE;
325 break;
326 default:
327 break;
328 }
329
330 switch (config & ACCEL_MASK_DISABLE)
331 {
332 case ACCEL_DISABLE_X:
333 ctl1_reg |= CTL1_X_DISABLE;
334 break;
335 case ACCEL_DISABLE_Y:
336 ctl1_reg |= CTL1_Y_DISABLE;
337 break;
338 case ACCEL_DISABLE_Z:
339 ctl1_reg |= CTL1_Z_DISABLE;
340 break;
341 default:
342 break;
343 }
344
345 if (config & ACCEL_THRESHOLD_INTEGER)
346 {
347 ctl1_reg |= CTL1_THRESHOLD_INTEGER;
348 }
349
350 if (config & ACCEL_BANDWIDTH_125HZ)
351 {
352 ctl1_reg |= CTL1_BANDWIDTH_125HZ;
353 }
354
355 /* Modify CTL2 */
356 if (config & ACCEL_LEVEL_AND)
357 {
358 ctl2_reg |= CTL2_LEVEL_AND;
359 }
360 if (config & ACCEL_PULSE_AND)
361 {
362 ctl2_reg |= CTL2_PULSE_AND;
363 }
364 if (config & ACCEL_DRIVE_STRONG)
365 {
366 ctl2_reg |= CTL2_DRIVE_STRONG;
367 }
368
369 do
370 {
371 /* Write registers */
372 buf[0] = MCTL;
373 buf[1] = mctl_reg;
374 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
375 {
376 ret = -RT_ERROR;
377 break;
378 }
379 accel_debug("Accel: MCTL %x\n", mctl_reg);
380
381 buf[0] = CTL1;
382 buf[1] = ctl1_reg;
383 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
384 {
385 ret = -RT_ERROR;
386 break;
387 }
388 accel_debug("Accel: CTL1 %x\n", ctl1_reg);
389
390 buf[0] = CTL2;
391 buf[1] = ctl2_reg;
392 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
393 {
394 ret = -RT_ERROR;
395 break;
396 }
397 accel_debug("Accel: CTL2 %x\n", ctl2_reg);
398 accelConfig = config;
399
400 if (mode == ACCEL_MODE_PULSE)
401 {
402 buf[0] = PDTH;
403 buf[1] = pulse_threshold;
404 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
405 {
406 ret = -RT_ERROR;
407 break;
408 }
409 accel_debug("Accel: PDTH %x\n", buf[1]);
410
411 buf[0] = PW;
412 buf[1] = pulse_duration;
413 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
414 {
415 ret = -RT_ERROR;
416 break;
417 }
418 accel_debug("Accel: PW %x\n", buf[1]);
419
420 buf[0] = LT;
421 buf[1] = pulse_latency;
422 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
423 {
424 ret = -RT_ERROR;
425 break;
426 }
427 accel_debug("Accel: LT %x\n", buf[1]);
428
429 buf[0] = TW;
430 buf[1] = pulse_duration2;
431 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
432 {
433 ret = -RT_ERROR;
434 break;
435 }
436 accel_debug("Accel: TW %x\n", buf[1]);
437 }
438
439 if ((mode == ACCEL_MODE_LEVEL) || (mode == ACCEL_MODE_PULSE))
440 {
441 efm32_irq_hook_init_t hook;
442
443 /* Reset the interrupt flags: Part 1 */
444 buf[0] = INTRST;
445 buf[1] = INTRST_INT_1 | INTRST_INT_2;
446 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
447 {
448 ret = -RT_ERROR;
449 break;
450 }
451
452 /* Set level detection threshold */
453 buf[0] = LDTH;
454 if (config & ACCEL_THRESHOLD_INTEGER)
455 {
456 buf[1] = level_threshold;
457 }
458 else
459 {
460 buf[1] = level_threshold & 0x7f;
461 }
462 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
463 {
464 ret = -RT_ERROR;
465 break;
466 }
467 accel_debug("Accel: LDTH %x\n", buf[1]);
468
469 /* Config interrupt */
470 hook.type = efm32_irq_type_gpio;
471 hook.unit = ACCEL_INT1_PIN;
472 hook.cbFunc = efm_accel_isr;
473 hook.userPtr = RT_NULL;
474 efm32_irq_hook_register(&hook);
475 hook.unit = ACCEL_INT2_PIN;
476 efm32_irq_hook_register(&hook);
477 /* Clear pending interrupt */
478 BITBAND_Peripheral(&(GPIO->IFC), ACCEL_INT1_PIN, 0x1UL);
479 BITBAND_Peripheral(&(GPIO->IFC), ACCEL_INT2_PIN, 0x1UL);
480 /* Set raising edge interrupt and clear/enable it */
481 GPIO_IntConfig(
482 ACCEL_INT1_PORT,
483 ACCEL_INT1_PIN,
484 true,
485 false,
486 true);
487 GPIO_IntConfig(
488 ACCEL_INT2_PORT,
489 ACCEL_INT2_PIN,
490 true,
491 false,
492 true);
493 if (((rt_uint8_t)ACCEL_INT1_PORT % 2) || \
494 ((rt_uint8_t)ACCEL_INT2_PORT % 2))
495 {
496 NVIC_ClearPendingIRQ(GPIO_ODD_IRQn);
497 NVIC_SetPriority(GPIO_ODD_IRQn, EFM32_IRQ_PRI_DEFAULT);
498 NVIC_EnableIRQ(GPIO_ODD_IRQn);
499 }
500 if (!((rt_uint8_t)ACCEL_INT1_PORT % 2) || \
501 !((rt_uint8_t)ACCEL_INT2_PORT % 2))
502 {
503 NVIC_ClearPendingIRQ(GPIO_EVEN_IRQn);
504 NVIC_SetPriority(GPIO_EVEN_IRQn, EFM32_IRQ_PRI_DEFAULT);
505 NVIC_EnableIRQ(GPIO_EVEN_IRQn);
506 }
507
508 /* Reset the interrupt flags: Part 2 */
509 buf[0] = INTRST;
510 buf[1] = 0x00;
511 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
512 {
513 ret = -RT_ERROR;
514 break;
515 }
516 }
517 } while (0);
518
519 return ret;
520 }
521
522 #endif
523
524 /***************************************************************************//**
525 * @brief
526 * Accelerometer auto-zero calibration function
527 *
528 * @details
529 *
530 * @note
531 *
532 * @param[in] mode
533 * 0, simple mode (assuming the device is placed on flat surface)
534 * 1, interaction method
535 *
536 * @param[in] period
537 * Time period to perform auto-zero calibration
538 *
539 * @return
540 * Error code
541 ******************************************************************************/
efm_accel_auto_zero(rt_uint8_t mode,rt_tick_t period)542 rt_err_t efm_accel_auto_zero(rt_uint8_t mode, rt_tick_t period)
543 {
544 RT_ASSERT(accel != RT_NULL);
545
546 rt_timer_t calTimer;
547 struct efm32_accel_result_t min = {0, 0, 0};
548 struct efm32_accel_result_t max = {0, 0, 0};
549 struct efm32_accel_result_t temp, sum;
550 rt_int32_t simpleOffset[] = ACCEL_CAL_1G_VALUE;
551 rt_uint8_t cmd[7] = {0};
552 rt_uint8_t i, j;
553
554 /* Reset offset */
555 #if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
556 accelOffset.x = 0;
557 accelOffset.y = 0;
558 accelOffset.z = 0;
559
560 #elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
561 cmd[0] = XOFFL;
562 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, cmd, sizeof(cmd)) == 0)
563 {
564 return -RT_ERROR;
565 }
566 #endif
567
568 if (mode == ACCEL_CAL_SIMPLE)
569 {
570 /* Simple mode */
571 for (j = 0; j < ACCEL_CAL_ROUND; j++)
572 {
573 sum.x = 0x0;
574 sum.y = 0x0;
575 sum.z = 0x0;
576
577 for (i = 0; i < ACCEL_CAL_SAMPLES; i++)
578 {
579 #if (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
580 /* Waiting for data ready */
581 while(!GPIO_PinInGet(ACCEL_INT1_PORT, ACCEL_INT1_PIN));
582 #endif
583 if (efm_accel_get_data(&temp, false) != RT_EOK)
584 {
585 return -RT_ERROR;
586 }
587 sum.x += temp.x;
588 sum.y += temp.y;
589 sum.z += temp.z;
590 }
591
592 #if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
593 temp.x = sum.x / ACCEL_CAL_SAMPLES;
594 temp.y = sum.y / ACCEL_CAL_SAMPLES;
595 temp.z = sum.z / ACCEL_CAL_SAMPLES - simpleOffset[ACCEL_G_SELECT];
596 if ((temp.x == 0) && (temp.y == 0) && \
597 (temp.z == 0))
598 {
599 accel_debug("Accel: Offset %+d %+d %+d\n",
600 accelOffset.x, accelOffset.y, accelOffset.z);
601 break;
602 }
603 accelOffset.x -= temp.x;
604 accelOffset.y -= temp.y;
605 accelOffset.z -= temp.z;
606
607 #elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
608 temp.x = sum.x / (ACCEL_CAL_SAMPLES >> 1);
609 temp.y = sum.y / (ACCEL_CAL_SAMPLES >> 1);
610 temp.z = sum.z / (ACCEL_CAL_SAMPLES >> 1) \
611 - (simpleOffset[ACCEL_G_SELECT] << 1);
612 if ((temp.x == 0) && (temp.y == 0) && \
613 (temp.z == 0))
614 {
615 break;
616 }
617
618 /* Set offset drift registers */
619 max.x -= temp.x;
620 max.y -= temp.y;
621 max.z -= temp.z;
622 *(rt_int16_t *)&cmd[1] = (rt_int16_t)max.x;
623 *(rt_int16_t *)&cmd[3] = (rt_int16_t)max.y;
624 *(rt_int16_t *)&cmd[5] = (rt_int16_t)max.z;
625 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, cmd, sizeof(cmd)) == 0)
626 {
627 return -RT_ERROR;
628 }
629 accel_debug("Accel: Offset %+d %+d %+d\n", *(rt_int16_t *)&cmd[1], \
630 *(rt_int16_t *)&cmd[3], *(rt_int16_t *)&cmd[5]);
631 #endif
632 rt_thread_delay(1);
633 }
634 }
635 else
636 {
637 /* Interact mode */
638 if ((calTimer = rt_timer_create(
639 "cal_tmr",
640 efm_accel_timer,
641 RT_NULL,
642 period,
643 RT_TIMER_FLAG_ONE_SHOT)) == RT_NULL)
644 {
645 accel_debug("Accel err: Create timer failed!\n");
646 return -RT_ERROR;
647 }
648
649 accelInTime = true;
650 rt_timer_start(calTimer);
651 do
652 {
653 sum.x = 0x0;
654 sum.y = 0x0;
655 sum.z = 0x0;
656
657 for (i = 0; i < ACCEL_CAL_SAMPLES; i++)
658 {
659 #if (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
660 /* Waiting for data ready */
661 while(!GPIO_PinInGet(ACCEL_INT1_PORT, ACCEL_INT1_PIN));
662 #endif
663 if (efm_accel_get_data(&temp, false) != RT_EOK)
664 {
665 return -RT_ERROR;
666 }
667 sum.x += temp.x;
668 sum.y += temp.y;
669 sum.z += temp.z;
670 }
671 sum.x /= ACCEL_CAL_SAMPLES;
672 sum.y /= ACCEL_CAL_SAMPLES;
673 sum.z /= ACCEL_CAL_SAMPLES;
674 if (sum.x < min.x)
675 {
676 min.x = sum.x;
677 }
678 if (sum.y < min.y)
679 {
680 min.y = sum.y;
681 }
682 if (sum.z < min.z)
683 {
684 min.z = sum.z;
685 }
686 if (sum.x > max.x)
687 {
688 max.x = sum.x;
689 }
690 if (sum.y > max.y)
691 {
692 max.y = sum.y;
693 }
694 if (sum.z > max.z)
695 {
696 max.z = sum.z;
697 }
698 rt_thread_delay(1);
699 } while (accelInTime);
700
701 accel_debug("Accel: Min %+d %+d %+d, max %+d %+d %+d\n",
702 min.x, min.y, min.z, max.x, max.y, max.z);
703
704 #if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
705 accelOffset.x = -((min.x + max.x) >> 1);
706 accelOffset.y = -((min.y + max.y) >> 1);
707 accelOffset.z = -((min.z + max.z) >> 1);
708
709 accel_debug("Accel: Offset %+d %+d %+d\n",
710 accelOffset.x, accelOffset.y, accelOffset.z);
711
712 #elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
713 /* Set offset drift registers */
714 *(rt_int16_t *)&cmd[1] = (rt_int16_t)-(min.x + max.x);
715 *(rt_int16_t *)&cmd[3] = (rt_int16_t)-(min.y + max.y);
716 *(rt_int16_t *)&cmd[5] = (rt_int16_t)-(min.z + max.z);
717 if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, cmd, sizeof(cmd)) == 0)
718 {
719 return -RT_ERROR;
720 }
721
722 accel_debug("Accel: Offset %+d %+d %+d\n",
723 *(rt_int16_t *)&cmd[1], *(rt_int16_t *)&cmd[3], *(rt_int16_t *)&cmd[5]);
724 #endif
725
726 rt_timer_delete(calTimer);
727 }
728
729 return RT_EOK;
730 }
731
732 /***************************************************************************//**
733 * @brief
734 * Initialize the accelerometer
735 *
736 * @details
737 *
738 * @note
739 *
740 * @return
741 * Error code
742 ******************************************************************************/
efm_accel_init(void)743 rt_err_t efm_accel_init(void)
744 {
745 rt_err_t ret;
746
747 ret = RT_EOK;
748 do
749 {
750 /* Find ADC device */
751 accel = rt_device_find(ACCEL_USING_DEVICE_NAME);
752 if (accel == RT_NULL)
753 {
754 accel_debug("Accel err: Can't find device: %s!\n", ACCEL_USING_DEVICE_NAME);
755 ret = -RT_ERROR;
756 break;
757 }
758 accel_debug("Accel: Find device %s\n", ACCEL_USING_DEVICE_NAME);
759
760 /* --------- ADC interface --------- */
761 #if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
762 ADC_InitScan_TypeDef scanInit = ADC_INITSCAN_DEFAULT;
763
764 #if defined(EFM32_GXXX_DK)
765 /* Enable accelerometer */
766 DVK_enablePeripheral(DVK_ACCEL);
767 /* Select g-range */
768 #if (ACCEL_G_SELECT == 0)
769 DVK_disablePeripheral(DVK_ACCEL_GSEL);
770 #elif (ACCEL_G_SELECT == 1)
771 DVK_enablePeripheral(DVK_ACCEL_GSEL);
772 #else
773 #error "Wrong value for ACCEL_G_SELECT"
774 #endif
775 #endif
776 /* Init ADC for scan mode */
777 scanInit.reference = adcRefVDD;
778 scanInit.input = ACCEL_X_ADC_CH | ACCEL_Y_ADC_CH | ACCEL_Z_ADC_CH;
779
780 control.scan.init = &scanInit;
781 if ((ret = accel->control(accel, RT_DEVICE_CTRL_ADC_MODE, \
782 (void *)&control)) != RT_EOK)
783 {
784 break;
785 }
786
787 /* --------- IIC interface --------- */
788 #elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
789 rt_uint8_t cmd[2];
790
791 /* Initialize */
792 if ((ret = accel->control(accel, RT_DEVICE_CTRL_IIC_SETTING, \
793 (void *)&control)) != RT_EOK)
794 {
795 break;
796 }
797
798 if (efm_accel_config(
799 ACCEL_MODE_MEASUREMENT | ACCEL_RANGE_2G,
800 EFM32_NO_DATA,
801 EFM32_NO_DATA,
802 EFM32_NO_DATA,
803 EFM32_NO_DATA,
804 EFM32_NO_DATA) != RT_EOK)
805 {
806 break;
807 }
808
809 /* Config interrupt pin1 */
810 GPIO_PinModeSet(ACCEL_INT1_PORT, ACCEL_INT1_PIN, gpioModeInput, 0);
811 /* Config interrupt pin2 */
812 GPIO_PinModeSet(ACCEL_INT2_PORT, ACCEL_INT2_PIN, gpioModeInput, 0);
813 #endif
814
815 accel_debug("Accel: Init OK\n");
816 return RT_EOK;
817 } while (0);
818
819 accel_debug("Accel err: Init failed!\n");
820 return -RT_ERROR;
821 }
822
823 /*******************************************************************************
824 * Export to FINSH
825 ******************************************************************************/
826 #ifdef RT_USING_FINSH
827 #include <finsh.h>
828
accel_cal(rt_uint8_t mode,rt_uint32_t second)829 void accel_cal(rt_uint8_t mode, rt_uint32_t second)
830 {
831 if (efm_accel_auto_zero(mode, RT_TICK_PER_SECOND * second) != RT_EOK)
832 {
833 rt_kprintf("Error occurred.");
834 return;
835 }
836
837 rt_kprintf("Calibration done.\n");
838 }
839 FINSH_FUNCTION_EXPORT(accel_cal, auto-zero calibration.)
840
list_accel(void)841 void list_accel(void)
842 {
843 struct efm32_accel_result_t data;
844
845 efm_accel_get_data(&data, false);
846 rt_kprintf("X: %d, Y: %d, Z: %d\n", data.x, data.y, data.z);
847 }
848 FINSH_FUNCTION_EXPORT(list_accel, list accelerometer info.)
849
test_accel(rt_uint8_t mode)850 void test_accel(rt_uint8_t mode)
851 {
852 if (mode == 0)
853 {
854 if (efm_accel_config(
855 ACCEL_MODE_LEVEL | ACCEL_RANGE_8G | ACCEL_INT_LEVEL_PULSE | \
856 ACCEL_SOURCE_LEVEL_X | ACCEL_SOURCE_LEVEL_Y,
857 0x1f,
858 EFM32_NO_DATA,
859 EFM32_NO_DATA,
860 EFM32_NO_DATA,
861 EFM32_NO_DATA) != RT_EOK)
862 {
863 rt_kprintf("efm_accel_config(): error\n");
864 return;
865 }
866 }
867 else
868 {
869 if (efm_accel_config(
870 ACCEL_MODE_PULSE | ACCEL_RANGE_8G | ACCEL_INT_SINGLE_DOUBLE | \
871 ACCEL_SOURCE_PULSE_X | ACCEL_SOURCE_PULSE_Y,
872 0x1f,
873 0x1f,
874 200,
875 255,
876 255) != RT_EOK)
877 {
878 rt_kprintf("efm_accel_config(): error\n");
879 return;
880 }
881 }
882 }
883 FINSH_FUNCTION_EXPORT(test_accel, list accelerometer info.)
884 #endif
885
886 #endif
887 /***************************************************************************//**
888 * @}
889 ******************************************************************************/
890