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 mma9553_demo.c
11  *  @brief The mma9553_demo.c file implements the ISSDK MMA9553L sensor driver
12  *          example demonstration as a Accelerometer in I2C Mode.
13  */
14 
15 /*  SDK Includes */
16 #include "board.h"
17 #include "pin_mux.h"
18 #include "fsl_lptmr.h"
19 #include "clock_config.h"
20 
21 /* CMSIS Includes */
22 #include "Driver_I2C.h"
23 
24 /* ISSDK Includes */
25 #include "issdk_hal.h"
26 #include "gpio_driver.h"
27 #include "mma9553_drv.h"
28 #include "host_io_uart.h"
29 #include "systick_utils.h"
30 #include "auto_detection_service.h"
31 
32 /*******************************************************************************
33  * Macros
34  ******************************************************************************/
35 #define SAMPLING_RATE_ms (100)                /* Timeout for the ODR Timer. */
36 #define MMA9553_ACCEL_DATA_SIZE (6)           /* 2 byte X,Y,Z Axis Data each. */
37 #define mma9553_en_callback LPTMR0_IRQHandler /* Timer timeout Callback. */
38 
39 #define MMA9553_STREAM_DATA_SIZE (10)
40 
41 /*! @brief Unique Name for this application which should match the target GUI pkg name. */
42 #define APPLICATION_NAME "MMA9553 Pedometer Demo"
43 /*! @brief Version to distinguish between instances the same application based on target Shield and updates. */
44 #define APPLICATION_VERSION "2.5"
45 
46 /*******************************************************************************
47  * Constants
48  ******************************************************************************/
49 /*! Prepare the register write list to configure MMA9553L in 30Hz Mode. */
50 const registercommandlist_t cMma9553Config30Hz[] = {
51     {SetFSRange_2g, 0, sizeof(SetFSRange_2g)},                     /* Set FS Range 2G */
52     {SetSampleRate_30Hz, 0, sizeof(SetSampleRate_30Hz)},           /* Set Sensor Sampling Rate 30Hz */
53     {SetAFEPriority_for30Hz, 0, sizeof(SetAFEPriority_for30Hz)},   /* Set AFE Priority for 30Hz Sampling Rate */
54     {SetMBoxPriority_for30Hz, 0, sizeof(SetMBoxPriority_for30Hz)}, /* Set MBox Priority for 30Hz Sampling Rate */
55     __END_WRITE_CMD__};
56 
57 /*! Prepare the register read list to read the raw Accel data from MMA9553. */
58 const registerreadlist_t cMma9553ReadRawOutput[] = {
59     {.readFrom = MMA9553_XYZ_DATA_OFFSET, .numBytes = MMA9553_ACCEL_DATA_SIZE}, __END_READ_DATA__};
60 
61 /*******************************************************************************
62  * Globals
63  ******************************************************************************/
64 char boardString[ADS_MAX_STRING_LENGTH] = {0}, shieldString[ADS_MAX_STRING_LENGTH] = {0},
65      embAppName[ADS_MAX_STRING_LENGTH] = {0};
66 volatile bool bStreamingEnabled = false, bMma9553DataReady = false, bMma9553Ready = false;
67 uint8_t gStreamID; /* The auto assigned Stream ID. */
68 int32_t gSystick;
69 GENERIC_DRIVER_GPIO *pGpioDriver = &Driver_GPIO_KSDK;
70 
71 /*******************************************************************************
72  * Functions
73  ******************************************************************************/
74 /* LPTMR based ODR Callback function. */
mma9553_en_callback(void)75 void mma9553_en_callback(void)
76 {
77     LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
78     bMma9553DataReady = true;
79 }
80 
81 /* Handler for Device Info and Streaming Control Commands. */
process_host_command(uint8_t tag,uint8_t * hostCommand,uint8_t * hostResponse,size_t * hostMsgSize,size_t respBufferSize)82 bool process_host_command(
83     uint8_t tag, uint8_t *hostCommand, uint8_t *hostResponse, size_t *hostMsgSize, size_t respBufferSize)
84 {
85     bool success = false;
86 
87     /* If it is Host requesting Device Info, send Board Name and Shield Name. */
88     if (tag == HOST_PRO_INT_DEV_TAG)
89     { /* Byte 1     : Payload - Length of APPLICATION_NAME (b)
90        * Bytes=b    : Payload Application Name
91        * Byte b+1   : Payload - Length of BOARD_NAME (s)
92        * Bytes=s    : Payload Board Name
93        * Byte b+s+2 : Payload - Length of SHIELD_NAME (v)
94        * Bytes=v    : Payload Shield Name */
95 
96         size_t appNameLen = strlen(embAppName);
97         size_t boardNameLen = strlen(boardString);
98         size_t shieldNameLen = strlen(shieldString);
99 
100         if (respBufferSize >= boardNameLen + shieldNameLen + appNameLen + 3)
101         { /* We have sufficient buffer. */
102             *hostMsgSize = 0;
103         }
104         else
105         {
106             return false;
107         }
108 
109         hostResponse[*hostMsgSize] = appNameLen;
110         *hostMsgSize += 1;
111 
112         memcpy(hostResponse + *hostMsgSize, embAppName, appNameLen);
113         *hostMsgSize += appNameLen;
114 
115         hostResponse[*hostMsgSize] = boardNameLen;
116         *hostMsgSize += 1;
117 
118         memcpy(hostResponse + *hostMsgSize, boardString, boardNameLen);
119         *hostMsgSize += boardNameLen;
120 
121         hostResponse[*hostMsgSize] = shieldNameLen;
122         *hostMsgSize += 1;
123 
124         memcpy(hostResponse + *hostMsgSize, shieldString, shieldNameLen);
125         *hostMsgSize += shieldNameLen;
126 
127         return true;
128     }
129 
130     /* If it is Host sending Streaming Commands, take necessary actions. */
131     if ((tag == (HOST_PRO_INT_CMD_TAG | HOST_PRO_CMD_W_CFG_TAG)) &&
132         (*hostMsgSize == HOST_MSG_CMD_ACT_OFFSET - HOST_MSG_LEN_LSB_OFFSET))
133     {                           /* Byte 1 : Payload - Operation Code (Start/Stop Operation Code)
134                                  * Byte 2 : Payload - Stream ID (Target Stream for carrying out operation) */
135         switch (hostCommand[0]) /* Execute desired operation (Start/Stop) on the requested Stream. */
136         {
137             case HOST_CMD_START:
138                 if (hostCommand[1] == gStreamID && bMma9553Ready && bStreamingEnabled == false)
139                 {
140                     BOARD_SystickStart(&gSystick);
141                     bStreamingEnabled = true;
142                     success = true;
143                 }
144                 break;
145             case HOST_CMD_STOP:
146                 if (hostCommand[1] == gStreamID && bMma9553Ready && bStreamingEnabled == true)
147                 {
148                     pGpioDriver->clr_pin(&GREEN_LED);
149                     bStreamingEnabled = false;
150                     success = true;
151                 }
152                 break;
153             default:
154                 break;
155         }
156         *hostMsgSize = 0; /* Zero payload in response. */
157     }
158 
159     return success;
160 }
161 
162 /*!
163  * @brief Main function
164  */
main(void)165 int main(void)
166 {
167     int32_t status;
168     uint8_t streamingPacket[STREAMING_HEADER_LEN + MMA9553_STREAM_DATA_SIZE];
169 
170     lptmr_config_t lptmrConfig;
171     mma9553_i2c_sensorhandle_t mma9553Driver;
172     mma9553_acceldata_t rawData = {.timestamp = 0};
173 
174     ARM_DRIVER_I2C *pI2Cdriver = &I2C_S_DRIVER;
175     ARM_DRIVER_USART *pUartDriver = &HOST_S_DRIVER;
176 
177     /*! Initialize the MCU hardware */
178     BOARD_BootClockRUN();
179     BOARD_SystickEnable();
180 
181     /* Create the Short Application Name String for ADS. */
182     sprintf(embAppName, "%s:%s", APPLICATION_NAME, APPLICATION_VERSION);
183 
184     /* Run ADS. */
185     BOARD_RunADS(embAppName, boardString, shieldString, ADS_MAX_STRING_LENGTH);
186 
187     /* Create the Full Application Name String for Device Info Response. */
188     sprintf(embAppName, "%s:%s:%s", SHIELD_NAME, APPLICATION_NAME, APPLICATION_VERSION);
189 
190     /*! Initialize RGB LED pin used by FRDM board */
191     pGpioDriver->pin_init(&GREEN_LED, GPIO_DIRECTION_OUT, NULL, NULL, NULL);
192 
193     /* Initialize ODR Timer. */
194     LPTMR_GetDefaultConfig(&lptmrConfig);
195     LPTMR_Init(LPTMR0, &lptmrConfig);
196     LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
197     LPTMR_SetTimerPeriod(LPTMR0, MSEC_TO_COUNT(SAMPLING_RATE_ms, CLOCK_GetFreq(kCLOCK_LpoClk)));
198     EnableIRQ(LPTMR0_IRQn);
199 
200     /*! Initialize the I2C driver. */
201     status = pI2Cdriver->Initialize(I2C_S_SIGNAL_EVENT);
202     if (ARM_DRIVER_OK != status)
203     {
204         return -1;
205     }
206 
207     /*! Set the I2C Power mode. */
208     status = pI2Cdriver->PowerControl(ARM_POWER_FULL);
209     if (ARM_DRIVER_OK != status)
210     {
211         return -1;
212     }
213 
214     /*! Set the I2C bus speed. */
215     status = pI2Cdriver->Control(ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST);
216     if (ARM_DRIVER_OK != status)
217     {
218         return -1;
219     }
220 
221     /*! Initialize the UART driver. */
222     status = pUartDriver->Initialize(HOST_S_SIGNAL_EVENT);
223     if (ARM_DRIVER_OK != status)
224     {
225         return -1;
226     }
227 
228     /*! Set the UART Power mode. */
229     status = pUartDriver->PowerControl(ARM_POWER_FULL);
230     if (ARM_DRIVER_OK != status)
231     {
232         return -1;
233     }
234 
235     /*! Set UART Baud Rate. */
236     status = pUartDriver->Control(ARM_USART_MODE_ASYNCHRONOUS, BOARD_DEBUG_UART_BAUDRATE);
237     if (ARM_DRIVER_OK != status)
238     {
239         return -1;
240     }
241 
242     /*! Initialize the MMA9553 sensor driver. */
243     status = MMA9553_I2C_Initialize(&mma9553Driver, &I2C_S_DRIVER, I2C_S_DEVICE_INDEX, MMA9553_I2C_ADDR);
244     if (SENSOR_ERROR_NONE == status)
245     {
246         /*!  Set the task to be executed while waiting for I2C transactions to complete. */
247         MMA9553_I2C_SetIdleTask(&mma9553Driver, (registeridlefunction_t)SMC_SetPowerModeVlpr, SMC);
248 
249         /*! Configure the MMA9553 sensor driver with 30Hz Mode settings. */
250         status = MMA9553_I2C_Configure(&mma9553Driver, cMma9553Config30Hz);
251         if (SENSOR_ERROR_NONE == status)
252         {
253             bMma9553Ready = true;
254         }
255     }
256 
257     /*! Initialize streaming and assign a Stream ID. */
258     gStreamID =
259         Host_IO_Init(pUartDriver, (void *)mma9553Driver.pCommDrv, &mma9553Driver.deviceInfo, NULL, MMA9553_I2C_ADDR);
260     /* Confirm if a valid Stream ID has been allocated for this stream. */
261     if (0 == gStreamID)
262     {
263         bMma9553Ready = false;
264     }
265     else
266     {
267         /*! Populate streaming header. */
268         Host_IO_Add_ISO_Header(gStreamID, streamingPacket, MMA9553_STREAM_DATA_SIZE);
269         pGpioDriver->clr_pin(&GREEN_LED);
270     }
271 
272     LPTMR_StartTimer(LPTMR0);
273     for (;;) /* Forever loop */
274     {        /* Call UART Non-Blocking Receive. */
275         Host_IO_Receive(process_host_command, HOST_FORMAT_HDLC);
276 
277         /* Process packets only if streaming has been enabled by Host and ODR Timer ISR has expired. */
278         if (false == bStreamingEnabled || false == bMma9553DataReady)
279         {
280             SMC_SetPowerModeWait(SMC); /* Power save, wait if nothing to do. */
281             continue;
282         }
283         else
284         { /*! Clear the data ready flag, it will be set again by the ISR. */
285             bMma9553DataReady = false;
286             pGpioDriver->toggle_pin(&GREEN_LED);
287         }
288 
289         /*! Read the raw sensor data from the MMA9553. */
290         status = MMA9553_I2C_CommandResponse(&mma9553Driver, NULL, cMma9553ReadRawOutput, (uint8_t *)&rawData.accel);
291         if (ARM_DRIVER_OK != status)
292         {
293             continue;
294         }
295 
296         /* Update timestamp from Systick framework. */
297         rawData.timestamp += BOARD_SystickElapsedTime_us(&gSystick);
298 
299         /* Copy Raw samples to Streaming Buffer. */
300         memcpy(streamingPacket + STREAMING_HEADER_LEN, &rawData, MMA9553_STREAM_DATA_SIZE);
301         /* Send streaming packet to Host. */
302         Host_IO_Send(streamingPacket, sizeof(streamingPacket), HOST_FORMAT_HDLC);
303     }
304 }
305