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