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