ISSDK  1.7
IoT Sensing Software Development Kit
sensor_fusion.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 sensor_fusion.c
36  \brief The sensor_fusion.c file implements the top level programming interface
37 */
38 
39 /* Including needed modules to compile this module/procedure */
40 #include <stdio.h>
41 #include "sensor_fusion.h"
42 #include "magnetic.h"
43 #include "drivers.h"
44 #include "sensor_drv.h"
45 #include "status.h"
46 #include "control.h"
47 #include "fusion.h"
48 //#include "debug.h"
49 
50 /// Poor man's inheritance for status subsystem setStatus command
51 /// This function is normally involved via the "sfg." global pointer.
53 {
54  sfg->pStatusSubsystem->set(sfg->pStatusSubsystem, status);
55 }
56 
57 /// Poor man's inheritance for status subsystem queueStatus command.
58 /// This function is normally involved via the "sfg." global pointer.
60 {
61  sfg->pStatusSubsystem->queue(sfg->pStatusSubsystem, status);
62 }
63 
64 /// Poor man's inheritance for status subsystem updateStatus command.
65 /// This function is normally involved via the "sfg." global pointer.
67 {
69 }
70 
72 {
74 }
75 
76 /// utility function to insert default values in the top level structure
78  StatusSubsystem *pStatusSubsystem,
79  ControlSubsystem *pControlSubsystem)
80 {
81  sfg->iFlags = // all of the following defines are either 0x0000 or a 1-bit value (2, 4, 8 ...) and are defined in build.h
83  F_USING_MAG |
84  F_USING_GYRO |
87  F_ALL_SENSORS | // refers to all applicable sensor types for the given physical unit
88  F_1DOF_P_BASIC | // 1DOF pressure (altitude) and temperature: (pressure)
89  F_3DOF_G_BASIC | // 3DOF accel tilt: (accel)
90  F_3DOF_B_BASIC | // 3DOF mag eCompass (vehicle): (mag)
91  F_3DOF_Y_BASIC | // 3DOF gyro integration: (gyro)
92  F_6DOF_GB_BASIC | // 6DOF accel and mag eCompass)
93  F_6DOF_GY_KALMAN | // 6DOF accel and gyro (Kalman): (accel + gyro)
94  F_9DOF_GBY_KALMAN ; // 9DOF accel, mag and gyro (Kalman): (accel + mag + gyro)
95 
96  sfg->pControlSubsystem = pControlSubsystem;
97  sfg->pStatusSubsystem = pStatusSubsystem;
98  sfg->loopcounter = 0; // counter incrementing each iteration of sensor fusion (typically 25Hz)
99  sfg->systick_I2C = 0; // systick counter to benchmark I2C reads
100  sfg->systick_Spare = 0; // systick counter for counts spare waiting for timing interrupt
101  sfg->iPerturbation = 0; // no perturbation to be applied
102  sfg->installSensor = installSensor; // function for installing a new sensor into the structures
103  sfg->initializeFusionEngine = initializeFusionEngine; // function for installing a new sensor into the structures
104  sfg->readSensors = readSensors; // function for installing a new sensor into the structures
105  sfg->runFusion = runFusion; // function for installing a new sensor into the structures
106  sfg->applyPerturbation = ApplyPerturbation; // function used for step function testing
107  sfg->conditionSensorReadings = conditionSensorReadings; // function does averaging, HAL adjustments, etc.
108  sfg->clearFIFOs = clearFIFOs; // function to clear FIFO flags sfg->applyPerturbation = ApplyPerturbation; // function used for step function testing
109  sfg->setStatus = setStatus; // function to immediately set status change
110  sfg->queueStatus = queueStatus; // function to queue status change
111  sfg->updateStatus = updateStatus; // function to promote queued status change
112  sfg->testStatus = testStatus; // function for unit testing the status subsystem
113  sfg->pSensors = NULL; // pointer to linked list of physical sensors
114 // put error value into whoAmI as initial value
115 #if F_USING_ACCEL
116  sfg->Accel.iWhoAmI = 0;
117 #endif
118 #if F_USING_MAG
119  sfg->Mag.iWhoAmI = 0;
120 #endif
121 #if F_USING_GYRO
122  sfg->Gyro.iWhoAmI = 0;
123 #endif
124 #if F_USING_PRESSURE
125  sfg->Pressure.iWhoAmI = 0;
126 #endif
127 }
128 /// installSensor is used to instantiate a physical sensor driver into the
129 /// sensor fusion system.
130 /// This function is normally involved via the "sfg." global pointer.
132  SensorFusionGlobals *sfg, ///< top level fusion structure
133  struct PhysicalSensor *pSensor, ///< pointer to structure describing physical sensor
134  uint16_t addr, ///< I2C address for sensor (if applicable)
135  uint16_t schedule, ///< Parameter to control sensor sampling rate
136  void *bus_driver, ///< ISSDK sensor bus driver (usually KSDK I2C bus)
137  registerDeviceInfo_t *busInfo, ///< information required for bus power management
138  initializeSensor_t *initialize, ///< pointer to sensor initialization function
139  readSensor_t *read) ///< pointer to sensor read function
140 {
141  if (sfg && pSensor && bus_driver && initialize && read)
142  {
143  pSensor->bus_driver = bus_driver;
144  pSensor->deviceInfo.deviceInstance = busInfo->deviceInstance;
145  pSensor->deviceInfo.functionParam = busInfo->functionParam;
146  pSensor->deviceInfo.idleFunction = busInfo->idleFunction;
147 
148  pSensor->initialize = initialize; // The initialization function is responsible for putting the sensor
149  // into the proper mode for sensor fusion. It is normally KSDK-based.
150  pSensor->read = read; // The read function is responsible for taking sensor readings and
151  // loading them into the sensor fusion input structures. Also KDSK-based.
152  pSensor->addr = addr; // I2C address if applicable
153  pSensor->schedule = schedule;
154  pSensor->slaveParams.pReadPreprocessFN = NULL; // SPI-specific parameters get overwritten later if used
155  pSensor->slaveParams.pWritePreprocessFN = NULL;
156  pSensor->slaveParams.pTargetSlavePinID = NULL;
157  pSensor->slaveParams.spiCmdLen = 0;
158  pSensor->slaveParams.ssActiveValue = 0;
159  // Now add the new sensor at the head of the linked list
160  pSensor->next = sfg->pSensors;
161  sfg->pSensors = pSensor;
162  return (0);
163  }
164  else
165  {
166  return (1);
167  }
168 }
169 // The initializeSensors function traverses the linked list of physical sensor
170 // types and calls the initialization function for each one.
172 {
173  struct PhysicalSensor *pSensor;
174  int8_t s;
175  int8_t status = 0;
176  for (pSensor = sfg->pSensors; pSensor != NULL; pSensor = pSensor->next)
177  {
178  s = pSensor->initialize(pSensor, sfg);
179  if (status == 0) status = s; // will return 1st error flag, but try all sensors
180  }
181  return (status);
182 }
183 
184 // process<Sensor>Data routines do post processing for HAL and averaging. They
185 // are called from the readSensors() function below.
186 #if F_USING_ACCEL
187 void processAccelData(SensorFusionGlobals *sfg)
188 {
189  int32 iSum[3]; // channel sums
190  int16 i, j; // counters
191  if (sfg->Accel.iFIFOExceeded > 0) {
192  sfg->setStatus(sfg, SOFT_FAULT);
193  }
194 
195  ApplyAccelHAL(&(sfg->Accel)); // This function is board-dependent
196 
197  // calculate the average HAL-corrected measurement
198  for (j = CHX; j <= CHZ; j++) iSum[j] = 0;
199  for (i = 0; i < sfg->Accel.iFIFOCount; i++)
200  for (j = CHX; j <= CHZ; j++) iSum[j] += sfg->Accel.iGsFIFO[i][j];
201  if (sfg->Accel.iFIFOCount > 0)
202  {
203  for (j = CHX; j <= CHZ; j++)
204  {
205  sfg->Accel.iGs[j] = (int16)(iSum[j] / (int32) sfg->Accel.iFIFOCount);
206  sfg->Accel.fGs[j] = (float)sfg->Accel.iGs[j] * sfg->Accel.fgPerCount;
207  }
208  }
209 
210  // apply precision accelerometer calibration (offset V, inverse gain invW and rotation correction R^T)
211  // to map fGs onto fGc (g), iGc (counts)
212  fInvertAccelCal(&(sfg->Accel), &(sfg->AccelCal));
213 
214  // update the precision accelerometer data buffer
215  fUpdateAccelBuffer(&(sfg->AccelCal),
216  &(sfg->AccelBuffer),
217  &(sfg->Accel),
219  return;
220 }
221 #endif
222 #if F_USING_MAG
224 {
225  int32 iSum[3]; // channel sums
226  int16 i, j; // counters
227 
228  // printf("ProcessingMagData()\n");
229  if (sfg->Mag.iFIFOExceeded > 0) {
230  sfg->setStatus(sfg, SOFT_FAULT);
231  }
232 
233  ApplyMagHAL(&(sfg->Mag)); // This function is board-dependent
234 
235  // calculate the average HAL-corrected measurement
236  for (j = CHX; j <= CHZ; j++) iSum[j] = 0;
237  for (i = 0; i < sfg->Mag.iFIFOCount; i++)
238  for (j = CHX; j <= CHZ; j++) iSum[j] += sfg->Mag.iBsFIFO[i][j];
239  if (sfg->Mag.iFIFOCount > 0)
240  {
241  for (j = CHX; j <= CHZ; j++)
242  {
243  sfg->Mag.iBs[j] = (int16)(iSum[j] / (int32) sfg->Mag.iFIFOCount);
244  sfg->Mag.fBs[j] = (float)sfg->Mag.iBs[j] * sfg->Mag.fuTPerCount;
245  }
246  }
247 
248  // remove hard and soft iron terms from fBs (uT) to get calibrated data fBc (uT), iBc (counts) and
249  // update magnetic buffer avoiding a write while a magnetic calibration is in progress.
250  // run one iteration of the time sliced magnetic calibration
251  fInvertMagCal(&(sfg->Mag), &(sfg->MagCal));
252  if (!sfg->MagCal.iMagBufferReadOnly)
253  iUpdateMagBuffer(&(sfg->MagBuffer), &(sfg->Mag), sfg->loopcounter);
254  fRunMagCalibration(&(sfg->MagCal), &(sfg->MagBuffer), &(sfg->Mag),
255  sfg->loopcounter);
256 
257  return;
258 }
259 #endif
260 #if F_USING_GYRO
261 void processGyroData(SensorFusionGlobals *sfg)
262 {
263  int32 iSum[3]; // channel sums
264  int16 i, j; // counters
265  if (sfg->Gyro.iFIFOExceeded > 0) {
266  sfg->setStatus(sfg, SOFT_FAULT);
267  }
268 
269  ApplyGyroHAL(&(sfg->Gyro)); // This function is board-dependent
270 
271  // calculate the average HAL-corrected measurement. This is used for offset
272  // initialization, display purposes and in the 3-axis gyro-only algorithm.
273  // The Kalman filters both do the full incremental rotation integration
274  // right in the filters themselves.
275  for (j = CHX; j <= CHZ; j++) iSum[j] = 0;
276  for (i = 0; i < sfg->Gyro.iFIFOCount; i++)
277  for (j = CHX; j <= CHZ; j++)
278  iSum[j] += sfg->Gyro.iYsFIFO[i][j];
279  if (sfg->Gyro.iFIFOCount > 0)
280  {
281  for (j = CHX; j <= CHZ; j++)
282  {
283  sfg->Gyro.iYs[j] = (int16)(iSum[j] / (int32) sfg->Gyro.iFIFOCount);
284  sfg->Gyro.fYs[j] = (float)sfg->Gyro.iYs[j] * sfg->Gyro.fDegPerSecPerCount;
285  }
286  }
287  return;
288 }
289 #endif
290 /// readSensors traverses the linked list of physical sensors, calling the
291 /// individual read functions one by one.
292 /// This function is normally involved via the "sfg." global pointer.
293 int8_t readSensors(
294  SensorFusionGlobals *sfg, ///< pointer to global sensor fusion data structure
295  uint16_t read_loop_counter ///< current loop counter (used for multirate processing)
296 )
297 {
298  struct PhysicalSensor *pSensor;
299  int8_t s;
300  int8_t status = 0;
301  float remainder;
302 
303  pSensor = sfg->pSensors;
304 
305  for (pSensor = sfg->pSensors; pSensor != NULL; pSensor = pSensor->next)
306  { if (pSensor->isInitialized) {
307  remainder = fmod(read_loop_counter, pSensor->schedule);
308  if (remainder==0) {
309  s = pSensor->read(pSensor, sfg);
310  if (status == 0) status = s; // will return 1st error flag, but try all sensors
311  }
312  }
313  }
314  if (status==SENSOR_ERROR_INIT) sfg->setStatus(sfg, HARD_FAULT); // Never returns
315  return (status);
316 }
317 /// conditionSensorReadings() transforms raw software FIFO readings into forms that
318 /// can be consumed by the sensor fusion engine. This include sample averaging
319 /// and (in the case of the gyro) integrations, applying hardware abstraction layers,
320 /// and calibration functions.
321 /// This function is normally involved via the "sfg." global pointer.
323 #if F_USING_ACCEL
324  if (sfg->Accel.isEnabled) processAccelData(sfg);
325 #endif
326 
327 #if F_USING_MAG
328  if (sfg->Mag.isEnabled) processMagData(sfg);
329 #endif
330 
331 #if F_USING_GYRO
332  if (sfg->Gyro.isEnabled) processGyroData(sfg);
333 #endif
334  return;
335 }
336 
337 void zeroArray(StatusSubsystem *pStatus, void* data, uint16_t size, uint16_t numElements, uint8_t check) {
338  uint16_t i;
339  uint8_t *d8;
340  uint16_t *d16;
341  uint32_t *d32;
342  switch(size) {
343  case 8:
344  d8 = data;
345  for (i=0; i<numElements; i++) d8[i]=0;
346  break;
347  case 16:
348  d16 = data;
349  for (i=0; i<numElements; i++) d16[i]=0;
350  break;
351  case 32:
352  d32 = data;
353  for (i=0; i<numElements; i++) d32[i]=0;
354  break;
355  default:
356  pStatus->set(pStatus, HARD_FAULT);
357  }
358  if (check) {
359  switch(size) {
360  case 8:
361  d8 = data;
362  for (i=0; i<numElements; i++)
363  if (d8[i]!=0) pStatus->set(pStatus, HARD_FAULT);
364  break;
365  case 16:
366  d16 = data;
367  for (i=0; i<numElements; i++)
368  if (d16[i]!=0) pStatus->set(pStatus, HARD_FAULT);
369  break;
370  case 32:
371  d32 = data;
372  for (i=0; i<numElements; i++)
373  if (d32[i]!=0) pStatus->set(pStatus, HARD_FAULT);
374  break;
375  }
376  return;
377  }
378 }
379 /// Function to clear FIFO at the end of each fusion computation
381  // We only clear FIFOs if the sensors are enabled. This allows us
382  // to continue to use these values when we've shut higher power consumption
383  // sensors down during periods of no activity.
384 #if F_USING_ACCEL
385  sfg->Accel.iFIFOCount=0;
386  sfg->Accel.iFIFOExceeded = false;
387 #endif
388 #if F_USING_MAG
389  sfg->Mag.iFIFOCount=0;
390  sfg->Mag.iFIFOExceeded = false;
391 #endif
392 #if F_USING_GYRO
393  sfg->Gyro.iFIFOCount=0;
394  sfg->Gyro.iFIFOExceeded = false;
395 #endif
396 }
397 
398 /// runFusion the top level call that actually runs the sensor fusion.
399 /// This is a utility function which manages the various defines in build.h.
400 /// You should feel free to drop down a level and implement only those portions
401 /// of fFuseSensors() that your application needs.
402 /// This function is normally involved via the "sfg." global pointer.
404 {
405  struct SV_1DOF_P_BASIC *pSV_1DOF_P_BASIC;
406  struct SV_3DOF_G_BASIC *pSV_3DOF_G_BASIC;
407  struct SV_3DOF_B_BASIC *pSV_3DOF_B_BASIC;
408  struct SV_3DOF_Y_BASIC *pSV_3DOF_Y_BASIC;
409  struct SV_6DOF_GB_BASIC *pSV_6DOF_GB_BASIC;
410  struct SV_6DOF_GY_KALMAN *pSV_6DOF_GY_KALMAN;
411  struct SV_9DOF_GBY_KALMAN *pSV_9DOF_GBY_KALMAN;
412  struct AccelSensor *pAccel;
413  struct MagSensor *pMag;
414  struct GyroSensor *pGyro;
415  struct PressureSensor *pPressure;
416  struct MagCalibration *pMagCal;
417 #if F_1DOF_P_BASIC
418  pSV_1DOF_P_BASIC = &(sfg->SV_1DOF_P_BASIC);
419 #else
420  pSV_1DOF_P_BASIC = NULL;
421 #endif
422 #if F_3DOF_G_BASIC
423  pSV_3DOF_G_BASIC = &(sfg->SV_3DOF_G_BASIC) ;
424 #else
425  pSV_3DOF_G_BASIC = NULL;
426 #endif
427 #if F_3DOF_B_BASIC
428  pSV_3DOF_B_BASIC = &(sfg->SV_3DOF_B_BASIC);
429 #else
430  pSV_3DOF_B_BASIC = NULL;
431 #endif
432 #if F_3DOF_Y_BASIC
433  pSV_3DOF_Y_BASIC = &(sfg->SV_3DOF_Y_BASIC);
434 #else
435  pSV_3DOF_Y_BASIC = NULL;
436 #endif
437 #if F_6DOF_GB_BASIC
438  pSV_6DOF_GB_BASIC = &(sfg->SV_6DOF_GB_BASIC);
439 #else
440  pSV_6DOF_GB_BASIC = NULL;
441 #endif
442 #if F_6DOF_GY_KALMAN
443  pSV_6DOF_GY_KALMAN = &(sfg->SV_6DOF_GY_KALMAN);
444 #else
445  pSV_6DOF_GY_KALMAN = NULL;
446 #endif
447 #if F_9DOF_GBY_KALMAN
448  pSV_9DOF_GBY_KALMAN = &(sfg->SV_9DOF_GBY_KALMAN);
449 #else
450  pSV_9DOF_GBY_KALMAN = NULL;
451 #endif
452 #if F_USING_ACCEL
453  pAccel = &(sfg->Accel);
454 #else
455  pAccel = NULL;
456 #endif
457 #if F_USING_MAG
458  pMag = &(sfg->Mag);
459  pMagCal = &(sfg->MagCal);
460 #else
461  pMag = NULL;
462  pMagCal = NULL;
463 #endif
464 #if F_USING_GYRO
465  pGyro = &(sfg->Gyro);
466 #else
467  pGyro = NULL;
468 #endif
469 #if F_USING_PRESSURE
470  pPressure = &(sfg->Pressure);
471 #else
472  pPressure = NULL;
473 #endif
474 
475  // conditionSensorReadings(sfg); must be called prior to this function
476  // fuse the sensor data
477  fFuseSensors(pSV_1DOF_P_BASIC, pSV_3DOF_G_BASIC,
478  pSV_3DOF_B_BASIC, pSV_3DOF_Y_BASIC,
479  pSV_6DOF_GB_BASIC, pSV_6DOF_GY_KALMAN,
480  pSV_9DOF_GBY_KALMAN, pAccel, pMag, pGyro,
481  pPressure, pMagCal);
482  clearFIFOs(sfg);
483 }
484 
485 /// This function is responsible for initializing the system prior to starting
486 /// the main fusion loop.
487 /// This function is normally involved via the "sfg." global pointer.
489 {
490  int16_t status = 0;
491  struct ControlSubsystem *pComm;
492  pComm = sfg->pControlSubsystem;
493 
494  // configure the 24 bit downwards ARM systick timer and wait 50ms=CORE_SYSTICK_HZ / 20 clock ticks
495  // to avoid a race condition between Kinetis and the sensors after power on.
497  // wait 50ms to avoid a race condition with sensors at power on
499 
500  sfg->setStatus(sfg, INITIALIZING);
501  status = initializeSensors(sfg);
502  if (status!=SENSOR_ERROR_NONE) { // fault condition found
503  sfg->setStatus(sfg, HARD_FAULT); // Never returns
504  }
505 
506  // recall: typedef enum quaternion {Q3, Q3M, Q3G, Q6MA, Q6AG, Q9} quaternion_type;
507  // Set the default quaternion to the most sophisticated supported by this build
515 
516  // initialize the sensor fusion algorithms
517  fInitializeFusion(sfg);
518 
519  // reset the loop counter to zero for first iteration
520  sfg->loopcounter = 0;
521 
522  // initialize the magnetic calibration and magnetometer data buffer
523 #if F_USING_MAG
525 #endif
526 
527  // initialize the precision accelerometer calibration and accelerometer data buffer
528 #if F_USING_ACCEL
529  fInitializeAccelCalibration(&sfg->AccelCal, &sfg->AccelBuffer, &sfg->pControlSubsystem->AccelCalPacketOn );
530 #endif
531  sfg->setStatus(sfg, NORMAL);
532 
533  clearFIFOs(sfg);
534 }
535 
536 void conditionSample(int16_t sample[3])
537 {
538  // This function should be called for every 16 bit sample read from sensor hardware.
539  // It is responsible for making sure that we never pass on the value of -32768.
540  // That value cannot be properly negated using 16-bit twos complement math.
541  // The ability to be later negated is required for general compatibility
542  // with possible HAL (Hardware abstraction logic) which is run later in
543  // the processing pipeline.
544  if (sample[CHX] == -32768) sample[CHX]++;
545  if (sample[CHY] == -32768) sample[CHY]++;
546  if (sample[CHZ] == -32768) sample[CHZ]++;
547 }
548 void addToFifo(union FifoSensor *sensor, uint16_t maxFifoSize, int16_t sample[3])
549 {
550  // Note that FifoSensor is a union of GyroSensor, MagSensor and AccelSensor.
551  // All contain FIFO structures in the same location. We use the Accel
552  // structure to index here.
553 
554  // example usage: if (status==SENSOR_ERROR_NONE) addToFifo((FifoSensor*) &(sfg->Mag), MAG_FIFO_SIZE, sample);
555  uint8_t fifoCount = sensor->Accel.iFIFOCount;
556  if (fifoCount < maxFifoSize) {
557  // we have room for the new sample
558  sensor->Accel.iGsFIFO[fifoCount][CHX] = sample[CHX];
559  sensor->Accel.iGsFIFO[fifoCount][CHY] = sample[CHY];
560  sensor->Accel.iGsFIFO[fifoCount][CHZ] = sample[CHZ];
561  sensor->Accel.iFIFOCount += 1;
562  sensor->Accel.iFIFOExceeded = 0;
563  } else {
564  //there is no room for a new sample
565  sensor->Accel.iFIFOExceeded += 1;
566  }
567 }
568 
void initSensorFusionGlobals(SensorFusionGlobals *sfg, StatusSubsystem *pStatusSubsystem, ControlSubsystem *pControlSubsystem)
utility function to insert default values in the top level structure
Definition: sensor_fusion.c:77
The sensor_drv.h file contains sensor state and error definitions.
void ARM_systick_enable(void)
Initializing sensors and algorithms.
int8_t iMagBufferReadOnly
flag to denote that the magnetic measurement buffer is temporarily read only
Definition: magnetic.h:109
Quaternion derived from full 9-axis sensor fusion.
Definition: sensor_fusion.h:80
volatile quaternion_type QuaternionPacketType
quaternion type transmitted over UART
Definition: control.h:70
uint16_t iFIFOExceeded
Number of samples received in excess of software FIFO size.
void fInitializeFusion(SensorFusionGlobals *sfg)
Definition: fusion.c:59
int8_t() readSensor_t(struct PhysicalSensor *sensor, struct SensorFusionGlobals *sfg)
fpSpiWritePreprocessFn_t pWritePreprocessFN
#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
registeridlefunction_t idleFunction
Definition: sensor_drv.h:130
updateStatus_t * testStatus
increment to next enumerated status value (test only)
#define F_ALL_SENSORS
refers to all applicable sensor types for the given physical unit
ssSetStatus_t * set
change status immediately - no delay
Definition: status.h:54
void iUpdateMagBuffer(struct MagBuffer *pthisMagBuffer, struct MagSensor *pthisMag, int32 loopcounter)
Definition: magnetic.c:117
struct PhysicalSensor * next
pointer to next sensor in this linked list
int16_t iBs[3]
averaged uncalibrated measurement (counts)
void setStatus(SensorFusionGlobals *sfg, fusion_status_t status)
Definition: sensor_fusion.c:52
SensorFusionGlobals sfg
void fInitializeAccelCalibration(struct AccelCalibration *pthisAccelCal, struct AccelBuffer *pthisAccelBuffer, volatile int8 *AccelCalPacketOn)
Initialize the accelerometer calibration functions.
volatile uint8_t iPerturbation
test perturbation to be applied
Lower level sensor fusion interface.
struct MagBuffer MagBuffer
mag cal constellation points
void fUpdateAccelBuffer(struct AccelCalibration *pthisAccelCal, struct AccelBuffer *pthisAccelBuffer, struct AccelSensor *pthisAccel, volatile int8 *AccelCalPacketOn)
Update the buffer used to store samples used for accelerometer calibration.
int32_t systick_Spare
systick counter for counts spare waiting for timing interrupt
Quaternion derived from 3-axis mag only (auto compass algorithm)
Definition: sensor_fusion.h:76
uint8_t data[FXLS8962_DATA_SIZE]
void ApplyGyroHAL(struct GyroSensor *Gyro)
Apply the gyroscope Hardware Abstraction Layer.
#define F_USING_PRESSURE
nominally 0x0008 if altimeter is to be used, 0x0000 otherwise
uint16_t schedule
Parameter to control sensor sampling rate.
int32_t status
uint16_t iFIFOExceeded
Number of samples received in excess of software FIFO size.
void fInvertAccelCal(struct AccelSensor *pthisAccel, struct AccelCalibration *pthisAccelCal)
function maps the accelerometer data fGs (g) onto precision calibrated and de-rotated data fGc (g)...
installSensor_t * installSensor
function for installing a new sensor into t
void zeroArray(StatusSubsystem *pStatus, void *data, uint16_t size, uint16_t numElements, uint8_t check)
float fuTPerCount
uT per count
This is the 3DOF basic magnetometer state vector structure/.
void processMagData(SensorFusionGlobals *sfg)
void fRunMagCalibration(struct MagCalibration *pthisMagCal, struct MagBuffer *pthisMagBuffer, struct MagSensor *pthisMag, int32 loopcounter)
Definition: magnetic.c:339
Quaternion derived from 3-axis gyro only (rotation)
Definition: sensor_fusion.h:77
uint8_t iWhoAmI
sensor whoami
updateStatus_t * updateStatus
status=next status
void testStatus(SensorFusionGlobals *sfg)
Definition: sensor_fusion.c:71
Quaternion derived from 3-axis accel + 3 axis mag (eCompass)
Definition: sensor_fusion.h:78
The AccelSensor structure stores raw and processed measurements for a 3-axis accelerometer.
int32_t int32
Definition: sensor_fusion.h:67
void initializeFusionEngine(SensorFusionGlobals *sfg)
he ControlSubsystem encapsulates command and data streaming functions.
Definition: control.h:68
Quaternion derived from 3-axis accel + 3-axis gyro (gaming)
Definition: sensor_fusion.h:79
SV_9DOF_GBY_KALMAN is the 9DOF Kalman filter accelerometer, magnetometer and gyroscope state vector s...
void clearFIFOs(SensorFusionGlobals *sfg)
Function to clear FIFO at the end of each fusion computation.
The MagSensor structure stores raw and processed measurements for a 3-axis magnetic sensor...
bool isEnabled
true if the device is sampling
StatusSubsystem() provides an object-like interface for communicating status to the user...
Definition: status.h:48
The top level fusion structure.
quaternion_type DefaultQuaternionPacketType
default quaternion transmitted at power on
Definition: control.h:69
struct PhysicalSensor * pSensors
a linked list of physical sensors
int8_t() initializeSensor_t(struct PhysicalSensor *sensor, struct SensorFusionGlobals *sfg)
void fInitializeMagCalibration(struct MagCalibration *pthisMagCal, struct MagBuffer *pthisMagBuffer)
Definition: magnetic.c:50
The SV_1DOF_P_BASIC structure contains state information for a pressure sensor/altimeter.
Recoverable FAULT = something went wrong, but we can keep going.
#define F_1DOF_P_BASIC
1DOF pressure (altitude) and temperature algorithm selector - 0x0100 to include, 0x0000 otherwise ...
initializeSensor_t * initialize
pointer to function to initialize sensor using the supplied drivers
float fBs[3]
averaged un-calibrated measurement (uT)
ssUpdateStatus_t * update
make pending status active/visible
Definition: status.h:56
#define F_9DOF_GBY_KALMAN
9DOF accel, mag and gyro algorithm selector - 0x4000 to include, 0x0000 otherwise ...
applyPerturbation_t * applyPerturbation
apply step function for testing purposes
SV_6DOF_GY_KALMAN is the 6DOF Kalman filter accelerometer and gyroscope state vector structure...
struct AccelSensor Accel
int8_t readSensors(SensorFusionGlobals *sfg, uint16_t read_loop_counter)
struct MagSensor Mag
magnetometer storage
initializeFusionEngine_t * initializeFusionEngine
set sensor fusion structures to initial values
int16_t iBsFIFO[MAG_FIFO_SIZE][3]
FIFO measurements (counts)
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 F_6DOF_GY_KALMAN
6DOF accel and gyro (Kalman) algorithm selector - 0x2000 to include, 0x0000 otherwise ...
uint8_t iFIFOCount
number of measurements read from FIFO
setStatus_t * setStatus
change status indicator immediately
The sensor_fusion.h file implements the top level programming interface.
void runFusion(SensorFusionGlobals *sfg)
The FifoSensor union allows us to use common pointers for Accel, Mag & Gyro logical sensor structures...
SV_3DOF_Y_BASIC structure is the 3DOF basic gyroscope state vector structure.
#define F_3DOF_G_BASIC
3DOF accel tilt (accel) algorithm selector - 0x0200 to include, 0x0000 otherwise
#define CHZ
Used to access Z-channel entries in various data data structures.
Definition: sensor_fusion.h:88
void queueStatus(SensorFusionGlobals *sfg, fusion_status_t status)
Definition: sensor_fusion.c:59
uint16_t isInitialized
Bitfields to indicate sensor is active (use SensorBitFields from build.h)
spiSlaveSpecificParams_t slaveParams
SPI specific parameters. Not used for I2C.
int16_t iGsFIFO[ACCEL_FIFO_SIZE][3]
FIFO measurements (counts)
int8_t installSensor(SensorFusionGlobals *sfg, struct PhysicalSensor *pSensor, uint16_t addr, uint16_t schedule, void *bus_driver, registerDeviceInfo_t *busInfo, initializeSensor_t *initialize, readSensor_t *read)
Lower level magnetic calibration interface.
registerDeviceInfo_t deviceInfo
I2C device context.
Provides function prototypes for driver level interfaces.
ssSetStatus_t * queue
queue status change for next regular interval
Definition: status.h:55
#define F_USING_TEMPERATURE
nominally 0x0010 if temp sensor is to be used, 0x0000 otherwise
clearFIFOs_t * clearFIFOs
clear sensor FIFOs
struct StatusSubsystem * pStatusSubsystem
ssUpdateStatus_t * test
unit test which simply increments to next state
Definition: status.h:57
uint8_t iFIFOCount
number of measurements read from FIFO
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:86
uint32_t iFlags
a bit-field of sensors and algorithms used
void ApplyMagHAL(struct MagSensor *Mag)
Apply the magnetometer Hardware Abstraction Layer.
runFusion_t * runFusion
run the fusion routines
void conditionSample(int16_t sample[3])
conditionSample ensures that we never encounter the maximum negative two&#39;s complement value for a 16-...
Non-recoverable FAULT = something went very wrong.
Application-specific status subsystem.
Magnetic Calibration Structure.
Definition: magnetic.h:81
uint32_t size
void fInvertMagCal(struct MagSensor *pthisMag, struct MagCalibration *pthisMagCal)
Definition: magnetic.c:311
void conditionSensorReadings(SensorFusionGlobals *sfg)
struct MagCalibration MagCal
mag cal storage
void updateStatus(SensorFusionGlobals *sfg)
Definition: sensor_fusion.c:66
int32_t systick_I2C
systick counter to benchmark I2C reads
Quaternion derived from 3-axis accel (tilt)
Definition: sensor_fusion.h:75
#define F_3DOF_Y_BASIC
3DOF gyro integration algorithm selector - 0x0800 to include, 0x0000 otherwise
#define F_6DOF_GB_BASIC
6DOF accel and mag eCompass algorithm selector - 0x1000 to include, 0x0000 otherwise ...
readSensors_t * readSensors
read all physical sensors
conditionSensorReadings_t * conditionSensorReadings
preprocessing step for sensor fusion
Defines control sub-system.
struct ControlSubsystem * pControlSubsystem
void ApplyAccelHAL(struct AccelSensor *Accel)
Apply the accelerometer Hardware Abstraction Layer.
readSensor_t * read
pointer to function to read sensor using the supplied drivers
#define F_USING_ACCEL
nominally 0x0001 if an accelerometer is to be used, 0x0000 otherwise
fusion_status_t
Application-specific serial communications system.
void ARM_systick_delay_ms(uint32 iSystemCoreClock, uint32 delay_ms)
int16_t int16
Definition: sensor_fusion.h:66
SV_6DOF_GB_BASIC is the 6DOF basic accelerometer and magnetometer state vector structure.
This structure defines the device specific info required by register I/O.
Definition: sensor_drv.h:128
Operation is Nominal.
#define F_3DOF_B_BASIC
3DOF mag eCompass (vehicle/mag) algorithm selector - 0x0400 to include, 0x0000 otherwise ...
setStatus_t * queueStatus
queue status change for next regular interval
This is the 3DOF basic accelerometer state vector structure.
#define CORE_SYSTICK_HZ
core and systick clock rate (Hz)
Definition: frdm_k64f.h:172
An instance of PhysicalSensor structure type should be allocated for each physical sensors (combo dev...
#define F_USING_MAG
Definition: magnetic.h:47
int32_t loopcounter
counter incrementing each iteration of sensor fusion (typically 25Hz)
volatile int8_t AccelCalPacketOn
variable used to coordinate accelerometer calibration
Definition: control.h:75
The GyroSensor structure stores raw and processed measurements for a 3-axis gyroscope.
void fFuseSensors(struct SV_1DOF_P_BASIC *pthisSV_1DOF_P_BASIC, struct SV_3DOF_G_BASIC *pthisSV_3DOF_G_BASIC, struct SV_3DOF_B_BASIC *pthisSV_3DOF_B_BASIC, struct SV_3DOF_Y_BASIC *pthisSV_3DOF_Y_BASIC, struct SV_6DOF_GB_BASIC *pthisSV_6DOF_GB_BASIC, struct SV_6DOF_GY_KALMAN *pthisSV_6DOF_GY_KALMAN, struct SV_9DOF_GBY_KALMAN *pthisSV_9DOF_GBY_KALMAN, struct AccelSensor *pthisAccel, struct MagSensor *pthisMag, struct GyroSensor *pthisGyro, struct PressureSensor *pthisPressure, struct MagCalibration *pthisMagCal)
Definition: fusion.c:94
applyPerturbation_t ApplyPerturbation
ApplyPerturbation is a reverse unit-step test function.
fpSpiReadPreprocessFn_t pReadPreprocessFN
int8_t initializeSensors(SensorFusionGlobals *sfg)
The PressureSensor structure stores raw and processed measurements for an altimeter.