1 /*
2  * Copyright 2022 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 /**
9  * @file fxls8974cf_freemaster_usb_demo.c
10  * @brief The fxls8974cf_freemaster_usb_demo.c file implements FreeMASTER demo using the ISSDK
11  *        FXLS8974CF sensor driver example demonstration with interrupt mode.
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 #include "math.h"
22 #include "fsl_uart.h"
23 #include "fsl_common.h"
24 #include "freemaster.h"
25 #include "usb_device_config.h"
26 #include "freemaster_usb.h"
27 //-----------------------------------------------------------------------
28 // CMSIS Includes
29 //-----------------------------------------------------------------------
30 #include "Driver_I2C.h"
31 
32 //-----------------------------------------------------------------------
33 // ISSDK Includes
34 //-----------------------------------------------------------------------
35 #include "issdk_hal.h"
36 #include "gpio_driver.h"
37 #include "fxls8974_drv.h"
38 #include "systick_utils.h"
39 
40 //-----------------------------------------------------------------------
41 // Macros
42 //-----------------------------------------------------------------------
43 #define FXLS8974_NUM_REGISTERS (FXLS8974_SELF_TEST_CONFIG2 + 1)
44 #define FF_A_FFMT_THS          (0x08)       /* FreeFall Threshold Value. */
45 #define A_FFMT_COUNT           (0x18)       /* Freefall/motion debounce count value. */
46 #define PL_COUNT               (0x15)       /* Pulse debounce count value. */
47 #define ASLP_COUNTER           (0x07)       /* Auto Sleep after ~5s. */
48 #define ACCEL_2G_SENS          (0.000976)   /* Sensitivity factor for 2G FS */
49 #define ACCEL_4G_SENS          (0.001953)   /* Sensitivity factor for 4G FS */
50 #define ACCEL_8G_SENS          (0.003906)   /* Sensitivity factor for 8G FS */
51 #define ACCEL_16G_SENS         (0.007813)   /* Sensitivity factor for 16G FS */
52 #define N                      (100U)       /* Number of samples used to measure offset/noise */
53 #define RAW_ACCEL_DATA_SIZE    (6U)         /* Accel Data Size */
54 #define MAX8BITSTORAGE         (255U)
55 #define FXLS8974_DATA_SIZE 6
56 //-----------------------------------------------------------------------
57 // Constants
58 //-----------------------------------------------------------------------
59 /*! @brief Defines the register write list to configure FXLS8974 in Interrupt mode. */
60 const registerwritelist_t cFxls8974ConfigNormal[] = {
61     /*! Set Full-scale range as 4G. */
62     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_FSR_4G, FXLS8974_SENS_CONFIG1_FSR_MASK},
63     /*! Clear SENS_CONFIG2 */
64     {FXLS8974_SENS_CONFIG2, 0x00, 0x00},
65     /*! Disable Self-Test. */
66     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_DISABLED, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_MASK},
67     /*! Set Wake Mode ODR Rate as 12.5Hz. */
68     {FXLS8974_SENS_CONFIG3, FXLS8974_SENS_CONFIG3_WAKE_ODR_12_5HZ, FXLS8974_SENS_CONFIG3_WAKE_ODR_MASK},
69     /*! Enable Interrupts for Data Ready Events. */
70     {FXLS8974_INT_EN, FXLS8974_INT_EN_DRDY_EN_EN, FXLS8974_INT_EN_DRDY_EN_MASK},
71     /*! Enable Temperature sensor. */
72     {FXLS8974_SENS_CONFIG2,FXLS8974_SENS_CONFIG2_ANIC_TEMP_EN,FXLS8974_SENS_CONFIG2_ANIC_TEMP_MASK},
73     /*! Set Self-Test ODR to 100 Hz. */
74     {0x38,0x05,0x00},
75     {0x2F,0x38,0x00},
76     {0x30,0xD8,0x00},
77     {0x33,0xC0,0x00},
78     {0x34,0xFF,0x00},
79     {0x35,0x40,0x00},
80     __END_WRITE_DATA__};
81 
82 /*! @brief Register settings for Self-Test in X Axis (Positive polarity). */
83 const registerwritelist_t cFxls8974STXP[] = {
84     /* Set Self Test Axis. */
85     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_FSR_16G, FXLS8974_SENS_CONFIG1_FSR_MASK},
86     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_EN_X, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_MASK},
87     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_POL_POSITIVE,  FXLS8974_SENS_CONFIG1_ST_POL_MASK},
88     __END_WRITE_DATA__};
89 
90 /*! @brief Register settings for Self-Test in X Axis (Negative polarity). */
91 const registerwritelist_t cFxls8974STXN[] = {
92     /* Set Self Test Axis. */
93     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_FSR_16G, FXLS8974_SENS_CONFIG1_FSR_MASK},
94     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_EN_X, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_MASK},
95     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_POL_NEGATIVE, FXLS8974_SENS_CONFIG1_ST_POL_MASK},
96     __END_WRITE_DATA__};
97 
98 /*! @brief Register settings for Self-Test in Y Axis (Positive polarity). */
99 const registerwritelist_t cFxls8974STYP[] = {
100     /* Set Self Test Axis. */
101     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_FSR_16G, FXLS8974_SENS_CONFIG1_FSR_MASK},
102     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_EN_Y, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_MASK},
103     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_POL_POSITIVE,FXLS8974_SENS_CONFIG1_ST_POL_MASK},
104     __END_WRITE_DATA__};
105 
106 /*! @brief Register settings for Self-Test in Y Axis (Negative polarity). */
107 const registerwritelist_t cFxls8974STYN[] = {
108     /* Set Self Test Axis. */
109     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_FSR_16G, FXLS8974_SENS_CONFIG1_FSR_MASK},
110     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_EN_Y, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_MASK},
111     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_POL_NEGATIVE, FXLS8974_SENS_CONFIG1_ST_POL_MASK},
112     __END_WRITE_DATA__};
113 
114 /*! @brief Register settings for Self-Test in Z Axis (Positive polarity). */
115 const registerwritelist_t cFxls8974STZP[] = {
116     /* Set Self Test Axis. */
117     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_FSR_16G, FXLS8974_SENS_CONFIG1_FSR_MASK},
118     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_EN_Z, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_MASK},
119     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_POL_POSITIVE, FXLS8974_SENS_CONFIG1_ST_POL_MASK},
120     __END_WRITE_DATA__};
121 
122 /*! @brief Register settings for Self-Test in Z Axis (Negative polarity). */
123 const registerwritelist_t cFxls8974STZN[] = {
124     /* Set Self Test Axis. */
125     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_FSR_16G, FXLS8974_SENS_CONFIG1_FSR_MASK},
126     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_EN_Z, FXLS8974_SENS_CONFIG1_ST_AXIS_SEL_MASK},
127     {FXLS8974_SENS_CONFIG1, FXLS8974_SENS_CONFIG1_ST_POL_NEGATIVE,  FXLS8974_SENS_CONFIG1_ST_POL_MASK},
128     __END_WRITE_DATA__};
129 
130 /*! @brief Address of Raw Accel Data in Normal Mode. */
131 const registerreadlist_t cFxls8974OutputNormal[] = {{.readFrom = FXLS8974_OUT_X_LSB, .numBytes = FXLS8974_DATA_SIZE},
132     __END_READ_DATA__};
133 
134 const registerreadlist_t cFXLS8974_whoami[] = {
135         {.readFrom = FXLS8974_WHO_AM_I, .numBytes = 1}, __END_READ_DATA__};
136 
137 /*! @brief Prepare the register read for INT Status Register. */
138 const registerreadlist_t cFXLS8974_int_src[] = {
139         {.readFrom = FXLS8974_INT_STATUS, .numBytes = 1}, __END_READ_DATA__};
140 
141 /*! @brief Prepare the register read for FullScale range Register. */
142 const registerreadlist_t cFXLS8974_fs_src[] = {
143         {.readFrom = FXLS8974_SENS_CONFIG1, .numBytes = 1}, __END_READ_DATA__};
144 
145 /*! @brief FXLS8974 register list to read all registers */
146 const registerreadlist_t FXLS8974_ALL_REG_READ[] = {{.readFrom = FXLS8974_INT_STATUS, .numBytes = FXLS8974_NUM_REGISTERS},
147                                                       __END_READ_DATA__};
148 
149 //-----------------------------------------------------------------------
150 // Global Variables
151 //-----------------------------------------------------------------------
152 /*! @brief This structure defines the fxls8974 all registers metadata.*/
153 typedef struct
154 {
155     uint8_t offset;
156     uint8_t value;
157     uint8_t trigger;
158     uint8_t read_offset;
159     uint8_t read_value;
160     uint8_t read_trigger;
161     uint8_t readall_value[FXLS8974_NUM_REGISTERS];
162     uint8_t readall_size;
163     uint8_t readall_trigger;
164     uint8_t toggle;
165     uint8_t trigger_accel_offnoise;
166     uint8_t trigger_selftest;
167     uint8_t fs_value;
168     uint8_t mods_value;
169     uint8_t odr_value;
170     uint8_t reg_addr[FXLS8974_NUM_REGISTERS];
171     uint8_t dataready_cntr;
172     float accel[3];
173     int16_t accelraw[3];
174     uint8_t sdcd;
175     int8_t temp;
176     int16_t selftest[3];
177     uint32_t timestamp;
178 } fxls8974_allregs_t;
179 //-----------------------------------------------------------------------
180 /*! @brief This structure defines the fxls8974 offset and noise calculation parameters. */
181 typedef struct
182 {
183   	float offx;
184   	float offy;
185   	float offz;
186   	float rmsx;
187   	float rmsy;
188   	float rmsz;
189   	uint8_t complete_accel_offnoise;
190 } fxls8974_offset_noise_t;
191 
192 /*! @brief This structure defines variables to compute self-test output change (STOC) and self-test offset (STOF). */
193 typedef struct
194 {
195 	int16_t x_stoc;
196 	int16_t y_stoc;
197 	int16_t z_stoc;
198 	int16_t x_stof;
199 	int16_t y_stof;
200 	int16_t z_stof;
201   	uint8_t complete_selftest;
202 } fxls8974_selftest_t;
203 
204 /*! @brief This structure defines the fxls8974 raw data buffer.*/
205 typedef struct
206 {
207     int16_t xdata; /*!< The x accel data */
208     int16_t ydata; /*!< The y accel data */
209     int16_t zdata; /*!< The z accel data */
210 } sensor_data;
211 
212 
213 typedef union rawdata
214 {
215 	uint8_t byte_data[sizeof(sensor_data)];
216 	sensor_data dat;
217 }RAW_DATA;
218 
219 /*! @brief This structure defines the fxls8974 host operation type.*/
220 typedef enum fxls8974_operation_type
221 {
222 	FXLS8974_REG_WRITE   = 1U,
223 	FXLS8974_REG_READ    = 2U,
224     FXLS8974_ALLREG_READ = 3U,
225 	FXLS8974_ACCEL_CONFIG_END
226 
227 } fxls8974_operation_type_t;
228 
229 /*******************************************************************************
230  * Globals
231  ******************************************************************************/
232 
233 fxls8974_acceldata_t rawData;
234 fxls8974_allregs_t      registers;
235 fxls8974_offset_noise_t offnoise_data;
236 fxls8974_selftest_t selftest;
237 uint8_t prev_toggle = 1;
238 volatile bool bFxls8974IntFlag = false;
239 
240 static FMSTR_U8 recBuffer[1024*10];
241 FMSTR_REC_BUFF  recBuffCfg;
242 FMSTR_REC_VAR   recVar;
243 FMSTR_REC_CFG   recCfg;
244 
245 int32_t status, gSystick;
246 static unsigned char pipe3_rxb[512];
247 static unsigned char pipe3_txb[0x1000];
248 
249 uint8_t axis=0;
250 /* variables to store self-test values (Positive(P) + / Negative(N) -) */
251 int16_t XSTP[2]={0,0},YSTP[2]={0,0},ZSTP[2]={0,0},XSTN[2]={0,0},YSTN[2]={0,0},ZSTN[2]={0,0};
252 
253 
254 /*******************************************************************************
255  * Local functions
256  ******************************************************************************/
257 /*! @brief           ISR for FXLS8974 interrupt source event.
258  *  @details         This function implements ISR for FXLS8974 INT source.
259  *  @param[in]       void *.
260  *  @return          void.
261  */
262 void fxls8974_isr_callback(void *pUserData);
263 /*! @brief           Function to apply FXLS8974 register write operation.
264  *  @details         This function apply FXLS8974 register write based on write trigger from host.
265  *  @param[in]       fxls8974_i2c_sensorhandle_t fxls8974Driver, FXLS8974 sensor I2C handle.
266  *  @param[in]       uint8_t offset, the address of the register to start writing from.
267  *  @param[in]       uint8_t value, value to write on register offset.
268  *  @return          returns the status of the operation.
269  */
270 int32_t apply_register_write(fxls8974_i2c_sensorhandle_t fxls8974Driver, uint8_t offset, uint8_t value);
271 /*! @brief           Function to apply FXLS8974 register read operation.
272  *  @details         This function apply FXLS8974 register read based on read trigger from host.
273  *  @param[in]       fxls8974_i2c_sensorhandle_t fxls8974Driver, FXLS8974 sensor I2C handle.
274  *  @param[in]       uint8_t offset, the address of the register to read from.
275  *  @param[in/out]   uint8_t *value, pointer to output buffer.
276  *  @return          returns the status of the operation.
277  */
278 int32_t apply_register_read(fxls8974_i2c_sensorhandle_t fxls8974Driver, uint8_t offset, uint8_t *value);
279 /*! @brief           Function to apply FXLS8974 register read-all operation.
280  *  @details         This function apply FXLS8974 all-registers read based on read-all trigger from host.
281  *  @param[in]       fxls8974_i2c_sensorhandle_t fxls8974Driver, FXLS8974 sensor I2C handle.
282  *  @return          returns the status of the operation.
283  */
284 int32_t apply_register_readall(fxls8974_i2c_sensorhandle_t fxls8974Driver);
285 /*! @brief           Function to update dropdown selection.
286  *  @details         This function updates the dropdown selection values in real-time based on read/write/read-all triggers.
287  *  @param[in/out]   fxls8974_allregs_t *registers, pointer to FXLS8974 all-registers metadata.
288  *  @param[in]       uint8_t caller, called from which operation type.
289  *  @return          returns the status of the operation.
290  */
291 int32_t update_dropdown_selection(fxls8974_allregs_t *registers, uint8_t caller);
292 /*! @brief           Function to initialize offset noise measurement.
293  *  @details         This function initializes offset noise measurement metadata.
294  *  @param[in/out]   fxls8974_offset_noise_t *offnoiseptr, pointer to FXLS8974 offset noise metadata.
295  *  @return          void.
296  */
297 void offset_noise_init(fxls8974_offset_noise_t *offnoiseptr);
298 /*! @brief           Function to measure accelerometer offset noise.
299  *  @details         This function measures accelerometer offset noise.
300  *  @param[in]       fxls8974_acceldata_t *rawData, pointer to FXLS8974 rawdata metadata.
301  *  @param[in/out]   fxls8974_offset_noise_t *offnoiseptr, pointer to FXLS8974 offset noise metadata.
302  *  @param[in]       float sens, FXLS8974 sensitivity based on FS configuration.
303  *  @return          void.
304  */
305 void accel_off_noise(fxls8974_acceldata_t* rawData, fxls8974_offset_noise_t *offnoiseptr, float sens);
306 /*! @brief           Function to initialize FXLS8974 self test metadata.
307  *  @details         This function initializes FXLS8974 self test metadata.
308  *  @param[in/out]   fxls8974_selftest_t *selftest, pointer to FXLS8974 selftest metadata.
309  *  @return          void.
310  */
311 void selftest_init(fxls8974_selftest_t *selftest);
312 /*! @brief           Function to perform FXLS8974 self test.
313  *  @details         This function performs FXLS8974 self test.
314  *  @param[in]       fxls8974_i2c_sensorhandle_t fxls8974Driver, FXLS8974 sensor I2C handle.
315  *  @param[in/out]   fxls8974_selftest_t *selftest, pointer to FXLS8974 selftest metadata.
316  *  @return          returns the status of the operation..
317  */
318 int32_t perform_selftest(fxls8974_i2c_sensorhandle_t fxls8974Driver, fxls8974_selftest_t *selftest);
319 void FRM_Recorder_Init();
320 
321 /*******************************************************************************
322  * Code
323  ******************************************************************************/
fxls8974_isr_callback(void * pUserData)324 void fxls8974_isr_callback(void *pUserData)
325 { /*! @brief Set flag to indicate Sensor has signalled data ready. */
326     bFxls8974IntFlag = true;
327 }
328 
329 /* Create TSA table and add output variables. */
330 /*!
331  * @brief Target Side Addressable (TSA) table created for this application.
332  */
333 FMSTR_TSA_TABLE_BEGIN(main_table)
FMSTR_TSA_STRUCT(fxls8974_acceldata_t)334 	FMSTR_TSA_STRUCT(fxls8974_acceldata_t)
335 
336 	FMSTR_TSA_STRUCT(fxls8974_allregs_t)
337     FMSTR_TSA_MEMBER(fxls8974_allregs_t, offset, FMSTR_TSA_UINT8)
338     FMSTR_TSA_MEMBER(fxls8974_allregs_t, value, FMSTR_TSA_UINT8)
339     FMSTR_TSA_MEMBER(fxls8974_allregs_t, trigger, FMSTR_TSA_UINT8)
340     FMSTR_TSA_MEMBER(fxls8974_allregs_t, read_offset, FMSTR_TSA_UINT8)
341     FMSTR_TSA_MEMBER(fxls8974_allregs_t, read_value, FMSTR_TSA_UINT8)
342     FMSTR_TSA_MEMBER(fxls8974_allregs_t, read_trigger, FMSTR_TSA_UINT8)
343     FMSTR_TSA_MEMBER(fxls8974_allregs_t, readall_value, FMSTR_TSA_UINT8)
344     FMSTR_TSA_MEMBER(fxls8974_allregs_t, readall_size, FMSTR_TSA_UINT8)
345     FMSTR_TSA_MEMBER(fxls8974_allregs_t, readall_trigger, FMSTR_TSA_UINT8)
346 	FMSTR_TSA_MEMBER(fxls8974_allregs_t, trigger_accel_offnoise, FMSTR_TSA_UINT8)
347 	FMSTR_TSA_MEMBER(fxls8974_allregs_t, trigger_selftest, FMSTR_TSA_UINT8)
348 	FMSTR_TSA_MEMBER(fxls8974_allregs_t, fs_value, FMSTR_TSA_UINT8)
349 	FMSTR_TSA_MEMBER(fxls8974_allregs_t, mods_value, FMSTR_TSA_UINT8)
350 	FMSTR_TSA_MEMBER(fxls8974_allregs_t, odr_value, FMSTR_TSA_UINT8)
351 	FMSTR_TSA_MEMBER(fxls8974_allregs_t, toggle, FMSTR_TSA_UINT8)
352     FMSTR_TSA_MEMBER(fxls8974_allregs_t, reg_addr, FMSTR_TSA_UINT8)
353     FMSTR_TSA_MEMBER(fxls8974_allregs_t, accel, FMSTR_TSA_FLOAT)
354     FMSTR_TSA_MEMBER(fxls8974_allregs_t, accelraw, FMSTR_TSA_SINT16)
355     FMSTR_TSA_MEMBER(fxls8974_allregs_t, sdcd, FMSTR_TSA_UINT8)
356     FMSTR_TSA_MEMBER(fxls8974_allregs_t, temp, FMSTR_TSA_SINT8)
357     FMSTR_TSA_MEMBER(fxls8974_allregs_t, selftest, FMSTR_TSA_SINT16)
358     FMSTR_TSA_MEMBER(fxls8974_allregs_t, dataready_cntr, FMSTR_TSA_UINT8)
359     FMSTR_TSA_MEMBER(fxls8974_allregs_t, timestamp, FMSTR_TSA_UINT32)
360 
361 	FMSTR_TSA_STRUCT(fxls8974_offset_noise_t)
362 	FMSTR_TSA_MEMBER(fxls8974_offset_noise_t, offx, FMSTR_TSA_FLOAT)
363 	FMSTR_TSA_MEMBER(fxls8974_offset_noise_t, offy, FMSTR_TSA_FLOAT)
364 	FMSTR_TSA_MEMBER(fxls8974_offset_noise_t, offz, FMSTR_TSA_FLOAT)
365 	FMSTR_TSA_MEMBER(fxls8974_offset_noise_t, rmsx, FMSTR_TSA_FLOAT)
366 	FMSTR_TSA_MEMBER(fxls8974_offset_noise_t, rmsy, FMSTR_TSA_FLOAT)
367 	FMSTR_TSA_MEMBER(fxls8974_offset_noise_t, rmsz, FMSTR_TSA_FLOAT)
368 	FMSTR_TSA_MEMBER(fxls8974_offset_noise_t, complete_accel_offnoise, FMSTR_TSA_UINT8)
369 
370 
371 	FMSTR_TSA_STRUCT(fxls8974_selftest_t)
372     FMSTR_TSA_MEMBER(fxls8974_selftest_t, x_stoc, FMSTR_TSA_SINT16)
373     FMSTR_TSA_MEMBER(fxls8974_selftest_t, y_stoc, FMSTR_TSA_SINT16)
374     FMSTR_TSA_MEMBER(fxls8974_selftest_t, z_stoc, FMSTR_TSA_SINT16)
375     FMSTR_TSA_MEMBER(fxls8974_selftest_t, x_stof, FMSTR_TSA_SINT16)
376     FMSTR_TSA_MEMBER(fxls8974_selftest_t, y_stof, FMSTR_TSA_SINT16)
377     FMSTR_TSA_MEMBER(fxls8974_selftest_t, z_stof, FMSTR_TSA_SINT16)
378 	FMSTR_TSA_MEMBER(fxls8974_selftest_t, complete_selftest, FMSTR_TSA_UINT8)
379 
380     FMSTR_TSA_RO_VAR(rawData, FMSTR_TSA_USERTYPE(fxls8974_acceldata_t))
381 
382     FMSTR_TSA_RW_VAR(registers, FMSTR_TSA_USERTYPE(fxls8974_allregs_t))
383 
384     FMSTR_TSA_RO_VAR(offnoise_data, FMSTR_TSA_USERTYPE(fxls8974_offset_noise_t))
385 
386     FMSTR_TSA_RO_VAR(selftest, FMSTR_TSA_USERTYPE(fxls8974_selftest_t))
387 
388 FMSTR_TSA_TABLE_END()
389 
390 FMSTR_TSA_TABLE_LIST_BEGIN()
391     FMSTR_TSA_TABLE(main_table)
392 FMSTR_TSA_TABLE_LIST_END()
393 
394 /*!
395  * @brief FreeMASTER recorder initialization
396  */
397 void FRM_Recorder_Init()
398 {
399     /* Do local configuration of additional recorder */
400 
401     /* Setup the additional recorder raw buffer */
402     recBuffCfg.addr = recBuffer;
403     recBuffCfg.size = sizeof(recBuffer);
404     recBuffCfg.basePeriod_ns = 0;    /* Unknown period */
405     recBuffCfg.name = "FXLS8974 3-Axis Accelerometer Data";
406 
407     FMSTR_RecorderCreate(1, &recBuffCfg);
408 }
409 
410 /*!
411  * @brief Main function
412  */
413 
main(void)414 int main(void)
415 {
416     int32_t status;
417     uint8_t whoami = 0;
418     uint8_t regdata;
419     float sensitivity = ACCEL_4G_SENS;
420 
421     ARM_DRIVER_I2C *I2Cdrv = &I2C_S_DRIVER; // Now using the shield.h value!!!
422     GENERIC_DRIVER_GPIO *pGpioDriver = &Driver_GPIO_KSDK;
423     fxls8974_i2c_sensorhandle_t fxls8974Driver;
424 
425     /*! Initialize the MCU hardware. */
426     BOARD_InitPins();
427     BOARD_BootClockRUN();
428     BOARD_SystickEnable();
429     BOARD_InitDebugConsole();
430 
431     /*! Initialize FXLS8974_INT1 pin used by FRDM board */
432     pGpioDriver->pin_init(&FXLS8974_INT1, GPIO_DIRECTION_IN, NULL, &fxls8974_isr_callback, NULL);
433 
434     /*! Initialize RGB LED pin used by FRDM board */
435     pGpioDriver->pin_init(&GREEN_LED, GPIO_DIRECTION_OUT, NULL, NULL, NULL);
436 
437     /*! FreeMASTER communication layer initialization */
438     //init_freemaster_uart();
439     /* Initialize the USB peripheral clock */
440     SystemCoreClockUpdate();
441     CLOCK_EnableUsbfs0Clock(kCLOCK_UsbSrcIrc48M, 48000000U);
442 
443     /* FreeMASTER communication layer initialization */
444     FMSTR_ExampleUsbInit();
445 
446     /*! Initialize the I2C driver. */
447     status = I2Cdrv->Initialize(I2C_S_SIGNAL_EVENT);
448     if (ARM_DRIVER_OK != status)
449     {
450         return -1;
451     }
452 
453     /*! Set the I2C Power mode. */
454     status = I2Cdrv->PowerControl(ARM_POWER_FULL);
455     if (ARM_DRIVER_OK != status)
456     {
457         return -1;
458     }
459 
460     /*! Set the I2C bus speed. */
461     status = I2Cdrv->Control(ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST);
462     if (ARM_DRIVER_OK != status)
463     {
464         return -1;
465     }
466 
467     /*! Initialize FXLS8974 sensor driver. */
468     status = FXLS8974_I2C_Initialize(&fxls8974Driver, &I2C_S_DRIVER, I2C_S_DEVICE_INDEX, FXLS8974_I2C_ADDR,
469                                      &whoami);
470     if (SENSOR_ERROR_NONE != status)
471     {
472         return status;
473     }
474 
475     /*!  Set the task to be executed while waiting for I2C transactions to complete. */
476     FXLS8974_I2C_SetIdleTask(&fxls8974Driver, (registeridlefunction_t)SMC_SetPowerModeVlpr, SMC);
477 
478     /*! Configure the FXLS8974 sensor. */
479     status = FXLS8974_I2C_Configure(&fxls8974Driver, cFxls8974ConfigNormal);
480     if (SENSOR_ERROR_NONE != status)
481     {
482         return status;
483     }
484 
485     /*! FreeMASTER Driver Initialization */
486     FMSTR_Init();
487 
488     /*! FreeMASTER Recorder Initialization */
489     FRM_Recorder_Init();
490 
491     /*! Open FreeMASTER Pipe and get a Pipe handle */
492     FMSTR_HPIPE hpipe = FMSTR_PipeOpen(3, NULL, (FMSTR_ADDR)pipe3_rxb, sizeof(pipe3_rxb), (FMSTR_ADDR)pipe3_txb, sizeof(pipe3_txb),
493                    FMSTR_PIPE_TYPE_ANSI_TERMINAL, "streaming");
494 
495     /*! Initialize trigger flags */
496     registers.toggle = 1;
497     registers.trigger = 0;
498     registers.read_trigger = 0;
499     registers.read_value = 0;
500     registers.readall_trigger = 0;
501     registers.trigger_accel_offnoise=0;
502     registers.trigger_selftest=0;
503     registers.dataready_cntr = 0;
504     registers.selftest[0]=0;
505     registers.selftest[1]=0;
506     registers.selftest[2]=0;
507     registers.timestamp = 0;
508 
509     for(int i = 0; i < FXLS8974_NUM_REGISTERS; i++)
510     {
511     	registers.readall_value[i] = 0;
512     }
513 
514     for (;;) /* Forever loop */
515     {
516 
517         /*! Calling Recorder#0 in execution loop for generic high-speed variables sampling. */
518         FMSTR_Recorder(0);
519 
520     	/*! FreeMASTER host communication polling mode */
521 		FMSTR_Poll();
522 
523         /*! Check for any write register trigger from Host */
524 		if (registers.trigger == 1)
525 		{
526 		    /*! Apply Register Write */
527 			status = apply_register_write(fxls8974Driver, registers.offset, registers.value);
528 		    if (SENSOR_ERROR_NONE != status)
529 		    {
530                 return status;
531 		    }
532 		    registers.trigger = 0;
533             /*! Update drop down menu selection based on updated register write */
534 		    update_dropdown_selection(&registers, FXLS8974_REG_WRITE);
535 		}
536 
537         /*! Check for any read register trigger from Host */
538 		if (registers.read_trigger == 1)
539 		{
540 		    /*! Apply Register Write */
541 			status = apply_register_read(fxls8974Driver, registers.read_offset, &(registers.read_value));
542 		    if (SENSOR_ERROR_NONE != status)
543 		    {
544                 return status;
545 		    }
546 		    registers.read_trigger = 0;
547             /*! Update drop down menu selection based on updated register read */
548 		    update_dropdown_selection(&registers, FXLS8974_REG_READ);
549 		}
550 
551         /*! Check for any read all register trigger from Host */
552 		if (registers.readall_trigger == 1)
553 		{
554 		    /*! Apply Register Write */
555 			status = apply_register_readall(fxls8974Driver);
556 		    if (SENSOR_ERROR_NONE != status)
557 		    {
558                 return status;
559 		    }
560 		    registers.readall_trigger = 0;
561 		    registers.readall_size = FXLS8974_NUM_REGISTERS;
562             /*! Update drop down menu selection based on updated all register read */
563 		    update_dropdown_selection(&registers, FXLS8974_ALLREG_READ);
564 		}
565 
566         /*! Wait for data ready interrupt from the FXLS8974. */
567         if (false == bFxls8974IntFlag)
568         { /* Loop, if new sample is not available. */
569             SMC_SetPowerModeWait(SMC);
570             continue;
571         }
572         else
573         { /*! Clear the data ready flag, it will be set again by the ISR. */
574             bFxls8974IntFlag = false;
575             pGpioDriver->toggle_pin(&GREEN_LED);
576         }
577 
578         /*! Calling Recorder#1 for sampling sensor data when we get sensor data ready interrupt based on ODR. */
579         FMSTR_Recorder(1);
580 
581         /*! Read new raw sensor data from the FXLS8974. */
582         status = FXLS8974_I2C_ReadData(&fxls8974Driver, FXLS8974_ALL_REG_READ, registers.reg_addr);
583         if (ARM_DRIVER_OK != status)
584         {
585             return -1;
586         }
587 
588         /* Update timestamp from Systick framework. */
589         registers.timestamp +=BOARD_SystickElapsedTime_us(&gSystick);
590 
591         /*! Increment data ready counter and check for rollover */
592         registers.dataready_cntr++;
593         if(MAX8BITSTORAGE == registers.dataready_cntr)
594         {
595         	registers.dataready_cntr = 0;
596         }
597 
598         registers.temp = registers.reg_addr[1]+25;
599         registers.sdcd = (registers.reg_addr[0] & 0x10)>>4;
600 
601         /*! Convert the raw sensor data to signed 16-bit container for display to the debug port. */
602         rawData.accel[0] = (int16_t)(((int16_t)(((int16_t)registers.reg_addr[3] << 8) | registers.reg_addr[2])));
603         rawData.accel[1] = (int16_t)(((int16_t)(((int16_t)registers.reg_addr[5] << 8) | registers.reg_addr[4])));
604         rawData.accel[2] = (int16_t)(((int16_t)(((int16_t)registers.reg_addr[7] << 8) | registers.reg_addr[6])));
605 
606         registers.accelraw[0] = rawData.accel[0];
607         registers.accelraw[1] = rawData.accel[1];
608         registers.accelraw[2] = rawData.accel[2];
609 
610         /*! Add data log into Pipe TX */
611         FMSTR_PipePrintf(hpipe, "%d\t%d\t%d\t%d\t%d\n", registers.timestamp, registers.dataready_cntr, registers.accelraw[0], registers.accelraw[1], registers.accelraw[2]);
612 
613         status = FXLS8974_I2C_ReadData(&fxls8974Driver, cFXLS8974_whoami, (uint8_t *)&registers.reg_addr[13]);
614 
615         /*! Check the FS and apply sensitivity */
616         status = FXLS8974_I2C_ReadData(&fxls8974Driver, cFXLS8974_fs_src, &regdata);
617         if ((regdata & FXLS8974_SENS_CONFIG1_FSR_MASK) == 2)
618         {
619             sensitivity = ACCEL_4G_SENS;
620         }
621         else if ((regdata & FXLS8974_SENS_CONFIG1_FSR_MASK) == 4)
622         {
623             sensitivity = ACCEL_8G_SENS;
624         }
625         else if ((regdata & FXLS8974_SENS_CONFIG1_FSR_MASK) == 6)
626         {
627             sensitivity = ACCEL_16G_SENS;
628         }
629         else
630         {
631             sensitivity = ACCEL_2G_SENS;
632         }
633 
634         /*! Convert raw values to Gs */
635         registers.accel[0] = (float) (rawData.accel[0] * sensitivity);
636         registers.accel[1] = (float) (rawData.accel[1] * sensitivity);
637         registers.accel[2] = (float) (rawData.accel[2] * sensitivity);
638 
639         if (prev_toggle != registers.toggle)
640         {
641         	pGpioDriver->toggle_pin(&GREEN_LED);
642         	prev_toggle = registers.toggle;
643         }
644 
645         /*! Call offset and noise calculation function for FXLS8974 */
646         if (registers.trigger_accel_offnoise == 1)
647         {
648         	accel_off_noise(&(rawData), &(offnoise_data), sensitivity);
649             if (offnoise_data.complete_accel_offnoise == 1)
650             {
651             	registers.trigger_accel_offnoise = 0;
652             }
653         }
654 
655         /*! Call self-test function */
656         if (registers.trigger_selftest == 1)
657         {
658         	perform_selftest(fxls8974Driver, &selftest);
659             if (selftest.complete_selftest == 1)
660             {
661             	registers.trigger_selftest = 0;
662 
663                 /*! Re-Configure the FXLS8974 sensor to default configuration */
664                 status = FXLS8974_I2C_Configure(&fxls8974Driver, cFxls8974ConfigNormal);
665                 if (SENSOR_ERROR_NONE != status)
666                 {
667                     return status;
668                 }
669             }
670         }
671 
672     }
673 }
674 
675 
676 /*!
677  * @brief Service register write trigger from Host
678  */
apply_register_write(fxls8974_i2c_sensorhandle_t fxls8974Driver,uint8_t offset,uint8_t value)679 int32_t apply_register_write(fxls8974_i2c_sensorhandle_t fxls8974Driver, uint8_t offset, uint8_t value)
680 {
681     int32_t status;
682 
683 	if (offset > FXLS8974_NUM_REGISTERS)
684 	{
685 		return SENSOR_ERROR_INVALID_PARAM;
686 	}
687 
688 	registerwritelist_t fxls8974_register_write[] = {
689 	     /*! Set register offset with provided value */
690 	     {offset, value, 0},
691 	      __END_WRITE_DATA__};
692 
693     status = FXLS8974_I2C_Configure(&fxls8974Driver, fxls8974_register_write);
694     if (SENSOR_ERROR_NONE != status)
695     {
696         return SENSOR_ERROR_WRITE;
697     }
698 
699     return SENSOR_ERROR_NONE;
700 }
701 
702 /*!
703  * @brief Service register read trigger from Host
704  */
apply_register_read(fxls8974_i2c_sensorhandle_t fxls8974Driver,uint8_t read_offset,uint8_t * read_value)705 int32_t apply_register_read(fxls8974_i2c_sensorhandle_t fxls8974Driver, uint8_t read_offset, uint8_t *read_value)
706 {
707     int32_t status;
708 
709 	if (read_offset > FXLS8974_NUM_REGISTERS)
710 	{
711 		return SENSOR_ERROR_INVALID_PARAM;
712 	}
713 
714 	registerreadlist_t fxls8974_register_read[] = {
715 		     /*! Set register offset with provided value */
716 	        {.readFrom = read_offset, .numBytes = 1}, __END_READ_DATA__};
717 
718     status = FXLS8974_I2C_ReadData(&fxls8974Driver, fxls8974_register_read, read_value);
719     if (SENSOR_ERROR_NONE != status)
720     {
721         return SENSOR_ERROR_WRITE;
722     }
723 
724     return SENSOR_ERROR_NONE;
725 }
726 
727 /*!
728  * @brief Service register read all trigger from Host
729  */
apply_register_readall(fxls8974_i2c_sensorhandle_t fxls8974Driver)730 int32_t apply_register_readall(fxls8974_i2c_sensorhandle_t fxls8974Driver)
731 {
732     int32_t status;
733 
734 	for (int reg_offset = FXLS8974_INT_STATUS; reg_offset <= FXLS8974_SELF_TEST_CONFIG2; reg_offset++)
735 	{
736 		registerreadlist_t fxls8974_register_readall[] = {
737 				 /*! Set register offset with provided value */
738 				{.readFrom = reg_offset, .numBytes = 1}, __END_READ_DATA__};
739 
740 		status = FXLS8974_I2C_ReadData(&fxls8974Driver, fxls8974_register_readall, &(registers.readall_value[reg_offset]));
741 		if (SENSOR_ERROR_NONE != status)
742 		{
743 			return SENSOR_ERROR_READ;
744 		}
745 	}
746 
747     return SENSOR_ERROR_NONE;
748 }
749 
750 /*!
751  * @brief Update drop down selection values based on register write, read or readall.
752  */
update_dropdown_selection(fxls8974_allregs_t * registers,uint8_t caller)753 int32_t update_dropdown_selection(fxls8974_allregs_t *registers, uint8_t caller)
754 {
755 
756     int32_t status = SENSOR_ERROR_NONE;
757 
758 	switch (caller)
759 	{
760 		case FXLS8974_REG_WRITE:
761 
762             /*! Update drop down option based on updated read value */
763 		    if(FXLS8974_SENS_CONFIG1 == registers->offset) //FS Selection
764 		    {
765 			    registers->fs_value = registers->value;
766 		    }
767 		    else if (FXLS8974_SENS_CONFIG2 == registers->offset)
768 		    {
769 			    registers->mods_value = registers->value;
770 		    }
771 		    else if (FXLS8974_SENS_CONFIG3 == registers->offset)
772 		    {
773 			    registers->odr_value = registers->value;
774 		    }
775 			break;
776 		case FXLS8974_REG_READ: //Called from Register Read
777 
778             /*! Update drop down option based on updated read value */
779 		    if(FXLS8974_SENS_CONFIG1 == registers->read_offset) //FS Selection
780 		    {
781 			    registers->fs_value = registers->read_value;
782 		    }
783 		    else if (FXLS8974_SENS_CONFIG2 == registers->read_offset)
784 		    {
785 			    registers->mods_value = registers->read_value;
786 		    }
787 		    else if (FXLS8974_SENS_CONFIG3 == registers->read_offset)
788 		    {
789 			    registers->odr_value = registers->read_value;
790 		    }
791 			break;
792 		case FXLS8974_ALLREG_READ: //Called from Register ReadAll
793 
794             /*! Update drop down option based on updated read values */
795 			registers->fs_value   = registers->reg_addr[FXLS8974_SENS_CONFIG1];
796 			registers->mods_value = registers->reg_addr[FXLS8974_SENS_CONFIG2];
797 			registers->odr_value = registers->reg_addr[FXLS8974_SENS_CONFIG3];
798 			break;
799         default:
800             status = SENSOR_ERROR_INVALID_PARAM;
801             break;
802 	}
803 
804     return status;
805 
806 }
807 
808 /*******************************************************************************
809  * OFFSET NOISE CALCULATION
810  ******************************************************************************/
811 
812 /*!
813  * @brief Initialize Offset-Noise Variables
814  */
offset_noise_init(fxls8974_offset_noise_t * offnoiseptr)815 void offset_noise_init(fxls8974_offset_noise_t *offnoiseptr)
816 {
817 	offnoiseptr->offx = 0.0;
818 	offnoiseptr->offy = 0.0;
819 	offnoiseptr->offz = 0.0;
820 	offnoiseptr->rmsx = 0.0;
821 	offnoiseptr->rmsy = 0.0;
822 	offnoiseptr->rmsz = 0.0;
823 	offnoiseptr->complete_accel_offnoise = 0;
824 }
825 
826 
827 /* Calculate Offset & Noise for FXLS8974 */
accel_off_noise(fxls8974_acceldata_t * rawData,fxls8974_offset_noise_t * offnoiseptr,float sens)828 void accel_off_noise(fxls8974_acceldata_t* rawData, fxls8974_offset_noise_t *offnoiseptr, float sens)
829 {
830 	uint16_t j;
831 	static uint16_t k=0;
832 	static uint16_t cntr=0;
833 	static float stdx=0;
834 	static float stdy=0;
835 	static float stdz=0;
836 	static float xx[N], yy[N], zz[N];
837 	static float xm[N], ym[N], zm[N];
838 	static float xsq[N], ysq[N], zsq[N];
839 	float am[3];
840 	static float sumx=0.0;
841 	static float sumy=0.0;
842 	static float sumz=0.0;
843 
844     /* Init offset noise variables */
845     offset_noise_init(offnoiseptr);
846 
847 	cntr++;
848 
849 	/* Store Accel samples and calculate sum for configured N */
850 	if(cntr < N)
851 	{
852 		 am[0]=rawData->accel[0]*sens;
853 		 am[1]=rawData->accel[1]*sens;
854 		 am[2]=rawData->accel[2]*sens;
855 		 xx[k]=am[0];
856 		 yy[k]=am[1];
857 		 zz[k]=am[2];
858 		 sumx+=am[0];
859 		 sumy+=am[1];
860 		 sumz+=am[2];
861 		 k+=1;
862 		 offnoiseptr->complete_accel_offnoise = 0;
863 	}
864 
865 	/* Measure offset and RMS */
866 	if(cntr == N)
867 	{
868 		/* Measure average */
869 		sumx=sumx/(N-1);
870 		sumy=sumy/(N-1);
871 		sumz=sumz/(N-1);
872 
873 		/* Measure offset */
874 		offnoiseptr->offx=0-sumx;
875 		offnoiseptr->offy=0-sumy;
876 		offnoiseptr->offz=1-sumz;
877 
878 		/* Measure standard deviation */
879 		for(j=0; j<N-1; j++)
880 		{
881 			xm[j]=xx[j]-sumx;
882 			ym[j]=yy[j]-sumy;
883 			zm[j]=zz[j]-sumz;
884 
885 			xsq[j]=(float)pow(xm[j],2);
886 			ysq[j]=(float)pow(ym[j],2);
887 			zsq[j]=(float)pow(zm[j],2);
888 			stdx+=xsq[j];
889 			stdy+=ysq[j];
890 			stdz+=zsq[j];
891 		}
892 		stdx=stdx/(N-2);
893 		stdy=stdy/(N-2);
894 		stdz=stdz/(N-2);
895 
896         /* Measure RMS */
897 		offnoiseptr->rmsx=(float)pow(stdx,0.5);
898 		offnoiseptr->rmsy=(float)pow(stdy,0.5);
899 		offnoiseptr->rmsz=(float)pow(stdz,0.5);
900 
901 		/* Set the completion flag */
902 		offnoiseptr->complete_accel_offnoise = 1;
903 
904 		/* Reset local storage */
905 		cntr = k = 0;
906 		sumx = sumy = sumz = 0;
907 		stdx = stdy = stdz = 0;
908 	}
909 }
910 
911 /*!
912  * @brief Initialize Offset-Noise Variables
913  */
selftest_init(fxls8974_selftest_t * selftest)914 void selftest_init(fxls8974_selftest_t *selftest)
915 {
916 	selftest->x_stoc = 0;
917 	selftest->y_stoc = 0;
918 	selftest->z_stoc = 0;
919 	selftest->x_stof = 0;
920 	selftest->y_stof = 0;
921 	selftest->z_stof = 0;
922 	selftest->complete_selftest = 0;
923 }
924 
925 
perform_selftest(fxls8974_i2c_sensorhandle_t fxls8974Driver,fxls8974_selftest_t * selftest)926 int32_t perform_selftest(fxls8974_i2c_sensorhandle_t fxls8974Driver, fxls8974_selftest_t *selftest)
927 {
928 	int32_t status;
929 
930 	axis=0;
931 
932     /* Initialize self-test parameters */
933 	selftest_init(selftest);
934 
935 	while (axis<6)
936 	{
937 
938 		switch(axis)
939 		{
940 			case 0:status = FXLS8974_I2C_Configure(&fxls8974Driver, cFxls8974STXP);break;
941 			case 1:status = FXLS8974_I2C_Configure(&fxls8974Driver, cFxls8974STXN);break;
942 			case 2:status = FXLS8974_I2C_Configure(&fxls8974Driver, cFxls8974STYP);break;
943 			case 3:status = FXLS8974_I2C_Configure(&fxls8974Driver, cFxls8974STYN);break;
944 			case 4:status = FXLS8974_I2C_Configure(&fxls8974Driver, cFxls8974STZP);break;
945 			case 5:status = FXLS8974_I2C_Configure(&fxls8974Driver, cFxls8974STZN);break;
946 			default:break;
947 		}
948 
949 		if (ARM_DRIVER_OK != status)
950 		{
951 			return status;
952 		}
953 
954 		int counter =0;
955 		for(counter=0;counter<1;counter++)
956 		{
957 
958 			// In ISR Mode we do not need to check Data Ready Register.
959 			// The receipt of interrupt will indicate data is ready.
960 			RAW_DATA data_ = {0x00};
961 			while(false == bFxls8974IntFlag)
962 			{
963 
964 			}
965 
966 			/*! Set device to Standby mode. */
967 			Register_I2C_Write(&I2C_S_DRIVER,&(fxls8974Driver.deviceInfo),FXLS8974_I2C_ADDR, FXLS8974_SENS_CONFIG1,0x00,0x00,0x00);
968 			if (ARM_DRIVER_OK != status)
969 			{
970 				return SENSOR_ERROR_WRITE;
971 			}
972 
973 
974 			bFxls8974IntFlag = false;
975 			//pGpioDriver->toggle_pin(&RED_LED);
976 
977 			/*! Read new raw sensor data from the FXLS8974. */
978 			status = FXLS8974_I2C_ReadData(&fxls8974Driver, cFxls8974OutputNormal, &data_.byte_data[0]);
979 			if (ARM_DRIVER_OK != status)
980 			{ /* Read did not work, so loop. */
981 				continue;
982 			}
983 
984 			/* store the self-test values for each axis & for each polarity*/
985 			switch(axis)
986 			{
987 			case 0: XSTP[counter]= data_.dat.xdata;break;
988 			case 1: XSTN[counter]= data_.dat.xdata;break;
989 			case 2: YSTP[counter]= data_.dat.ydata;break;
990 			case 3: YSTN[counter]= data_.dat.ydata;break;
991 			case 4: ZSTP[counter]= data_.dat.zdata;break;
992 			case 5: ZSTN[counter]= data_.dat.zdata;break;
993 			default:break;
994 			}
995 
996 		}
997 
998 		BOARD_DELAY_ms(1000);
999 		axis++;
1000 	}
1001 
1002 		/* compute self-test output change*/
1003 	    selftest->x_stoc=(XSTP[0]-XSTN[0])/2;
1004 	    selftest->y_stoc=(YSTP[0]-YSTN[0])/2;
1005 	    selftest->z_stoc=(ZSTP[0]-ZSTN[0])/2;
1006 
1007 		/* compute self-test offset*/
1008 	    selftest->x_stof=(XSTP[0]+XSTN[0])/2;
1009 	    selftest->y_stof=(YSTP[0]+YSTN[0])/2;
1010 	    selftest->z_stof=(ZSTP[0]+ZSTN[0])/2;
1011 
1012 	    selftest->complete_selftest = 1;
1013 	    return SENSOR_ERROR_NONE;
1014 }
1015 
1016 
1017