Get started: NXP Sensor Fusion for Kinetis MCUs (Part 1)

Get started: NXP Sensor Fusion for Kinetis MCUs (Part 1)

In “IoT Sensing Software Development Kit,” I introduced the new ISSDK component within the Kinetis SDK. I also mentioned it included NXP Sensor Fusion for Kinetis MCUs Version 7.00. Today, I’ll provide details.

NXP, and Freescale before it, have been providing an open source library for development of sensor fusion applications for a couple of years now. Version 4.22 started that trend. Version 5.00 followed a year later with significant enhancements. Version 6.00 was never published. It added support for precision accelerometer trim and storing of trim parameters into NVM. But about that time, we learned that the CodeWarrior and Processor Expert tools were being phased out for Kinetis MCUs. It was time to retool. That’s where Version 7.00 comes into play. It is based on the V6.00 baseline, but with a LOT of changes:

  1. The CodeWarrior software development tool support is retired
  2. Processor Expert software support is retired
  3. MQX  RTOS support is retired
  4. FreeRTOS support has been added
  5. Support for bare metal projects has been added.  This also dramatically reduces the amount of flash memory you need to store the application.
  6. Because it is now part of the KEX ecosystem, you now get support for:
    • Kinetis Design Studio IDE v3.2
    • IAR Embedded Workbench for ARM version 7.50.1
    • MDK-ARM Microcontroller Development Kit (Keil)® 5.17
    • Makefiles support with GCC revision 4.9-2015-q3-update from ARM Embedded
    • Atollic® TrueSTUDIO® 5.4.0
  7. Precision trim for accelerometers
  8. Storage of all sensor trim values to non-volatile flash memory (via the updated Sensor Fusion Toolbox for Windows)
  9. Ability to power down selected sensors (specifically the gyro) during periods of inactivity
  10. Top level functions have been re-partitioned to make it obscenely easy to integrate sensor fusion capabilities into your code
  11. Hardware facing functions have been streamlined for easy portability to non-Kinetis platforms.

The block diagram below shows how the sensor fusion library fits into your application.  The number of top level functions you need to remember is extremely modest.  Sensor drivers are already provided for NXP sensors, but it’s also easy to write your own if you want to enable some other device.

architecture_cropped

In this solution, we will use the FXOS8700 6-axis magnetometer and accelerometer, FXAS21002 3-axis gyroscope, and the MPL3115 barometric pressure sensors.  Let’s take a look at a bare metal main().  The first code block pulls in headers specific to your hardware:

// KSDK  and ISSDK Headers
#include "fsl_debug_console.h"  // KSDK header file for the debug interface
#include "board.h"              // KSDK header file to define board configuration
#include "pin_mux.h"            // KSDK header file for pin mux initialization functions
#include "clock_config.h"       // KSDK header file for clock configuration
#include "fsl_port.h"           // KSDK header file for Port I/O control
#include "fsl_i2c.h"            // KSDK header file for I2C interfaces
#include "fsl_pit.h"            // KSDK header file for Periodic Interval Timer
#include "Driver_I2C.h"         // CMSIS I2C Driver
#include "Driver_I2C_SDK2.h"    // ISSDK CMSIS I2C Driver
#include "fxas21002.h"          // Gyroscope register and bit-field definitions
#include "mpl3115.h"            // Pressure sensor register and bit-field definitions
#include "fxos8700.h"           // 6-axis accel/mag register and bit-field definitions
#include "fsl_smc.h"

Next we include a number of sensor fusion headers:

#include "sensor_fusion.h"   // Top level magCal and sensor fusion interfaces
#include "control.h"         // Command/Streaming interface - application specific
#include "status.h"          // Status indicator interface - application specific
#include "drivers.h"         // NXP sensor drivers OR customer-supplied drivers
#include "driver_pit.h"      // PIT is used to control main() timing loop

You will need to define a number of global data structures:

SensorFusionGlobals sfg;             ///< This is the primary sensor fusion data structure
ControlSubsystem controlSubsystem;   ///< Used for serial communications
StatusSubsystem statusSubsystem;     ///< Provides visual (usually LED) status indicator
PhysicalSensor sensors[3];           ///< This implementation uses up to 3 sensors

Now let’s take a look at main(). Start by doing some general hardware configuration:

int main(void) // This is a bare-metal implementation of the NXP sensor fusion demo build.
{
    uint16_t i=0;                    // general counter variable
    BOARD_InitPins();                // defined in pin_mux.c, initializes pkg pins
    BOARD_BootClockRUN();            // defined in clock_config.c, initializes clocks
    BOARD_InitDebugConsole();        // defined in board.c, initializes the OpenSDA port

Next, initialize the I2C bus used for sensor communications:

    ARM_DRIVER_I2C* I2Cdrv = &I2C_S_DRIVER_BLOCKING;            // Defined by ISSDK
    I2Cdrv->Initialize(NULL);                                   // Initialize the I2C KSDK driver
    I2Cdrv->Control(ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST); // Configure the I2C bus speed

Now initialize various subsystems associated with sensor fusion:

    initializeControlPort(&controlSubsystem);     // configure pins and ports for the control sub-system
    initializeStatusSubsystem(&statusSubsystem);  // configure pins and ports for the status sub-system
    // Initialize sensor fusion structures
    initSensorFusionGlobals(&sfg, &statusSubsystem, &controlSubsystem); 

Sensors are installed at run time:

    sfg.installSensor(&sfg, &sensors[0], FXOS8700_I2C_ADDR,  1, (void*) I2Cdrv, FXOS8700_Init,  FXOS8700_Read);
    sfg.installSensor(&sfg, &sensors[1], FXAS21002_I2C_ADDR, 1, (void*) I2Cdrv, FXAS21002_Init, FXAS21002_Read);
    sfg.installSensor(&sfg, &sensors[2], MPL3115_I2C_ADDR,   1, (void*) I2Cdrv, MPL3115_Init,   MPL3115_Read);

Start up the fusion engine, hardware timer and initial status:

    sfg.initializeFusionEngine(&sfg);    // This will initialize sensors and magnetic calibration
    pit_init(1000000/FUSION_HZ);         // pitIsrFlag will be set true at FUSION_HZ periodic intervals
    sfg.setStatus(&sfg, NORMAL);         // If we got this far, let's set status state to NORMAL

Now we have our main loop, which is timed via a periodic interval timer:

    while (true)
    {
        if (true == pitIsrFlag) {               // Check whether occur interupt and toggle LED
            sfg.readSensors(&sfg, 1);           // Reads sensors, applies HAL and does averaging
            sfg.conditionSensorReadings(&sfg);  // MagCal is run as part of this
            sfg.runFusion(&sfg);                // Run the actual fusion algorithms
            sfg.loopcounter++;                  // Used to "serialize" mag cal operations
            i=i+1;
            if (i>=4) {                         // Some status codes include a "blink" feature.  This loop
                    i=0;                        // should cycle at least 4X for that to operate correctly.
                    sfg.updateStatus(&sfg);     // This is where pending status updates are made visible
            }
            sfg.queueStatus(&sfg, NORMAL);      // assume NORMAL status for next pass through the loop

            // Send stream data to the Sensor Fusion Toolbox
            sfg.pControlSubsystem->stream(&sfg, sUARTOutputBuffer);      
            pitIsrFlag = false;                 // Reset the flag for the next cycle
        }
    }
}

Even though we’ve used standard C, we’ve used an objected oriented coding style for the top level interface.  Functions that operate on a structure are actually installed as part of that structure, just as in C++.  Status and control subsystems are installed at run time.  This allows you to install your own versions rather than use the NXP defaults.  Sensors to be used by the application are also explicitly installed.  Then we simply start the fusion subsystem and a system timer and drop into a main loop.

I think you will agree that this release makes it easier to see and comprehend the overall application structure than it was with previous libraries. To find more information, go to nxp.com/sensorfusion and kex.nxp.com to download this release and nxp.com/freedom to order development boards. .

Our next posting in the series will look at sensor drivers and a FreeRTOS implementation of the same application shown in bare metal form above.

Michael Stanley “works” on fun sensors and systems topics.

Michael Stanley
Michael Stanley
Mike Stanley develops advanced algorithms and applications for MCUs and sensors, including sensor fusion and sensor data analytics. He is a founding member of the MEMS Industry Group’s Accelerated Innovation Community and a contributor to the IEEE Standard for Sensor Performance Parameter Definitions (IEEE 2700-2014). He is co-author of a chapter on intelligent sensors in “Measurement, Instrumentation, and Sensors Handbook” (volume two), and speaks on sensor topics. When the Arizona temperature drops below 100 degrees, you'll find Mike flying his F450 quadcopter . Follow him @SensorFusion.

Comments are closed.

Buy now