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