MPL3115A2 - Bare metal example project

Document created by Tomas Vaverka Employee on Jun 30, 2014Last modified by Tomas Vaverka Employee on Jul 1, 2014
Version 2Show Document
  • View in full screen mode

Hi Everyone,


To complete the collection of simple bare-metal examples for the Xtrinsic sensors on the FRDM-FXS-MULTI(-B) sensor expansion board, I would like to share here another example code/demo I have created for the MPL3115A2 pressure sensor.

This example illustrates:

1. Initialization of the MKL25Z128 MCU (mainly I2C and PORT 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 and °C.

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


1. As you can see in the FRDM-FXS-MULTI(-B)/FRDM-KL25Z schematics and the image below, I2C signals are routed to the I2C1 module (PTC1 and PTC2 pins) of the KL25Z MCU and the INT1 output (INT_PED) is connected to the PTA13 pin (make sure that pins 2-3 of J5 on the sensor board are connected together using a jumper). The INT1 output of the MPL3115A2 is configured as a push-pull active-low output, so the corresponding PTA13 pin configuration is GPIO with an interrupt on falling edge.




The MCU is, therefore, configured as follows.


void MCU_Init(void)


     //I2C1 module initialization

     SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;        // Turn on clock to I2C1 module

     SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;       // Turn on clock to Port C module

     PORTC_PCR1 |= PORT_PCR_MUX(0x2);         // PTC1 pin is I2C1 SCL line

     PORTC_PCR2 |= PORT_PCR_MUX(0x2);         // PTC2 pin is I2C1 SDA line

     I2C1_F  |= I2C_F_ICR(0x14);              // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us

     I2C1_C1 |= I2C_C1_IICEN_MASK;            // Enable I2C1 module


         //Configure the PTA13 pin (connected to the INT1 of the MPL3115A2) for falling edge interrupts

     SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;       // Turn on clock to Port A module

     PORTA_PCR13 |= (0|PORT_PCR_ISF_MASK|     // Clear the interrupt flag

                       PORT_PCR_MUX(0x1)|     // PTA5 is configured as GPIO

                       PORT_PCR_IRQC(0xA));   // PTA5 is configured for falling edge interrupts


        //Enable PORTA interrupt on NVIC

     NVIC_ICPR |= 1 << ((INT_PORTA - 16)%32);

     NVIC_ISER |= 1 << ((INT_PORTA - 16)%32);


2. The 7-bit I2C address of the MPL3115A2 is fixed value 0x60 which translates to 0xC0 for a write and 0xC1 for a read. As shown above, the SCL line is connected to the PTC1 pin and SDA line to the PTC2 pin. The I2C clock frequency is 125 kHz.


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


I2C Write.JPG.jpg


And here is the single byte read from the WHO_AM_I register (0x0C). As you can see, it returns the correct device ID 0xC4.

I2C Read.JPG.jpg

Multiple bytes of data can be read from sequential registers after each MPL3115A2 acknowledgment (AK) is received until a no acknowledge (NAK) occurs from the KL25Z followed by a stop condition (SP) signaling an end of transmission. A burst read of 5 bytes from registers 0x01 to 0x05 is shown below. It also shows how the INT1 pin is automatically deasserted by reading the output registers.

Burst Read.JPG.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(MPL3115A2_I2C_ADDRESS, CTRL_REG1, 0x04);          // Reset all registers to POR values


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


     I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, PT_DATA_CFG_REG, 0x07);    // Enable data flags

     I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG3, 0x00);          // Push-pull, active low interrupt

     I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG4, 0x80);          // Enable DRDY interrupt

     I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG5, 0x80);          // DRDY interrupt routed to INT1 - PTA13

     I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG1, 0x39);          // Active barometer mode, OSR = 128     

        //I2C_WriteRegister(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()


     PORTA_PCR13 |= PORT_PCR_ISF_MASK;          // 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(MPL3115A2_I2C_ADDRESS, OUT_P_MSB_REG, 5, RawData);          // 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 RawData[0], RawData[1] and bits 7-6 of RawData[2].

     The fractional component is located in bits 5-4 of RawData[2]. Bits 3-0 of RawData[2] 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 RawData[3].

     The fractional component is located in bits 7-4 of RawData[4]. 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 RawData[0] and RawData[1].

     The fraction component is located in bits 7-4 of RawData[2]. Bits 3-0 of RawData[2] 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 "Variables" window on the top right of the Debug perspective or in the FreeMASTER application. To open and run the FreeMASTER project, install the FreeMASTER 1.4 application and FreeMASTER Communication Driver.

CW Variables.JPG.jpg

FreeMASTER Variables.JPG.jpg

Attached you can find the complete source code written in the CW for MCU's v10.5 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.




2 people found this helpful