In comparison with other Xtrinsic accelerometers, the MMA8491Q is turned on at the rising edge on the EN pin and acquires only one sample for each of the three axes. It does not have any interrupt pins, instead there are three push-pull logic outputs which provide tilt detection at 45 degrees as the original target application was tamper detection. However, it is possible to read the 14-bit output values through the I2C port as demonstrated in my example below.
According to the User Manual, both SCL and SDA lines are connected through the 4.7K pull-up resistors to the I2C1 module (PTE1 and PTE0 pins) on the KL25Z128 MCU and the EN pin is connected to the PTA13 pin. The EN input needs to be kept high until a new data is ready (max. 900us) and read. In my code I use the PIT module to wait 1ms before reading the output values. This timer is also used to read the output data periodically at a fixed rate. The timeout period of the PIT is set to 500us. 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
In the PIT interrupt service routine (ISR), there is a variable Counter that is increased by one on every PIT interrupt (500us) and its value is then compared with two preset values. The first preset value EN_HIGH_TIME determines how long the EN pin will remain high to ensure a valid reading of a new set of output data. The second preset value DATA_UPDATE_PERIOD corresponds to the desired output data rate. At the end of the ISR, the PIT interrupt flag is cleared.
staticintCounter = 0;
Counter++;// Each increment represents 500us
GPIOA_PSOR |= 1<<13; // Set EN pin high
caseEN_HIGH_TIME:// 1ms passed
DataReady = 1; // Data is ready
caseDATA_UPDATE_PERIOD:// 100ms passed
Counter = 0; // Clear Counter at the end of the sample period
PIT_TFLG0 |= PIT_TFLG_TIF_MASK; // Clear PIT interrupt flag
In the main loop, the DataReady variable is periodically checked and if it is set, the accelerometer data registers 0x01 - 0x06 are read and then the acceleration in units of g is calculated. Finally the EN pin is set low to reduce the current consumption and the DataReady variable is cleared.
if(DataReady) // Is a new set of data ready?
AccData = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_X_MSB_REG); // [7:0] are 8 MSBs of the 14-bit X-axis sample
AccData = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_X_LSB_REG); // [7:2] are the 6 LSB of 14-bit X-axis sample
AccData = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_Y_MSB_REG); // [7:0] are 8 MSBs of the 14-bit Y-axis sample
AccData = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_Y_LSB_REG); // [7:2] are the 6 LSB of 14-bit Y-axis sample
AccData = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_Z_MSB_REG); // [7:0] are 8 MSBs of the 14-bit Z-axis sample
AccData = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_Z_LSB_REG); // [7:2] are the 6 LSB of 14-bit Z-axis sample