1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 /**
10  * @file mma8491q_example.c
11  * @brief The mma8491q_example.c file implements the ISSDK MMA8491Q sensor driver
12  *        example demonstration with Timers.
13  */
14 
15 //-----------------------------------------------------------------------
16 // SDK Includes
17 //-----------------------------------------------------------------------
18 #include "pin_mux.h"
19 #include "clock_config.h"
20 #include "board.h"
21 #include "fsl_lptmr.h"
22 #include "fsl_debug_console.h"
23 
24 //-----------------------------------------------------------------------
25 // CMSIS Includes
26 //-----------------------------------------------------------------------
27 #include "Driver_I2C.h"
28 
29 //-----------------------------------------------------------------------
30 // ISSDK Includes
31 //-----------------------------------------------------------------------
32 #include "issdk_hal.h"
33 #include "gpio_driver.h"
34 #include "mma8491q_drv.h"
35 
36 //-----------------------------------------------------------------------
37 // Macros
38 //-----------------------------------------------------------------------
39 /* Timer timeout Callback. */
40 #define mma8491q_en_callback LPTMR0_IRQHandler
41 /* Desired ODR rate in milli seconds (since the example uses LPTMR, this should be >= 10ms for reliable timing). */
42 #define MMA8491Q_T_ODR_ms 100U
43 /* The LPTMR Timeout Correction in milliseconds. */
44 #define LPTMR_T_CORRECTION_ms 2
45 
46 //-----------------------------------------------------------------------
47 // Constants
48 //-----------------------------------------------------------------------
49 /*! @brief Address of Status Register. */
50 const registerreadlist_t cMma8491qStatus[] = {{.readFrom = MMA8491Q_STATUS, .numBytes = 1}, __END_READ_DATA__};
51 
52 /*! @brief Address and size of Raw Acceleration Data. */
53 const registerreadlist_t cMma8491qOutput[] = {{.readFrom = MMA8491Q_OUT_X_MSB, .numBytes = MMA8491Q_DATA_SIZE},
54                                               __END_READ_DATA__};
55 
56 //-----------------------------------------------------------------------
57 // Global Variables
58 //-----------------------------------------------------------------------
59 volatile bool bMma849qDataReady = false;
60 gpioConfigKSDK_t gGpioConfigInPins = /* SDK GPIO Config for Tilt Pins. */
61     {
62         .pinConfig = {kGPIO_DigitalInput, 0},
63         .interruptMode = kPORT_InterruptOrDMADisabled,
64         .portPinConfig = {0},
65         .portPinConfig.mux = kPORT_MuxAsGpio,
66 };
67 GENERIC_DRIVER_GPIO *pGpioDriver = &Driver_GPIO_KSDK;
68 
69 //-----------------------------------------------------------------------
70 // Functions
71 //-----------------------------------------------------------------------
72 /* @brief  Block for adding EN delay. */
mma8491q_en_delay()73 void mma8491q_en_delay()
74 {
75     uint32_t delay, count, systemCoreClock;
76 
77     systemCoreClock = CLOCK_GetCoreSysClkFreq();
78     delay = (int)(0.16*MSEC_TO_COUNT(MMA8491Q_T_ON_TYPICAL, systemCoreClock));
79     for(count=0;count<delay;count++)
80     {
81         __NOP();
82     }
83 }
84 
85 /* LPTMR based EN control Timer Callback function. */
mma8491q_en_callback(void)86 void mma8491q_en_callback(void)
87 {
88     LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
89     bMma849qDataReady = true;
90 }
91 
92 /* Function for MMA8491Q specific initialization tasks. */
mma8491q_timer_fwk_init(uint32_t samplingInterval)93 void mma8491q_timer_fwk_init(uint32_t samplingInterval)
94 {
95     lptmr_config_t lptmrConfig;
96     /* Initialize ODR Timer. */
97     LPTMR_GetDefaultConfig(&lptmrConfig);
98     LPTMR_Init(LPTMR0, &lptmrConfig);
99     LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
100     EnableIRQ(LPTMR0_IRQn);
101 
102     /* Put the Sensor into Active Mode to enable I2C communication. */
103     LPTMR_SetTimerPeriod(LPTMR0, MSEC_TO_COUNT((samplingInterval-LPTMR_T_CORRECTION_ms), CLOCK_GetFreq(kCLOCK_LpoClk)));
104 }
105 
106 /*!
107  * @brief Main function
108  */
main(void)109 int main(void)
110 {
111     int32_t status;
112     uint8_t dataReady, data[MMA8491Q_DATA_SIZE];
113 
114     mma8491q_i2c_sensorhandle_t mma8491qDriver;
115     mma8491q_acceldata_t rawData = {.timestamp = 0};
116 
117     ARM_DRIVER_I2C *pI2cDriver = &I2C_S_DRIVER;
118 
119     /*! Initialize the MCU hardware. */
120     BOARD_InitPins();
121     BOARD_BootClockRUN();
122     BOARD_InitDebugConsole();
123 
124     PRINTF("\r\n ISSDK MMA8491Q sensor driver example demonstration with poll mode\r\n");
125 
126     /* Initialize Tilt Pin IDs. */
127     pGpioDriver->pin_init(&MMA8491_EN, GPIO_DIRECTION_OUT, NULL, NULL, NULL);
128     pGpioDriver->pin_init(&MMA8491_XOUT, GPIO_DIRECTION_IN, &gGpioConfigInPins, NULL, NULL);
129     pGpioDriver->pin_init(&MMA8491_YOUT, GPIO_DIRECTION_IN, &gGpioConfigInPins, NULL, NULL);
130     pGpioDriver->pin_init(&MMA8491_ZOUT, GPIO_DIRECTION_IN, &gGpioConfigInPins, NULL, NULL);
131 
132     /*! Initialize GREEN LED pin used by FRDM board */
133     pGpioDriver->pin_init(&GREEN_LED, GPIO_DIRECTION_OUT, NULL, NULL, NULL);
134 
135     /*! Initialize the I2C driver. */
136     status = pI2cDriver->Initialize(I2C_S_SIGNAL_EVENT);
137     if (ARM_DRIVER_OK != status)
138     {
139         PRINTF("\r\n I2C Initialization Failed\r\n");
140         return -1;
141     }
142 
143     /*! Set the I2C Power mode. */
144     status = pI2cDriver->PowerControl(ARM_POWER_FULL);
145     if (ARM_DRIVER_OK != status)
146     {
147         PRINTF("\r\n I2C Power Mode setting Failed\r\n");
148         return -1;
149     }
150 
151     /*! Set the I2C bus speed. */
152     status = pI2cDriver->Control(ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST);
153     if (ARM_DRIVER_OK != status)
154     {
155         PRINTF("\r\n I2C Control Mode setting Failed\r\n");
156         return -1;
157     }
158 
159     /* Set EN = 1 to enable I2C communication. */
160     pGpioDriver->set_pin(&MMA8491_EN);
161     mma8491q_en_delay();
162 
163     /* Initialize the Sensor Driver. */
164     status = MMA8491Q_I2C_Initialize(&mma8491qDriver, &I2C_S_DRIVER, I2C_S_DEVICE_INDEX, MMA8491_I2C_ADDR);
165     if (SENSOR_ERROR_NONE != status)
166     {
167         PRINTF("\r\n Sensor Initialization Failed\r\n");
168         return -1;
169     }
170     PRINTF("\r\n Successfully Initiliazed Sensor\r\n");
171 
172     /*!  Set the task to be executed while waiting for I2C transactions to complete. */
173     MMA8491Q_I2C_SetIdleTask(&mma8491qDriver, (registeridlefunction_t)SMC_SetPowerModeVlpr, SMC);
174 
175     /*! Initialize MMA8491_ODR Timer framework. */
176     mma8491q_timer_fwk_init(MMA8491Q_T_ODR_ms);
177     for (;;) /* Forever loop */
178     {
179         /*! Process packets on Data ready Timer Expiry */
180         if (false == bMma849qDataReady)
181         {
182             SMC_SetPowerModeWait(SMC); /* Power save, wait if nothing to do. */
183             continue;
184         }
185         else
186         {
187             pGpioDriver->toggle_pin(&GREEN_LED);
188             bMma849qDataReady = false;
189         }
190 
191         /* Set EN = 1 to put the Sensor into Active Mode. */
192         pGpioDriver->set_pin(&MMA8491_EN);
193         mma8491q_en_delay();
194         do
195         { /*! Process packets only when data ready is indicated by the MMA8491Q. */
196             MMA8491Q_I2C_ReadData(&mma8491qDriver, cMma8491qStatus, &dataReady);
197         } while (0 == (dataReady & MMA8491Q_STATUS_ZYXDR_MASK));
198 
199         /*! Read the raw sensor data from the MMA8491Q. */
200         status = MMA8491Q_I2C_ReadData(&mma8491qDriver, cMma8491qOutput, data);
201         if (ARM_DRIVER_OK != status)
202         { /* Loop, if sample read failed. */
203             continue;
204         }
205         /* Set EN = 0 to put the Sensor into Shutdown Mode. */
206         pGpioDriver->clr_pin(&MMA8491_EN);
207 
208         /* Read Tilt Output */
209         rawData.tilt[0] = pGpioDriver->read_pin(&MMA8491_XOUT);
210         rawData.tilt[1] = pGpioDriver->read_pin(&MMA8491_YOUT);
211         rawData.tilt[2] = pGpioDriver->read_pin(&MMA8491_ZOUT);
212 
213         /*! Process the sample and convert the raw sensor data. */
214         rawData.accel[0] = ((int16_t)data[0] << 8) | (data[1]);
215         rawData.accel[0] /= 4;
216         rawData.accel[1] = ((int16_t)data[2] << 8) | (data[3]);
217         rawData.accel[1] /= 4;
218         rawData.accel[2] = ((int16_t)data[4] << 8) | (data[5]);
219         rawData.accel[2] /= 4;
220 
221         PRINTF("\r\n Tilt :  X = %d  Y = %d  Z = %d ", rawData.tilt[0], rawData.tilt[1], rawData.tilt[2]);
222         PRINTF("|| Accel : X = %5d  Y = %5d  Z = %5d \r\n", rawData.accel[0], rawData.accel[1], rawData.accel[2]);
223         ASK_USER_TO_RESUME(100); /* Ask for user input after processing 100 samples. */
224     }
225 }
226