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