1 /*
2  * Copyright 2021 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 /**
9  * @file  fxls896x_motion_wakeup.c
10  *  @brief The fxls896x_motion_wakeup.c file implements the ISSDK FXLS896xAF I2C sensor driver
11  *         example demonstrating motion detection and Auto-Wake/Sleep features.
12  */
13 
14 //-----------------------------------------------------------------------
15 // SDK Includes
16 //-----------------------------------------------------------------------
17 #include "pin_mux.h"
18 #include "clock_config.h"
19 #include "board.h"
20 #include "fsl_debug_console.h"
21 
22 //-----------------------------------------------------------------------
23 // ISSDK Includes
24 //-----------------------------------------------------------------------
25 #include "issdk_hal.h"
26 #include "gpio_driver.h"
27 #include "fxls896x_drv.h"
28 #include "systick_utils.h"
29 
30 //-----------------------------------------------------------------------
31 // CMSIS Includes
32 //-----------------------------------------------------------------------
33 #include "Driver_I2C.h"
34 
35 //-----------------------------------------------------------------------
36 // Macros
37 //-----------------------------------------------------------------------
38 #define FXLS8964_DATA_SIZE      6
39 #define FXLS8964_STANDBY_MODE   0
40 #define FXLS8964_ACTIVE_MODE    1
41 //-----------------------------------------------------------------------
42 // Constants
43 //-----------------------------------------------------------------------
44 /*! @brief Register settings for configuring SDCD-OT for tap-detection and Auto-Wake/Sleep in interrupt mode. */
45 const registerwritelist_t cFxls896xAwsConfig[] = {
46     /* Set Full-scale range as 4G. */
47     {FXLS896x_SENS_CONFIG1, FXLS896x_SENS_CONFIG1_FSR_4G, FXLS896x_SENS_CONFIG1_FSR_MASK},
48     /* Set Wake ODR as 400Hz & Sleep Mode ODR as 6.25Hz. */
49     {FXLS896x_SENS_CONFIG3, FXLS896x_SENS_CONFIG3_WAKE_ODR_400HZ | FXLS896x_SENS_CONFIG3_SLEEP_ODR_6_25HZ, FXLS896x_SENS_CONFIG3_WAKE_ODR_MASK | FXLS896x_SENS_CONFIG3_SLEEP_ODR_MASK},
50     /* Enable SDCD OT for all 3 axes X, Y & Z and within-thresholds event latch disabled. */
51     {FXLS896x_SDCD_CONFIG1, FXLS896x_SDCD_CONFIG1_X_OT_EN_EN | FXLS896x_SDCD_CONFIG1_Y_OT_EN_EN | FXLS896x_SDCD_CONFIG1_Z_OT_EN_EN | FXLS896x_SDCD_CONFIG1_OT_ELE_DIS,
52     		FXLS896x_SDCD_CONFIG1_X_OT_EN_MASK | FXLS896x_SDCD_CONFIG1_Y_OT_EN_MASK | FXLS896x_SDCD_CONFIG1_Z_OT_EN_MASK | FXLS896x_SDCD_CONFIG1_OT_ELE_MASK},
53     /* Enabling SDCD and Relative Data (N) � Data (N-1) mode for transient detection */
54     {FXLS896x_SDCD_CONFIG2, FXLS896x_SDCD_CONFIG2_SDCD_EN_EN | FXLS896x_SDCD_CONFIG2_REF_UPDM_SDCD_REF, FXLS896x_SDCD_CONFIG2_SDCD_EN_MASK | FXLS896x_SDCD_CONFIG2_REF_UPDM_MASK},
55     /* Set the SDCD_OT debounce count to 0 */
56     {FXLS896x_SDCD_OT_DBCNT, 0, 0},
57     /* Set the SDCD lower and upper thresholds to +/-100mg*/
58     {FXLS896x_SDCD_LTHS_LSB, 0xCC, 0},
59     {FXLS896x_SDCD_LTHS_MSB, 0xFF, 0},
60     {FXLS896x_SDCD_UTHS_LSB, 0x34, 0},
61     {FXLS896x_SDCD_UTHS_MSB, 0x00, 0},
62     /* Enable SDCD outside of thresholds event Auto-WAKE/SLEEP transition source enable. */
63     {FXLS896x_SENS_CONFIG4, FXLS896x_SENS_CONFIG4_WK_SDCD_OT_EN | FXLS896x_SENS_CONFIG4_INT_POL_ACT_HIGH, FXLS896x_SENS_CONFIG4_WK_SDCD_OT_MASK | FXLS896x_SENS_CONFIG4_INT_POL_MASK},
64     /* Set the ASLP count to 5sec */
65     {FXLS896x_ASLP_COUNT_LSB, 0xD0, 0},
66     {FXLS896x_ASLP_COUNT_MSB, 0x07, 0},
67     /* Enable Interrupts for WAKE mode. */
68     {FXLS896x_INT_EN, FXLS896x_INT_EN_WAKE_OUT_EN_EN, FXLS896x_INT_EN_WAKE_OUT_EN_MASK},
69     {FXLS896x_INT_PIN_SEL, FXLS896x_INT_PIN_SEL_WK_OUT_INT2_DIS, FXLS896x_INT_PIN_SEL_WK_OUT_INT2_MASK},
70     __END_WRITE_DATA__};
71 
72 /*! @brief Read register list to read SysMode Register. */
73 const registerreadlist_t cFxls896xReadSysMode[] = {{.readFrom = FXLS896x_SYS_MODE, .numBytes = 1}, __END_READ_DATA__};
74 
75 /*! @brief Read register list to read INT_STATUS Register. */
76 const registerreadlist_t cFxls896xReadIntStatus[] = {{.readFrom = FXLS896x_INT_STATUS, .numBytes = 1}, __END_READ_DATA__};
77 
78 //-----------------------------------------------------------------------
79 // Global Variables
80 //-----------------------------------------------------------------------
81 volatile bool gFxls896xIntFlag = false;
82 
83     ARM_DRIVER_I2C *I2Cdrv = &I2C_S_DRIVER;
84     fxls896x_i2c_sensorhandle_t fxls896xDriver;
85     GENERIC_DRIVER_GPIO *pGpioDriver = &Driver_GPIO_KSDK;
86 //-----------------------------------------------------------------------
87 // Functions
88 //-----------------------------------------------------------------------
89 /*! -----------------------------------------------------------------------
90  *  @brief       This is the Sensor Data Ready ISR implementation.
91  *  @details     This function sets the flag which indicates if a new sample(s) is available for reading.
92  *  @param[in]   pUserData This is a void pointer to the instance of the user specific data structure for the ISR.
93  *  @return      void  There is no return value.
94  *  -----------------------------------------------------------------------*/
fxls896x_int_callback(void * pUserData)95 void fxls896x_int_callback(void *pUserData)
96 { /*! @brief Set flag to indicate Sensor has signalled data ready. */
97 	gFxls896xIntFlag = true;
98 }
99 
100 /*! -----------------------------------------------------------------------
101  *  @brief       This is the The main function implementation.
102  *  @details     This function invokes board initializes routines, then then brings up the sensor and
103  *               finally enters an endless loop to continuously read available samples.
104  *  @param[in]   void This is no input parameter.
105  *  @return      void  There is no return value.
106  *  -----------------------------------------------------------------------*/
main(void)107 int main(void)
108 {
109     int32_t status;
110     uint8_t whoami;
111     uint8_t intStatus, eventStatus = 0;
112     uint8_t sleeptowake = 0;
113 	uint8_t waketosleep = 0;
114     uint8_t firsttransition = 1;
115     uint8_t onetime_modetransition = 1;
116 
117     /*! Initialize the MCU hardware. */
118     BOARD_InitPins();
119     BOARD_BootClockRUN();
120     BOARD_SystickEnable();
121     BOARD_InitDebugConsole();
122 
123     PRINTF("\r\n ISSDK FXLS896xAF sensor driver example to detect motion event & AWS\r\n");
124 
125     /*! Initialize FXLS8964 pin used by FRDM board */
126     pGpioDriver->pin_init(&FXLS896x_INT1, GPIO_DIRECTION_IN, NULL, &fxls896x_int_callback, NULL);
127 
128     /*! Initialize RGB LED pin used by FRDM board */
129     pGpioDriver->pin_init(&GREEN_LED, GPIO_DIRECTION_OUT, NULL, NULL, NULL);
130 
131     /*! Initialize the I2C driver. */
132     status = I2Cdrv->Initialize(I2C_S_SIGNAL_EVENT);
133     if (ARM_DRIVER_OK != status)
134     {
135         PRINTF("\r\n I2C Initialization Failed\r\n");
136         return -1;
137     }
138 
139     /*! Set the I2C Power mode. */
140     status = I2Cdrv->PowerControl(ARM_POWER_FULL);
141     if (ARM_DRIVER_OK != status)
142     {
143         PRINTF("\r\n I2C Power Mode setting Failed\r\n");
144         return -1;
145     }
146 
147     /*! Set the I2C bus speed. */
148     status = I2Cdrv->Control(ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST);
149     if (ARM_DRIVER_OK != status)
150     {
151         PRINTF("\r\n I2C Control Mode setting Failed\r\n");
152         return -1;
153     }
154 
155     /*! Initialize FXLS896x sensor driver. */
156     status = FXLS896x_I2C_Initialize(&fxls896xDriver, &I2C_S_DRIVER, I2C_S_DEVICE_INDEX, FXLS896x_I2C_ADDR,
157                                      &whoami);
158     if (ARM_DRIVER_OK != status)
159     {
160         PRINTF("\r\n Sensor Initialization Failed\r\n");
161         return -1;
162     }
163     if ((FXLS8964_WHOAMI_VALUE == whoami) || (FXLS8967_WHOAMI_VALUE == whoami))
164     {
165     	PRINTF("\r\n Successfully Initialized Gemini with WHO_AM_I = 0x%X\r\n", whoami);
166     }
167     else if ((FXLS8974_WHOAMI_VALUE == whoami) || (FXLS8968_WHOAMI_VALUE == whoami))
168     {
169     	PRINTF("\r\n Successfully Initialized Timandra with WHO_AM_I = 0x%X\r\n", whoami);
170     }
171     else if (FXLS8962_WHOAMI_VALUE == whoami)
172     {
173     	PRINTF("\r\n Successfully Initialized Newstein with WHO_AM_I = 0x%X\r\n", whoami);
174     }
175     else
176     {
177     	PRINTF("\r\n Bad WHO_AM_I = 0x%X\r\n", whoami);
178         return -1;
179     }
180 
181     /*!  Set the task to be executed while waiting for I2C transactions to complete. */
182     FXLS896x_I2C_SetIdleTask(&fxls896xDriver, (registeridlefunction_t)SMC_SetPowerModeVlpr, SMC);
183 
184     /*! Configure the FXLS896x sensor. */
185     status = FXLS896x_I2C_Configure(&fxls896xDriver, cFxls896xAwsConfig);
186     if (SENSOR_ERROR_NONE != status)
187     {
188         PRINTF("\r\n FXLS8964 Sensor Configuration Failed, Err = %d\r\n", status);
189         return -1;
190     }
191     PRINTF("\r\n Successfully Applied FXLS8964 Sensor Configuration\r\n");
192 
193     for (;;) /* Forever loop */
194     {
195     	eventStatus = 0;
196         /*! Read new raw sensor data from the FXLS8964. */
197         status = FXLS896x_I2C_ReadData(&fxls896xDriver, cFxls896xReadSysMode, &eventStatus);
198         if (ARM_DRIVER_OK != status)
199         {
200             return status;
201         }
202 
203         if (eventStatus == FXLS896x_SYS_MODE_SYS_MODE_WAKE)
204         {
205             if (true == gFxls896xIntFlag)
206             {
207               if (sleeptowake == 1)
208               {
209                 /*! Wake Mode Detected. */
210                 PRINTF("\r\n Motion Detected....\r\n");
211                 PRINTF("\r\n Motion Wake Mode Detected....SYSMODE = %d\r\n", eventStatus);
212                 PRINTF("\r\n MCU woke-up on sensor motion event\r\n");
213                 PRINTF("\r\n Will enter sleep mode after expiration of ASLP counter = ~5sec\r\n\r\n");
214                 sleeptowake = 0;
215               }
216                 pGpioDriver->set_pin(&RED_LED);
217                 pGpioDriver->clr_pin(&GREEN_LED);
218                 waketosleep = 1;
219             }
220         }
221         else
222         {
223            if ((waketosleep == 1) || (firsttransition == 1))
224            {
225              if (1 == onetime_modetransition)
226              {
227                onetime_modetransition = 0;
228              }
229 
230              status = FXLS896x_I2C_ReadData(&fxls896xDriver, cFxls896xReadIntStatus, &intStatus);
231              if (ARM_DRIVER_OK != status)
232              {
233                return status;
234              }
235              PRINTF("\r\n ASLP counter expired....\r\n");
236              PRINTF("\r\n Going to Sleep Mode....SYSMODE = %d\r\n", eventStatus);
237              PRINTF("\r\n Putting MCU in low power sleep\r\n\r\n");
238              waketosleep = 0;
239              firsttransition = 0;
240            }
241            pGpioDriver->set_pin(&GREEN_LED);
242            pGpioDriver->clr_pin(&RED_LED);
243            sleeptowake = 1;
244            gFxls896xIntFlag = false;
245            SMC_SetPowerModeWait(SMC);
246           continue;
247         }
248     }
249 }
250