I would like to share a simple example code/demo that reads both the altitude and temperature data from the Xtrinsic MPL3115A2 pressure sensor and visualizes them using the FreeMASTER tool via USBDM interface. I have used recently released Xtrinsic MEMS sensors board that features three types of Xtrinsic sensors including the MPL3115A2 and is fully compatible with the Freescale FRDM-KL25Z platform.
According to the User Manual, both interrupt pins of the MPL3115A2 are connected to the PTD3 pin of KL25Z MCU through a 4.7K pull-up resistor as well as both SCL and SDA lines that are connected to the I2C1 module (PTE1 and PTE0 pins) on the KL25Z. The MCU is, therefore, configured as follows:
//I2C1 module initialization
SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK; // Turn on clock to I2C1 module
SIM_SCGC5 |= SIM_SCGC5_PORTE_MASK; // Turn on clock to Port E module
PORTE_PCR1 = PORT_PCR_MUX(6); // PTE1 pin is I2C1 SCL line
PORTE_PCR0 = PORT_PCR_MUX(6); // PTE0 pin is I2C1 SDA line
I2C1_F = 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 PTD3 pin (connected to the INT2 of the MPL3115A2) for falling edge interrupt
SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK; // Turn on clock to Port D module
PORTD_PCR3 |= (0|PORT_PCR_ISF_MASK| // Clear the interrupt flag
PORT_PCR_MUX(0x1)| // PTD3 is configured as GPIO
PORT_PCR_IRQC(0xA)); // PTD3 is configured for falling edge interrupts
//Enable PORTD interrupt on NVIC
NVIC_ICPR |= 1 << ((INT_PORTD - 16)%32);
NVIC_ISER |= 1 << ((INT_PORTD - 16)%32);
In the ISR, only the interrupt flag is cleared and the DataReady variable is set to indicate the arrival of new data.
PORTD_PCR3 |= PORT_PCR_ISF_MASK; // Clear the interrupt flag
DataReady = 1;
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 INT2 pin that is configured to be an open-drain, active-low output. During the initialization of the MPL3115A2, the OSR ratio of 128 is selected and finally the part goes into Active Altimeter mode.
void MPL3115A2_Init (void)
unsigned char reg_val = 0;
I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG1, 0x04); // Reset all registers to POR values
do // Wait for the RST bit to clear
reg_val = I2C_ReadRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG1) & 0x04;
} while (reg_val);
I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, PT_DATA_CFG_REG, 0x07); // Enable data flags
I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG3, 0x11); // Open drain, active low interrupts
I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG4, 0x80); // Enable DRDY interrupt
I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG5, 0x00); // DRDY interrupt routed to INT2 - PTD3
I2C_WriteRegister(MPL3115A2_I2C_ADDRESS, CTRL_REG1, 0xB9); // Active altimeter mode, OSR = 128
In the main loop, the DataReady variable is periodically checked and if it is set, both altitude and temperature data are read and then calculated.
if (DataReady) // Is a new set of data ready?
DataReady = 0;
OUT_P_MSB = I2C_ReadRegister(MPL3115A2_I2C_ADDRESS, OUT_P_MSB_REG); // High byte of integer part of altitude,
OUT_P_CSB = I2C_ReadRegister(MPL3115A2_I2C_ADDRESS, OUT_P_CSB_REG); // Low byte of integer part of altitude
OUT_P_LSB = I2C_ReadRegister(MPL3115A2_I2C_ADDRESS, OUT_P_LSB_REG); // Decimal part of altitude in bits 7-4
OUT_T_MSB = I2C_ReadRegister(MPL3115A2_I2C_ADDRESS, OUT_T_MSB_REG); // Integer part of temperature
OUT_T_LSB = I2C_ReadRegister(MPL3115A2_I2C_ADDRESS, OUT_T_LSB_REG); // Decimal part of temperature in bits 7-4
/* 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) ((OUT_P_MSB << 8) | OUT_P_CSB)) + (float) (OUT_P_LSB >> 4) * 0.0625;
/* 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) ((signed char) OUT_T_MSB) + (float) (OUT_T_LSB >> 4) * 0.0625;
The calculated values can be watched in the "Variables" window on the top right of the Debug perspective or in the FreeMASTER application.
Attached you can find the complete source code written in the CW 10.3 as well as the FreeMASTER project.
If there are any questions regarding this simple application, please feel free to ask below. Your feedback or suggestions are also welcome.