MMA8491Q - Acceleration data streaming using the PIT on the Kinetis KL25Z MCU

Document created by Tomas Vaverka Employee on Aug 15, 2013Last modified by Tomas Vaverka Employee on Nov 27, 2013
Version 5Show Document
  • View in full screen mode

Hi Everyone,

 

I would like to present another example code/demo that reads acceleration data from the Xtrinsic MMA8491Q digital accelerometer 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 MMA8491Q and is fully compatible with the Freescale FRDM-KL25Z platform.

 

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:

 

void MCU_Init(void)

{

            //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 PTA13 pin as an output to drive the EN input of the MMA8491Q

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

       PORTA_PCR13 = PORT_PCR_MUX(1);           // PTA13 is configured as GPIO

       GPIOA_PCOR |= 1<<13;                     // Set PTA13 pin low

       GPIOA_PDDR |= 1<<13;                     // PTA13 pin is an output

  

            //PIT initialization

       SIM_SCGC6 |= SIM_SCGC6_PIT_MASK;         // Turn on clock to to the PIT module

       PIT_LDVAL0 = 5240;                       // Timeout period = 500us

       PIT_MCR = PIT_MCR_FRZ_MASK;              // Enable clock for PIT, freeze PIT in debug mode

       PIT_TCTRL0 = PIT_TCTRL_TIE_MASK |        // Enable PIT interrupt

                   PIT_TCTRL_TEN_MASK;          // and PIT

  

            //Enable PIT interrupt on NVIC   

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

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

}

 

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.

 

void PIT_IRQHandler()

{

       static int Counter = 0;

       Counter++;                                   // Each increment represents 500us

       switch (Counter)

    {

            case 1:

            GPIOA_PSOR |= 1<<13;                 // Set EN pin high

                     break;

            case EN_HIGH_TIME:                        // 1ms passed

            DataReady = 1;                       // Data is ready

                     break;

            case DATA_UPDATE_PERIOD:                  // 100ms passed

            Counter = 0;                         // Clear Counter at the end of the sample period

                     break;

            default:

                     break;

    }

       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[0] = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_X_MSB_REG);         // [7:0] are 8 MSBs of the 14-bit X-axis sample

     AccData[1] = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_X_LSB_REG);         // [7:2] are the 6 LSB of 14-bit X-axis sample

     AccData[2] = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_Y_MSB_REG);         // [7:0] are 8 MSBs of the 14-bit Y-axis sample

     AccData[3] = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_Y_LSB_REG);         // [7:2] are the 6 LSB of 14-bit Y-axis sample

     AccData[4] = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_Z_MSB_REG);         // [7:0] are 8 MSBs of the 14-bit Z-axis sample

     AccData[5] = I2C_ReadRegister(MMA8491Q_I2C_ADDRESS, OUT_Z_LSB_REG);         // [7:2] are the 6 LSB of 14-bit Z-axis sample

 

     Xout_14_bit = ((short) (AccData[0]<<8 | AccData[1])) >> 2;           // Compute 14-bit X-axis output value

     Yout_14_bit = ((short) (AccData[2]<<8 | AccData[3])) >> 2;           // Compute 14-bit Y-axis output value

     Zout_14_bit = ((short) (AccData[4]<<8 | AccData[5])) >> 2;           // Compute 14-bit Z-axis output value

                  

     Xout_g = ((float) Xout_14_bit) / SENSITIVITY;          // Compute X-axis output value in g's

     Yout_g = ((float) Yout_14_bit) / SENSITIVITY;          // Compute Y-axis output value in g's

     Zout_g = ((float) Zout_14_bit) / SENSITIVITY;          // Compute Z-axis output value in g's

                                       

     GPIOA_PCOR |= 1<<13;       // Set EN pin low

     DataReady = 0;                                                                                                                                

}                   

  

The calculated values can be watched in the "Variables" window on the top right of the Debug perspective or in the FreeMASTER application.

 

MMA8491Q_Acceleration reading.JPG

 

MMA8491Q_FreeMASTER_Acceleration reading.JPG

 

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, do not hesitate to ask below. Your feedback or suggestions are also welcome.

 

Regards,

Tomas

Outcomes