ISSDK  1.7
IoT Sensing Software Development Kit
driver_FXAS21002.c
Go to the documentation of this file.
1 /*
2  * The Clear BSD License
3  * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
4  * Copyright 2016-2017 NXP
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without modification,
8  * are permitted (subject to the limitations in the disclaimer below) provided
9  * that the following conditions are met:
10  *
11  * o Redistributions of source code must retain the above copyright notice, this list
12  * of conditions and the following disclaimer.
13  *
14  * o Redistributions in binary form must reproduce the above copyright notice, this
15  * list of conditions and the following disclaimer in the documentation and/or
16  * other materials provided with the distribution.
17  *
18  * o Neither the name of the copyright holder nor the names of its
19  * contributors may be used to endorse or promote products derived from this
20  * software without specific prior written permission.
21  *
22  * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
27  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 /*! \file driver_FXAS21002.c
36  \brief Provides init() and read() functions for the FXAS21002 gyroscope
37 */
38 
39 #include "board.h" // generated by Kinetis Expert. Long term - merge sensor_board.h into this file
40 #include "sensor_fusion.h" // Sensor fusion structures and types
41 #include "sensor_drv.h"
42 #include "sensor_io_i2c.h" // Low level IS-SDK prototype driver
43 #include "drivers.h" // Device specific drivers supplied by NXP (can be replaced with user drivers)
44 #include "fxas21002.h"
45 
46 // Includes support for pre-production FXAS21000 registers and constants which are not supported via IS-SDK
47 #define FXAS21000_STATUS 0x00
48 #define FXAS21000_F_STATUS 0x08
49 #define FXAS21000_F_SETUP 0x09
50 #define FXAS21000_WHO_AM_I 0x0C
51 #define FXAS21000_CTRL_REG0 0x0D
52 #define FXAS21000_CTRL_REG1 0x13
53 #define FXAS21000_CTRL_REG2 0x14
54 #define FXAS21000_WHO_AM_I_VALUE 0xD1 // engineering and production
55 #define FXAS21000_COUNTSPERDEGPERSEC 20 // 1600dps range
56 #define FXAS21002_COUNTSPERDEGPERSEC 16 // for 2000dps=32000 counts
57 
58 #define FXAS21002_GYRO_FIFO_SIZE 32 ///< FXAX21000, FXAS21002 have 32 element FIFO
59 
60 #if F_USING_GYRO
61 
62 // Command definition to read the WHO_AM_I value.
63 const registerreadlist_t FXAS21002_WHO_AM_I_READ[] =
64 {
65  { .readFrom = FXAS21002_WHO_AM_I, .numBytes = 1 }, __END_READ_DATA__
66 };
67 
68 // Command definition to read the number of entries in the gyro status register.
69 const registerreadlist_t FXAS21002_F_STATUS_READ[] =
70 {
71  { .readFrom = FXAS21002_STATUS, .numBytes = 1 }, __END_READ_DATA__
72 };
73 
74 // Command definition to read the number of entries in the accel FIFO.
75 registerreadlist_t FXAS21002_DATA_READ[] =
76 {
77  { .readFrom = FXAS21002_OUT_X_MSB, .numBytes = 1 }, __END_READ_DATA__
78 };
79 
80 // Each entry in a RegisterWriteList is composed of: register address, value to write, bit-mask to apply to write (0 enables)
81 const registerwritelist_t FXAS21000_Initialization[] =
82 {
83  // write 0000 0000 = 0x00 to CTRL_REG1 to place FXOS21000 in Standby
84  // [7]: ZR_cond=0
85  // [6]: RST=0
86  // [5]: ST=0 self test disabled
87  // [4-2]: DR[2-0]=000 for 200Hz ODR
88  // [1]: Active=0 for Standby mode
89  // [0]: Ready=0 but irrelevant since Active bit over-rides
90  { FXAS21000_CTRL_REG1, 0x00, 0x00 }, // write 0100 0000 = 0x40 to F_SETUP to enable FIFO in continuous mode
91 
92  // [7-6]: F_MODE[1-0]=01 for FIFO continuous mode
93  // [5-0]: F_WMRK[5-0]=000000 for no FIFO watermark
94  { FXAS21000_F_SETUP, 0x40, 0x00 },
95 
96  // write 0000 0000 = 0x00 to CTRL_REG0 to configure range
97  // [7-6]: unused=00
98  // [5]: SPIW=0 4 wire SPI (irrelevant)
99  // [4-3]: SEL[1-0]=00 for HPF cutoff but disabled in HPF_EN
100  // [2]: HPF_EN=0 disable HPF
101  // [1-0]: FS[1-0]=00 for 1600dps
102  { FXAS21000_CTRL_REG0, 0x00, 0x00 },
103 
104  // write 000X XX10 to CTRL_REG1 to configure ODR and enter Active mode
105  // [7]: Reserved=0
106  // [6]: RST=0 for no reset
107  // [5]: ST=0 self test disabled
108  // [4-2]: DR[2-0]=111 also for 12.5Hz ODR giving 0x1E
109  // [4-2]: DR[2-0]=110 for 12.5Hz ODR giving 0x1A
110  // [4-2]: DR[2-0]=101 for 25Hz ODR giving 0x16
111  // [4-2]: DR[2-0]=100 for 50Hz ODR giving 0x12
112  // [4-2]: DR[2-0]=011 for 100Hz ODR giving 0x0E
113  // [4-2]: DR[2-0]=010 for 200Hz ODR giving 0x0A
114  // [4-2]: DR[2-0]=001 for 400Hz ODR giving 0x06
115  // [4-2]: DR[2-0]=000 for 800Hz ODR giving 0x02
116  // [1]: Active=1 for Active mode
117  // [0]: Ready=0 but irrelevant since Active bit over-rides
118 #if (GYRO_ODR_HZ <= 1) // select 1.5625Hz ODR
119  { FXAS21000_CTRL_REG1, 0x1E, 0x00 },
120 #elif (GYRO_ODR_HZ <= 3) // select 3.125Hz ODR
121  { FXAS21000_CTRL_REG1, 0x1A, 0x00 },
122 #elif (GYRO_ODR_HZ <= 6) // select 6.25Hz ODR
123  { FXAS21000_CTRL_REG1, 0x16, 0x00 },
124 #elif (GYRO_ODR_HZ <= 12) // select 12.5Hz ODR
125  { FXAS21000_CTRL_REG1, 0x12, 0x00 },
126 #elif (GYRO_ODR_HZ <= 25) // select 25.0Hz ODR
127  { FXAS21000_CTRL_REG1, 0x0E, 0x00 },
128 #elif (GYRO_ODR_HZ <= 50) // select 50.0Hz ODR
129  { FXAS21000_CTRL_REG1, 0x0A, 0x00 },
130 #elif (GYRO_ODR_HZ <= 100) // select 100.0Hz ODR
131  { FXAS21000_CTRL_REG1, 0x06, 0x00 },
132 #else // select 200Hz ODR
133  { FXAS21000_CTRL_REG1, 0x02, 0x00 },
134 #endif
136 };
137 
138 // Each entry in a RegisterWriteList is composed of: register address, value to write, bit-mask to apply to write (0 enables)
139 const registerwritelist_t FXAS21002_Initialization[] =
140 {
141  // write 0000 0000 = 0x00 to CTRL_REG1 to place FXOS21000 in Standby
142  // [7]: ZR_cond=0
143  // [6]: RST=0
144  // [5]: ST=0 self test disabled
145  // [4-2]: DR[2-0]=000 for 200Hz ODR
146  // [1]: Active=0 for Standby mode
147  // [0]: Ready=0 but irrelevant since Active bit over-rides
148  { FXAS21002_CTRL_REG1, 0x00, 0x00 },
149 
150  // [7-6]: F_MODE[1-0]=01 for FIFO continuous mode
151  // [5-0]: F_WMRK[5-0]=000000 for no FIFO watermark
152  { FXAS21002_F_SETUP, 0x40, 0x00 },
153 
154  // write 0000 0000 = 0x00 to CTRL_REG0 to configure range and LPF
155  // [7-6]: BW[1-0]=00 for least aggressive LPF (0.32 * ODR cutoff for all ODR ie 64Hz cutoff at 200Hz ODR)
156  // [5]: SPIW=0 4 wire SPI (irrelevant)
157  // [4-3]: SEL[1-0]=00 for HPF cutoff but disabled in HPF_EN
158  // [2]: HPF_EN=0 to disable HPF
159  // [1-0]: FS[1-0]=00 for 2000dps
160  { FXAS21002_CTRL_REG0, 0x00, 0x00 },
161 
162  // write 0000 1000 = 0x08 to CTRL_REG3 to set FIFO address wraparound on read
163  // [7-4]: Reserved=0000
164  // [3]: WRAPTOONE=1 to permit burst FIFO read with address wrapround to OUT_X_MSB
165  // [2]: EXTCTRLEN=0 for default INT2 configuration as output
166  // [1]: Reserved=0
167  // [0]: FS_DOUBLE=0 for normal 2000dps range
168  { FXAS21002_CTRL_REG3, 0x08, 0x00 },
169 
170  // write 000X XX10 to CTRL_REG1 to configure ODR and enter Active mode
171  // [7]: Reserved=0
172  // [6]: RST=0 for no reset
173  // [5]: ST=0 self test disabled
174  // [4-2]: DR[2-0]=111 also for 12.5Hz ODR giving 0x1E
175  // [4-2]: DR[2-0]=110 for 12.5Hz ODR giving 0x1A
176  // [4-2]: DR[2-0]=101 for 25Hz ODR giving 0x16
177  // [4-2]: DR[2-0]=100 for 50Hz ODR giving 0x12
178  // [4-2]: DR[2-0]=011 for 100Hz ODR giving 0x0E
179  // [4-2]: DR[2-0]=010 for 200Hz ODR giving 0x0A
180  // [4-2]: DR[2-0]=001 for 400Hz ODR giving 0x06
181  // [4-2]: DR[2-0]=000 for 800Hz ODR giving 0x02
182  // [1]: Active=1 for Active mode
183  // [0]: Ready=0 but irrelevant since Active bit over-rides
184  // These values are different than the FXAS21000 values
185 #if (GYRO_ODR_HZ <= 12) // select 12.5Hz ODR
186  { FXAS21002_CTRL_REG1, 0x1A, 0x00 },
187 #elif (GYRO_ODR_HZ <= 25) // select 25Hz ODR
188  { FXAS21002_CTRL_REG1, 0x16, 0x00 },
189 #elif (GYRO_ODR_HZ <= 50) // select 50Hz ODR
190  { FXAS21002_CTRL_REG1, 0x12, 0x00 },
191 #elif (GYRO_ODR_HZ <= 100) // select 100Hz ODR
192  { FXAS21002_CTRL_REG1, 0x0E, 0x00 },
193 #elif (GYRO_ODR_HZ <= 200) // select 200Hz ODR
194  { FXAS21002_CTRL_REG1, 0x0A, 0x00 },
195 #elif (GYRO_ODR_HZ <= 400) // select 400Hz ODR
196  { FXAS21002_CTRL_REG1, 0x06, 0x00 },
197 #else // select 800Hz ODR
198  { FXAS21002_CTRL_REG1, 0x02, 0x00 },
199 #endif
201 };
202 
203 // All sensor drivers and initialization functions have the same prototype
204 // sensor = pointer to linked list element used by the sensor fusion subsystem to specify required sensors
205 
206 // sfg = pointer to top level (generally global) data structure for sensor fusion
207 int8_t FXAS21002_Init(struct PhysicalSensor *sensor, SensorFusionGlobals *sfg)
208 {
209 
210  int32_t status;
211  uint8_t reg;
212 
213  status = Register_I2C_Read(sensor->bus_driver, &sensor->deviceInfo, sensor->addr, FXAS21002_WHO_AM_I, 1, &reg);
214  if (status==SENSOR_ERROR_NONE) {
215  sfg->Gyro.iWhoAmI = reg;
216  switch (reg) {
220  default:
221  // whoAmI will retain default value of zero
222  return SENSOR_ERROR_INIT; // return with error
223  }
224  } else {
225  return status; // return with error
226  }
227 
228  // configure FXAS21000 or FXAS21002 depending on WHOAMI value read
229  switch (sfg->Gyro.iWhoAmI) {
231  // Configure and start the FXAS21000 sensor. This does multiple register writes
232  // (see FXAS21009_Initialization definition above)
233  status = Sensor_I2C_Write(sensor->bus_driver, &sensor->deviceInfo, sensor->addr, FXAS21000_Initialization );
234  sfg->Gyro.iCountsPerDegPerSec = FXAS21000_COUNTSPERDEGPERSEC;
235  sfg->Gyro.fDegPerSecPerCount = 1.0F / FXAS21000_COUNTSPERDEGPERSEC;
236  break;
239  status = Sensor_I2C_Write(sensor->bus_driver, &sensor->deviceInfo, sensor->addr, FXAS21002_Initialization );
240  sfg->Gyro.iCountsPerDegPerSec = FXAS21002_COUNTSPERDEGPERSEC;
241  sfg->Gyro.fDegPerSecPerCount = 1.0F / FXAS21002_COUNTSPERDEGPERSEC;
242  break;
243  }
244  sfg->Gyro.iFIFOCount=0;
245  sensor->isInitialized = F_USING_GYRO;
246  sfg->Gyro.isEnabled = true;
247  return (status);
248 }
249 
250 // read FXAS21002 gyro over I2C
251 int8_t FXAS21002_Read(struct PhysicalSensor *sensor, SensorFusionGlobals *sfg)
252 {
253  uint8_t I2C_Buffer[6 * FXAS21002_GYRO_FIFO_SIZE]; // I2C read buffer
254  int8_t j; // scratch
255  uint8_t sensor_fifo_count = 1;
256  int32_t status;
257  int16_t sample[3];
258 
259  if(sensor->isInitialized != F_USING_GYRO)
260  {
261  return SENSOR_ERROR_INIT;
262  }
263 
264  // read the F_STATUS register (mapped to STATUS) and extract number of measurements available (lower 6 bits)
265  status = Sensor_I2C_Read(sensor->bus_driver, &sensor->deviceInfo, sensor->addr, FXAS21002_F_STATUS_READ, I2C_Buffer );
266  if (status==SENSOR_ERROR_NONE) {
267 #ifdef SIMULATOR_MODE
268  sensor_fifo_count = 1;
269 #else
270  sensor_fifo_count = I2C_Buffer[0] & FXAS21002_F_STATUS_F_CNT_MASK ;
271 #endif
272  // return if there are no measurements in the FIFO.
273  // this will only occur when the FAST_LOOP_HZ equals or exceeds GYRO_ODR_HZ
274  if (sensor_fifo_count == 0) return(SENSOR_ERROR_READ);
275  } else {
276  return(status);
277  }
278 
279  // at this point there must be at least one measurement in the FIFO available to read.
280  // handle the FXAS21000 and FXAS21002 differently because only FXAS21002 supports WRAPTOONE feature.
281  if (sfg->Gyro.iWhoAmI == FXAS21002_WHO_AM_I_WHOAMI_OLD_VALUE)
282  {
283  // read six sequential gyro output bytes
284  FXAS21002_DATA_READ[0].readFrom = FXAS21002_OUT_X_MSB;
285  FXAS21002_DATA_READ[0].numBytes = 6;
286 
287  // for FXAS21000, perform sequential 6 byte reads
288  for (j = 0; j < sensor_fifo_count; j++)
289  {
290  // read one set of measurements totalling 6 bytes
291  status = Sensor_I2C_Read(sensor->bus_driver, &sensor->deviceInfo, sensor->addr, FXAS21002_DATA_READ, I2C_Buffer );
292 
293  if (status==SENSOR_ERROR_NONE) {
294  // place the measurements read into the gyroscope buffer structure
295  sample[CHX] = (I2C_Buffer[0] << 8) | I2C_Buffer[1];
296  sample[CHY] = (I2C_Buffer[2] << 8) | I2C_Buffer[3];
297  sample[CHZ] = (I2C_Buffer[4] << 8) | I2C_Buffer[5];
298  conditionSample(sample); // truncate negative values to -32767
299  addToFifo((union FifoSensor*) &(sfg->Gyro), GYRO_FIFO_SIZE, sample);
300  }
301  }
302  } // end of FXAS21000 FIFO read
303  else
304  {
305  // for FXAS21002, clear the FIFO in one using WRAPTOONE feature
306  FXAS21002_DATA_READ[0].readFrom = FXAS21002_OUT_X_MSB;
307  FXAS21002_DATA_READ[0].numBytes = 6 * sensor_fifo_count;
308  status = Sensor_I2C_Read(sensor->bus_driver, &sensor->deviceInfo, sensor->addr, FXAS21002_DATA_READ, I2C_Buffer );
309 
310  if (status==SENSOR_ERROR_NONE) {
311  for (j = 0; j < sensor_fifo_count; j++) {
312  // place the measurements read into the gyroscope buffer structure
313  sample[CHX] = (I2C_Buffer[6*j + 0] << 8) | I2C_Buffer[6*j + 1];
314  sample[CHY] = (I2C_Buffer[6*j + 2] << 8) | I2C_Buffer[6*j + 3];
315  sample[CHZ] = (I2C_Buffer[6*j + 4] << 8) | I2C_Buffer[6*j + 5];
316  conditionSample(sample); // truncate negative values to -32767
317  addToFifo((union FifoSensor*) &(sfg->Gyro), GYRO_FIFO_SIZE, sample);
318  }
319  }
320  } // end of optimized FXAS21002 FIFO read
321 
322  return status;
323 }
324 
325 
326 // Each entry in a RegisterWriteList is composed of: register address, value to write, bit-mask to apply to write (0 enables)
327 const registerwritelist_t FXAS21002_IDLE[] =
328 {
329  // Reset to Standby
330  { FXAS21000_CTRL_REG1, 0x00, 0x00 },
332 };
333 
334 // FXAS21002_Idle places the gyro into READY mode (wakeup time = 1/ODR+5ms)
335 int8_t FXAS21002_Idle(struct PhysicalSensor *sensor, SensorFusionGlobals *sfg)
336 {
337  int32_t status;
338  if(sensor->isInitialized == F_USING_GYRO) {
339  status = Sensor_I2C_Write(sensor->bus_driver, &sensor->deviceInfo, sensor->addr, FXAS21002_IDLE );
340  sensor->isInitialized = 0;
341  sfg->Gyro.isEnabled = false;
342  } else {
343  return SENSOR_ERROR_INIT;
344  }
345  return status;
346 }
347 #endif
The sensor_drv.h file contains sensor state and error definitions.
#define __END_WRITE_DATA__
Definition: sensor_drv.h:71
#define F_USING_GYRO
nominally 0x0004 if a gyro is to be used, 0x0000 otherwise
void * bus_driver
should be of type (ARM_DRIVER_I2C* for I2C-based sensors, ARM_DRIVER_SPI* for SPI) ...
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:87
int8_t FXAS21002_Read(struct PhysicalSensor *sensor, SensorFusionGlobals *sfg)
SensorFusionGlobals sfg
int32_t status
#define FXAS21000_COUNTSPERDEGPERSEC
#define FXAS21002_F_STATUS_F_CNT_MASK
Definition: fxas21002.h:257
int32_t Sensor_I2C_Read(ARM_DRIVER_I2C *pCommDrv, registerDeviceInfo_t *devInfo, uint16_t slaveAddress, const registerreadlist_t *pReadList, uint8_t *pOutBuffer)
Read register data from a sensor.
int8_t FXAS21002_Idle(struct PhysicalSensor *sensor, SensorFusionGlobals *sfg)
#define FXAS21000_CTRL_REG0
The fxas21002.h contains the fxas21002 sensor register definitions and its bit mask.
#define FXAS21002_GYRO_FIFO_SIZE
FXAX21000, FXAS21002 have 32 element FIFO.
#define __END_READ_DATA__
Definition: sensor_drv.h:77
The top level fusion structure.
#define GYRO_FIFO_SIZE
FXAX21000, FXAS21002 have 32 element FIFO.
#define FXAS21002_COUNTSPERDEGPERSEC
int8_t FXAS21002_Init(struct PhysicalSensor *sensor, SensorFusionGlobals *sfg)
uint16_t addr
I2C address if applicable.
void addToFifo(union FifoSensor *sensor, uint16_t maxFifoSize, int16_t sample[3])
addToFifo is called from within sensor driver read functions
#define FXAS21002_WHO_AM_I_WHOAMI_OLD_VALUE
Definition: fxas21002.h:426
The sensor_fusion.h file implements the top level programming interface.
The FifoSensor union allows us to use common pointers for Accel, Mag & Gyro logical sensor structures...
#define CHZ
Used to access Z-channel entries in various data data structures.
Definition: sensor_fusion.h:88
uint16_t isInitialized
Bitfields to indicate sensor is active (use SensorBitFields from build.h)
registerDeviceInfo_t deviceInfo
I2C device context.
Provides function prototypes for driver level interfaces.
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:86
#define FXAS21002_WHO_AM_I_WHOAMI_PROD_VALUE
Definition: fxas21002.h:428
void conditionSample(int16_t sample[3])
conditionSample ensures that we never encounter the maximum negative two&#39;s complement value for a 16-...
#define FXAS21000_CTRL_REG1
typedef int32_t(DATA_FORMAT_Append_t))(void *pData
The interface function to append the data on the formated stream.
int32_t Register_I2C_Read(ARM_DRIVER_I2C *pCommDrv, registerDeviceInfo_t *devInfo, uint16_t slaveAddress, uint8_t offset, uint8_t length, uint8_t *pOutBuffer)
The interface function to read a sensor register.
#define FXAS21000_F_SETUP
This structure defines the Write command List.
Definition: sensor_drv.h:94
This structure defines the Read command List.
Definition: sensor_drv.h:104
#define FXAS21000_WHO_AM_I_VALUE
#define FXAS21002_WHO_AM_I_WHOAMI_PRE_VALUE
Definition: fxas21002.h:427
An instance of PhysicalSensor structure type should be allocated for each physical sensors (combo dev...
The sensor_io_i2c.h file declares low-level interface functions for reading and writing sensor regist...
int32_t Sensor_I2C_Write(ARM_DRIVER_I2C *pCommDrv, registerDeviceInfo_t *devInfo, uint16_t slaveAddress, const registerwritelist_t *pRegWriteList)
Write register data to a sensor.
Definition: sensor_io_i2c.c:97