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