FRDMKL25-P3115 - Example project in KDS 3.0.2 using KSDK 2.0

Document created by Tomas Vaverka Employee on Jun 20, 2016Last modified by Tomas Vaverka Employee on Jun 20, 2016
Version 1Show Document
  • View in full screen mode

Hi Everyone,


In this document I would like to present a simple example code I created for the FRDMKL25-P3115 kit using the KDS 3.0.2 and KSDK 2.0. I will not cover the Sensor Toolbox – CE and Intelligent Sensing Framework (ISF) which primarily support this kit. The FreeMASTER tool is used to visualize both the pressure/altitude and temperature data that are read from the MPL3115A2 using an interrupt technique through the I2C interface.


This example illustrates:


1. Initialization of the MKL25Z128 MCU (mainly PORT and I2C modules).

2. I2C data write and read operations.

3. Initialization of the MPL3115A2.

4. Output data reading using an interrupt technique.

5. Conversion of the output values from registers 0x01 – 0x05 to real values in Pascals/meters and °C

6. Visualization of the calculated values in the FreeMASTER tool.


1. As you can see in the FRDMSTBC-P3115 schematic and the image below, with jumpers J7 and J8 in their default position (2-3), the I2C signals are routed to the I2C1 module (PTC1 and PTC2 pins) of the KL25Z MCU. The INT1 output is connected to the PTA5 pin and configured as push-pull active-low output, so the corresponding PTA5 pin configuration is GPIO with an interrupt on falling edge.




The configuration is done in the BOARD_InitPins() function.


void BOARD_InitPins(void)
    CLOCK_EnableClock(kCLOCK_PortC);                                            /* Port C Clock Gate Control: Clock enabled */
    CLOCK_EnableClock(kCLOCK_I2c1);                                             /* I2C1 Clock Gate Control: Clock enabled */
    PORT_SetPinMux(PORTC, PIN1_IDX, kPORT_MuxAlt2);                             /* PORTC1 (pin 56) is configured as I2C1_SCL */
    PORT_SetPinMux(PORTC, PIN2_IDX, kPORT_MuxAlt2);                             /* PORTC2 (pin 57) is configured as I2C1_SDA */

    CLOCK_EnableClock(kCLOCK_PortA);                                            /* Port A Clock Gate Control: Clock enabled */
    PORT_SetPinMux(PORTA, PIN5_IDX, kPORT_MuxAsGpio);                           /* PORTA5 (pin 31) is configured as PTA5 */
    PORT_SetPinInterruptConfig(PORTA, PIN5_IDX, kPORT_InterruptFallingEdge);    /* PTA5 is configured for falling edge interrupts */

    NVIC_EnableIRQ(PORTA_IRQn);                                                 /* Enable PORTA interrupt on NVIC */



2. The 7-bit I2C address of the MPL3115A2 is a fixed value 0x60 (defined in the MPL3115A2.h file) which translates to 0xC0 for a write and 0xC1 for a read. As mentioned before, the SCL line is connected to the PTC1 pin and SDA line to the PTC2 pin. The I2C clock frequency is 100 kHz. The I2C_Init() function is used to enable and configure the I2C1 module.


void I2C_Init(void)
    i2c_master_config_t config = {
    .enableMaster = true,
    .enableStopHold = false,
    .enableHighDrive = false,
    .baudRate_Bps = 100000,
    .glitchFilterWidth = 0

    I2C_MasterInit(I2C1, &config, 24000000U);
    I2C_MasterTransferCreateHandle(I2C1, &p_handle, i2c_master_callback, NULL);



The screenshot below shows the write operation which writes the value 0x39 to the CTRL_REG1 register (0x26).


MPL3115A2 Write 0x39 to the CTRL_REG1 register.JPG


Here is a burst read of 5 bytes from registers 0x01 to 0x05. It also shows how the INT1 pin is automatically deasserted by reading the output registers.


MPL3115A2 Burst read of registers 0x01 - 0x05.JPG



3. At the beginning of the initialization, all MPL3115A2 registers are reset to their default values by setting the RST bit of the CTRL_REG1 register. The DRDY interrupt is enabled and routed to the INT1 pin that is configured to be a push-pull, active-low output. Further, the OSR ratio of 128 is selected and finally the part goes into Active barometer (eventually altimeter) mode.


void MPL3115A2_Init (void)
    I2C_WriteRegister(I2C1, MPL3115A2_I2C_ADDRESS, CTRL_REG1, 0x04);               /* Reset all registers to POR values */

    Pause(0xC62);          // ~1ms delay

    I2C_WriteRegister(I2C1, MPL3115A2_I2C_ADDRESS, PT_DATA_CFG_REG, 0x07);         /* Enable data flags */
    I2C_WriteRegister(I2C1, MPL3115A2_I2C_ADDRESS, CTRL_REG3, 0x00);               /* Push-pull, active low interrupt */
    I2C_WriteRegister(I2C1, MPL3115A2_I2C_ADDRESS, CTRL_REG4, 0x80);               /* Enable DRDY interrupt */
    I2C_WriteRegister(I2C1, MPL3115A2_I2C_ADDRESS, CTRL_REG5, 0x80);               /* DRDY interrupt routed to INT1 - PTA13 */
    I2C_WriteRegister(I2C1, MPL3115A2_I2C_ADDRESS, CTRL_REG1, 0x39);               /* Active barometer mode, OSR = 128 */
    //I2C_WriteRegister(I2C1, MPL3115A2_I2C_ADDRESS, CTRL_REG1, 0xB9);             /* Active altimeter mode, OSR = 128 */



4. In the ISR, only the interrupt flag is cleared and the DataReady variable is set to indicate the arrival of new data.


void PORTA_IRQHandler(void)
    PORT_ClearPinsInterruptFlags(PORTA, 1<<5);                /* Clear the interrupt flag */
    DataReady = 1;



5. In the main loop, the DataReady variable is periodically checked and if it is set, both pressure (eventually altitude) and temperature data are read and then calculated.


if (DataReady)                  /* Is a new set of data ready? */
    DataReady = 0;

    I2C_ReadMultiRegisters(I2C1, MPL3115A2_I2C_ADDRESS, OUT_P_MSB_REG, RawData, 5);                      /* Read data output registers 0x01-0x05 */

    /* Get pressure, the 20-bit measurement in Pascals is comprised of an unsigned integer component and a fractional component.
    The unsigned 18-bit integer component is located in OUT_P_MSB, OUT_P_CSB and bits 7-6 of OUT_P_LSB.
    The fractional component is located in bits 5-4 of OUT_P_LSB. Bits 3-0 of OUT_P_LSB are not used. */

    Pressure = (float) (((RawData[0] << 16) | (RawData[1] << 8) | (RawData[2] & 0xC0)) >> 6) + (float) ((RawData[2] & 0x30) >> 4) * 0.25;

    /* Get temperature, the 12-bit temperature measurement in °C is comprised of a signed integer component and a fractional component.
    The signed 8-bit integer component is located in OUT_T_MSB. The fractional component is located in bits 7-4 of OUT_T_LSB.
    Bits 3-0 of OUT_T_LSB are not used. */

    Temperature = (float) ((short)((RawData[3] << 8) | (RawData[4] & 0xF0)) >> 4) * 0.0625;

    /* Get altitude, the 20-bit measurement in meters is comprised of a signed integer component and a fractional component.
    The signed 16-bit integer component is located in OUT_P_MSB and OUT_P_CSB.
    The fraction component is located in bits 7-4 of OUT_P_LSB. Bits 3-0 of OUT_P_LSB are not used */

    //Altitude = (float) ((short) ((RawData[0] << 8) | RawData[1])) + (float) (RawData[2] >> 4) * 0.0625;



6.  The calculated values can be watched in the Debug perspective or in the FreeMASTER application. To open and run the FreeMASTER project, install the FreeMASTER 2.0 application and FreeMASTER Communication Driver.


KDS Debug perspective.JPG



FreeMASTER vizualization.JPG



Attached you can find the complete source code written in the KDS 3.0.2 including the FreeMASTER project. If there are any questions regarding this simple application, do not hesitate to ask below. Your feedback or suggestions are also welcome.


Best regards,


1 person found this helpful