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: fxlc95000_flash_demo.c
11  * @brief The fxlc95000_flash_demo.c file implements the ISSDK FXLC95000L sensor driver
12  *          example demonstration for FLASH programming and Streaming for I2C Mode using Host I/O.
13  */
14 
15 //-----------------------------------------------------------------------
16 // SDK Includes
17 //-----------------------------------------------------------------------
18 #include "board.h"
19 #include "pin_mux.h"
20 #include "fsl_lptmr.h"
21 #include "clock_config.h"
22 
23 //-----------------------------------------------------------------------
24 // CMSIS Includes
25 //-----------------------------------------------------------------------
26 #include "Driver_I2C.h"
27 #include "Driver_USART.h"
28 
29 //-----------------------------------------------------------------------
30 // ISSDK Includes
31 //-----------------------------------------------------------------------
32 #include "issdk_hal.h"
33 #include "gpio_driver.h"
34 #include "host_io_uart.h"
35 #include "systick_utils.h"
36 #include "fxlc95000_drv.h"
37 #include "auto_detection_service.h"
38 
39 //-----------------------------------------------------------------------
40 // Macros
41 //-----------------------------------------------------------------------
42 #define fxlc95000_odrCallback LPTMR0_IRQHandler /* Timer timeout Callback. */
43 #define SAMPLING_RATE_ms 100                    /* Timeout for the ODR Timer in ms. */
44 #define FXLC95000_SAMPLE_SIZE 10                /* 4-Byte timestamp and 2-Byte X,Y,Z Data each. */
45 
46 /*! @brief Unique Name for this application which should match the target GUI pkg name. */
47 #define APPLICATION_NAME "FXLC95000 Accelerometer Demo"
48 /*! @brief Version to distinguish between instances the same application based on target Shield and updates. */
49 #define APPLICATION_VERSION "2.5"
50 
51 //-----------------------------------------------------------------------
52 // Constants
53 //-----------------------------------------------------------------------
54 /*! Create commands for setting FXLC95000L desired configuration. */
55 const uint8_t cFxlc95000_SetODR_Cmd[] = {FXLC95000_SET_ODR_CMD_HDR, /* ODR equal to Sampling Rate. */
56                                          FXLC95000_SST_ODR_PAYLOAD(SAMPLING_RATE_ms * 1000)};
57 const uint8_t cFxlc95000_SetResolution_Cmd[] = {FXLC95000_SET_RESOLUTION_CMD_HDR, /* Resolution 14-bits. */
58                                                 FXLC95000_ACCEL_RESOLUTION_14_BIT};
59 const uint8_t cFxlc95000_SetRange_Cmd[] = {FXLC95000_SET_RANGE_CMD_HDR, /* FS Range 2G. */
60                                            FXLC95000_ACCEL_RANGE_2G};
61 
62 /*! Prepare the register write list to initialize FXLC95000L with desired MBox Settings. */
63 const registercommandlist_t cFxlc95000ConfigMBox[] = {
64     {QuickReadInterruptDisable, 0, sizeof(QuickReadInterruptDisable)}, /* Disable QR INT. */
65     {ConfigureMBoxCmd, 0, sizeof(ConfigureMBoxCmd)}, /* Configure MBox 16 to 25 with 10 byte Sample. */
66     __END_WRITE_CMD__                                /* Ref. Table 3-7 of ISF1P195K_SW_REFERENCE_RM. */
67 };
68 
69 /*! Prepare the register write list to configure FXLC95000L with desired Sampling Settings. */
70 const registercommandlist_t cFxlc95000ConfigSensor[] = {
71     {StopDataCmd, 0, sizeof(StopDataCmd)},                                   /* Stop Data before (re)configuration. */
72     {cFxlc95000_SetODR_Cmd, 0, sizeof(cFxlc95000_SetODR_Cmd)},               /* Set Sensor Sampling Rate. */
73     {cFxlc95000_SetRange_Cmd, 0, sizeof(cFxlc95000_SetRange_Cmd)},           /* Set FS Range. */
74     {cFxlc95000_SetResolution_Cmd, 0, sizeof(cFxlc95000_SetResolution_Cmd)}, /* Set Resolution */
75     {StartDataCmd, 0, sizeof(StartDataCmd)},                                 /* Start Data after (re)configuration. */
76     __END_WRITE_CMD__};
77 
78 /*! Prepare the register write list with Flash Preprocess Commands. */
79 const registercommandlist_t cFxlc95000FlashPreprocess[] = {
80     {UnprotectFlash, 0, sizeof(UnprotectFlash)},           /* Unprotect Flash Banks to enable Writing. */
81     {EraseMainFlashArray, 0, sizeof(EraseMainFlashArray)}, /* Erase Flash completely before writing new Data. */
82     __END_WRITE_CMD__                                      /* Ref. Section 16.5 of FXLC95000CLHWRM. */
83 };
84 
85 /*! Prepare the register write list with Flash Postprocess Commands. */
86 const registercommandlist_t cFxlc95000FlashPostprocess[] = {
87     {ProtectFlash, 0, sizeof(ProtectFlash)}, /* Protect Flash Banks after Writing to enable booting to Flash. */
88     __END_WRITE_CMD__                        /* Ref. Section 16.5 of FXLC95000CLHWRM. */
89 };
90 
91 /*! Prepare the register read list to read the Timestamp and Accel data from FXLC95000. */
92 const registerreadlist_t cFxlc95000ReadSample[] = {
93     {.readFrom = FXLC95000_SAMPLE_OFFSET, .numBytes = FXLC95000_SAMPLE_SIZE}, __END_READ_DATA__};
94 
95 //-----------------------------------------------------------------------
96 // Global Variables
97 //-----------------------------------------------------------------------
98 char boardString[ADS_MAX_STRING_LENGTH] = {0}, shieldString[ADS_MAX_STRING_LENGTH] = {0},
99      embAppName[ADS_MAX_STRING_LENGTH] = {0};
100 volatile bool bStreamingEnabled = false, bFxlc95000DataReady = false, bFxlc95000Ready = false, bFxlc95000Boot = false,
101               bFxlc95000Flashing = false;
102 fxlc95000_i2c_sensorhandle_t fxlc95000Driver = /* Sensor Handle. */
103     {.deviceInfo = {.deviceInstance = I2C_S_DEVICE_INDEX, .idleFunction = NULL}};
104 uint8_t gStreamID; /* The auto assigned Stream ID. */
105 GENERIC_DRIVER_GPIO *pGpioDriver = &Driver_GPIO_KSDK;
106 
107 //-----------------------------------------------------------------------
108 // Functions
109 //-----------------------------------------------------------------------
110 /* LPTMR based ODR Callback function. */
fxlc95000_odrCallback(void)111 void fxlc95000_odrCallback(void)
112 {
113     LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
114     bFxlc95000DataReady = true;
115 }
116 
117 /* Sequence of commands for booting up FXLC95000 to Flash and enabling reading of samples. */
fxlc95000_enSensor(fxlc95000_i2c_sensorhandle_t * pSensorHandle)118 int fxlc95000_enSensor(fxlc95000_i2c_sensorhandle_t *pSensorHandle)
119 {
120     int32_t status;
121 
122     /*! Initialize the FXLC95000 sensor driver. */
123     status = FXLC95000_I2C_Initialize(pSensorHandle, &I2C_S_DRIVER, I2C_S_DEVICE_INDEX, FXLC95000_I2C_ADDR,
124                                       FXLC95000_BUILD_ID);
125     if (SENSOR_ERROR_NONE != status)
126     {
127         return -1;
128     }
129 
130     /*!  Set the task to be executed while waiting for I2C transactions to complete. */
131     FXLC95000_I2C_SetIdleTask(pSensorHandle, (registeridlefunction_t)SMC_SetPowerModeVlpr, SMC);
132 
133     /*! Configure the FXLC95000 with MBox settings. */
134     status = FXLC95000_I2C_CommandResponse(pSensorHandle, cFxlc95000ConfigMBox, NULL, NULL);
135     if (SENSOR_ERROR_NONE != status)
136     {
137         return -1;
138     }
139     /*! Configure the FXLC95000 with Sampling settings. */
140     status = FXLC95000_I2C_CommandResponse(pSensorHandle, cFxlc95000ConfigSensor, NULL, NULL);
141     if (SENSOR_ERROR_NONE != status)
142     {
143         return -1;
144     }
145 
146     LPTMR_StartTimer(LPTMR0);
147     bFxlc95000Boot = true;
148     pGpioDriver->set_pin(&RED_LED);   /* Clear RED LED to indicate sensor boot process is complete. */
149     pGpioDriver->clr_pin(&GREEN_LED); /* Set GREEN LED to indicate application is ready. */
150     return 0;
151 }
152 
153 /* Handler for Flash Write, Device Info and Streaming Control Commands. */
process_host_command(uint8_t tag,uint8_t * hostCommand,uint8_t * hostResponse,size_t * hostMsgSize,size_t respBufferSize)154 bool process_host_command(
155     uint8_t tag, uint8_t *hostCommand, uint8_t *hostResponse, size_t *hostMsgSize, size_t respBufferSize)
156 {
157     static uint8_t toggle_led = 0;
158     bool success = false;
159     size_t rxMsgSize = *hostMsgSize; /* Capture Rx Command Size. */
160     *hostMsgSize = 0;                /* Set Tx Response payload size to '0' as default and update if required. */
161 
162     /* If it is Host requesting Device Info, send Board Name and Shield Name. */
163     if (tag == HOST_PRO_INT_DEV_TAG)
164     { /* Byte 1     : Payload - Length of APPLICATION_NAME (b)
165        * Bytes=b    : Payload Application Name
166        * Byte b+1   : Payload - Length of BOARD_NAME (s)
167        * Bytes=s    : Payload Board Name
168        * Byte b+s+2 : Payload - Length of SHIELD_NAME (v)
169        * Bytes=v    : Payload Shield Name */
170 
171         size_t appNameLen = strlen(embAppName);
172         size_t boardNameLen = strlen(boardString);
173         size_t shieldNameLen = strlen(shieldString);
174 
175         if (respBufferSize >= boardNameLen + shieldNameLen + appNameLen + 3)
176         { /* We have sufficient buffer. */
177             *hostMsgSize = 0;
178         }
179         else
180         {
181             return false;
182         }
183 
184         hostResponse[*hostMsgSize] = appNameLen;
185         *hostMsgSize += 1;
186 
187         memcpy(hostResponse + *hostMsgSize, embAppName, appNameLen);
188         *hostMsgSize += appNameLen;
189 
190         hostResponse[*hostMsgSize] = boardNameLen;
191         *hostMsgSize += 1;
192 
193         memcpy(hostResponse + *hostMsgSize, boardString, boardNameLen);
194         *hostMsgSize += boardNameLen;
195 
196         hostResponse[*hostMsgSize] = shieldNameLen;
197         *hostMsgSize += 1;
198 
199         memcpy(hostResponse + *hostMsgSize, shieldString, shieldNameLen);
200         *hostMsgSize += shieldNameLen;
201 
202         if (false == bFxlc95000Boot) /* Bringup FXLC95000 if not already done. */
203         {
204             if (fxlc95000_enSensor(&fxlc95000Driver))
205             {
206                 bFxlc95000Boot = false;
207             }
208         }
209 
210         return true;
211     }
212 
213     /* If it is Host sending Streaming Commands, take necessary actions. */
214     if ((tag == (HOST_PRO_INT_CMD_TAG | HOST_PRO_CMD_W_CFG_TAG)) &&
215         (rxMsgSize == HOST_MSG_CMD_ACT_OFFSET - HOST_MSG_LEN_LSB_OFFSET))
216     {                           /* Byte 1 : Payload - Operation Code (Start/Stop Operation Code)
217                                  * Byte 2 : Payload - Stream ID (Target Stream for carrying out operation) */
218         switch (hostCommand[0]) /* Execute desired operation (Start/Stop) on the requested Stream. */
219         {
220             case HOST_CMD_START:
221                 if (hostCommand[1] == gStreamID && bStreamingEnabled == false)
222                 {
223                     if (false == bFxlc95000Boot) /* Bringup FXLC95000 if not already done. */
224                     {
225                         if (fxlc95000_enSensor(&fxlc95000Driver))
226                         {
227                             break;
228                         }
229                     }
230                     bStreamingEnabled = true;
231                     success = true;
232                 }
233                 break;
234             case HOST_CMD_STOP:
235                 if (hostCommand[1] == gStreamID && bStreamingEnabled == true)
236                 {
237                     pGpioDriver->clr_pin(&GREEN_LED);
238                     bStreamingEnabled = false;
239                     success = true;
240                 }
241                 break;
242             default:
243                 break;
244         }
245     }
246 
247     /* If it is Host sending Flash Commands, take necessary actions. */
248     if ((tag == (HOST_PRO_INT_CMD_TAG | HOST_PRO_CMD_W_CFG_TAG)) &&
249         (rxMsgSize >= HOST_MSG_CMD_ACT_OFFSET - HOST_MSG_LEN_LSB_OFFSET))
250     {                           /* Byte 1  : Payload - Operation Code (Start/Bytes/Stop Operation Code)
251                                  * Byte 2  : Payload - Slave ID (The Sensor's I2C Slave Address)
252                                  * Byte 3+ : Payload - (Only for Flash Bytes) The Flash Payload to be Written. */
253         switch (hostCommand[0]) /* Execute desired operation on the requested Sensor. */
254         {
255             case HOST_CMD_FLASH_START:
256                 /* Confirm Flashing is not active and Sensor is in ROM Mode. */
257                 if ((hostCommand[1] == FXLC95000_I2C_ADDR && false == bFxlc95000Flashing) &&
258                     (0 == FXLC95000_I2C_CheckRomMode(&I2C_S_DRIVER, I2C_S_DEVICE_INDEX, FXLC95000_I2C_ADDR)))
259                 { /*! Write Flash Preprocess Commands. */
260                     if (SENSOR_ERROR_NONE == FXLC95000_I2C_FlashCommands(&I2C_S_DRIVER, I2C_S_DEVICE_INDEX,
261                                                                          FXLC95000_I2C_ADDR, cFxlc95000FlashPreprocess))
262                     {
263                         bFxlc95000Flashing = true;
264                         success = true;
265                     }
266                     pGpioDriver->set_pin(&RED_LED); /* Indicate Flash Processing is active. */
267                 }
268                 break;
269             case HOST_CMD_FLASH_BYTES:
270                 /* Confirm Flashing is active. */
271                 if ((hostCommand[1] == FXLC95000_I2C_ADDR) && (true == bFxlc95000Flashing))
272                 { /*! Write Flash Data Bytes. */
273                     if (SENSOR_ERROR_NONE == FXLC95000_I2C_FlashPayload(&I2C_S_DRIVER, I2C_S_DEVICE_INDEX,
274                                                                         FXLC95000_I2C_ADDR, hostCommand + 2,
275                                                                         rxMsgSize - 2))
276                     {
277                         success = true;
278                     }
279                     if (toggle_led++ % 32 == 0 ? true : false)
280                     {
281                         pGpioDriver->toggle_pin(&RED_LED); /* Indicate Flash Processing is active. */
282                     }
283                 }
284                 break;
285             case HOST_CMD_FLASH_STOP:
286                 /* Confirm Flashing is active. */
287                 if ((hostCommand[1] == FXLC95000_I2C_ADDR) && (true == bFxlc95000Flashing))
288                 { /*! Write Flash Postprocess Commands. */
289                     if (SENSOR_ERROR_NONE == FXLC95000_I2C_FlashCommands(&I2C_S_DRIVER, I2C_S_DEVICE_INDEX,
290                                                                          FXLC95000_I2C_ADDR,
291                                                                          cFxlc95000FlashPostprocess))
292                     {
293                         bFxlc95000Flashing = false;
294                         success = true;
295                     }
296                     pGpioDriver->clr_pin(&RED_LED); /* Indicate Flash Processing is complete. */
297                 }
298                 break;
299             default:
300                 break;
301         }
302     }
303 
304     return success;
305 }
306 
307 /*!
308  * @brief Main function
309  */
main(void)310 int main(void)
311 {
312     int32_t status;
313     uint8_t streamingPacket[STREAMING_HEADER_LEN + FXLC95000_SAMPLE_SIZE];
314     lptmr_config_t lptmrConfig;
315 
316     ARM_DRIVER_I2C *I2Cdrv = &I2C_S_DRIVER;
317     ARM_DRIVER_USART *pUartDriver = &HOST_S_DRIVER;
318 
319     /*! Initialize the MCU hardware. */
320     BOARD_BootClockRUN();
321     BOARD_SystickEnable();
322 
323     /* Create the Short Application Name String for ADS. */
324     sprintf(embAppName, "%s:%s", APPLICATION_NAME, APPLICATION_VERSION);
325 
326     /* Run ADS. */
327     BOARD_RunADS(embAppName, boardString, shieldString, ADS_MAX_STRING_LENGTH);
328 
329     /* Create the Full Application Name String for Device Info Response. */
330     sprintf(embAppName, "%s:%s:%s", SHIELD_NAME, APPLICATION_NAME, APPLICATION_VERSION);
331 
332     /* Initialize ODR Timer. */
333     LPTMR_GetDefaultConfig(&lptmrConfig);
334     LPTMR_Init(LPTMR0, &lptmrConfig);
335     LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
336     LPTMR_SetTimerPeriod(LPTMR0, MSEC_TO_COUNT(SAMPLING_RATE_ms, CLOCK_GetFreq(kCLOCK_LpoClk)));
337     EnableIRQ(LPTMR0_IRQn);
338 
339     /*! Initialize RED LED pin used by FRDM board */
340     pGpioDriver->pin_init(&RED_LED, GPIO_DIRECTION_OUT, NULL, NULL, NULL);
341     pGpioDriver->set_pin(&RED_LED);
342 
343     /*! Initialize GREEN LED pin used by FRDM board */
344     pGpioDriver->pin_init(&GREEN_LED, GPIO_DIRECTION_OUT, NULL, NULL, NULL);
345     pGpioDriver->set_pin(&GREEN_LED);
346 
347     /*! Initialize the I2C driver. */
348     status = I2Cdrv->Initialize(I2C_S_SIGNAL_EVENT);
349     if (ARM_DRIVER_OK != status)
350     {
351         return -1;
352     }
353 
354     /*! Set the I2C Power mode. */
355     status = I2Cdrv->PowerControl(ARM_POWER_FULL);
356     if (ARM_DRIVER_OK != status)
357     {
358         return -1;
359     }
360 
361     /*! Set the I2C bus speed. */
362     status = I2Cdrv->Control(ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST);
363     if (ARM_DRIVER_OK != status)
364     {
365         return -1;
366     }
367 
368     /*! Initialize the UART driver. */
369     status = pUartDriver->Initialize(HOST_S_SIGNAL_EVENT);
370     if (ARM_DRIVER_OK != status)
371     {
372         return -1;
373     }
374 
375     /*! Set the UART Power mode. */
376     status = pUartDriver->PowerControl(ARM_POWER_FULL);
377     if (ARM_DRIVER_OK != status)
378     {
379         return -1;
380     }
381 
382     /*! Set UART Baud Rate. */
383     status = pUartDriver->Control(ARM_USART_MODE_ASYNCHRONOUS, BOARD_DEBUG_UART_BAUDRATE);
384     if (ARM_DRIVER_OK != status)
385     {
386         return -1;
387     }
388 
389     /*! Register with Host I/O Service and get a Stream ID. */
390     gStreamID = Host_IO_Init(pUartDriver, (void *)&I2C_S_DRIVER, &fxlc95000Driver.deviceInfo, NULL, FXLC95000_I2C_ADDR);
391     /* Confirm if a valid Stream ID has been allocated for this stream. */
392     if (0 == gStreamID)
393     {
394         return -1;
395     }
396 
397     /*! Populate streaming header. */
398     Host_IO_Add_ISO_Header(gStreamID, streamingPacket, FXLC95000_SAMPLE_SIZE);
399     pGpioDriver->clr_pin(&RED_LED); /* Set the RED LED to indicate that Boot proccess has not been done.*/
400 
401     for (;;) /* Forever loop */
402     {        /* Call UART Non-Blocking Receive to check for Commands from Host. */
403         Host_IO_Receive(process_host_command, HOST_FORMAT_HDLC);
404 
405         if (false == bStreamingEnabled || false == bFxlc95000DataReady)
406         {
407             SMC_SetPowerModeWait(SMC); /* Power save, wait if nothing to do. */
408             continue;
409         }
410         else
411         { /*! Clear the data ready flag, it will be set again by the ISR. */
412             bFxlc95000DataReady = false;
413             pGpioDriver->toggle_pin(&GREEN_LED);
414         }
415 
416         /*! Read raw sensor data from the FXLC95000. */
417         status = FXLC95000_I2C_CommandResponse(&fxlc95000Driver, NULL, cFxlc95000ReadSample,
418                                                streamingPacket + STREAMING_HEADER_LEN);
419         if (ARM_DRIVER_OK != status)
420         { /* Loop, if sample read failed. */
421             continue;
422         }
423 
424         /* Send streaming packet to Host. */
425         Host_IO_Send(streamingPacket, sizeof(streamingPacket), HOST_FORMAT_HDLC);
426     }
427 }
428