MMA8451Q - Bare metal example project

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MMA8451Q - Bare metal example project

No ratings

MMA8451Q - Bare metal example project

Hi Everyone,

As I am frequently asked for a simple bare metal example code for the Xtrinsic MMA8451Q digital accelerometer, I would like to share here one of my examples I have created for this part while working with the Freescale FRDM-KL25Z platform.

This example illustrates:

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

2. Initialization of the accelerometer to achieve the highest resolution.

3. Simple offset calibration based on the AN4069.

4. Output data reading using an interrupt technique.

5. Conversion of the output values from registers 0x01 – 0x06 to real acceleration values in g’s.

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

1. According to the schematic, the INT1 output of the MMA8451Q is connected to the PTA14 pin of the KL25Z MCU and both SCL and SDA lines are connected to the I2C0 module (PTE24 and PTE25 pins). The MCU is, therefore, configured as follows:

void MCU_Init(void)

{

     //I2C0 module initialization

     SIM_SCGC4 |= SIM_SCGC4_I2C0_MASK;        // Turn on clock to I2C0 module

     SIM_SCGC5 |= SIM_SCGC5_PORTE_MASK;       // Turn on clock to Port E module

     PORTE_PCR24 = PORT_PCR_MUX(5);           // PTE24 pin is I2C0 SCL line

     PORTE_PCR25 = PORT_PCR_MUX(5);           // PTE25 pin is I2C0 SDA line

     I2C0_F  = 0x14;                          // SDA hold time = 2.125us, SCL start hold time = 4.25us, SCL stop hold time = 5.125us *

     I2C0_C1 = I2C_C1_IICEN_MASK;             // Enable I2C0 module

 

        //Configure the PTA14 pin (connected to the INT1 of the MMA8451Q) for falling edge interrupts

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

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

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

                       PORT_PCR_IRQC(0xA));   // PTA14 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. At the beginning of the initialization, all accelerometer registers are reset to their default values by setting the RST bit of the CTRL_REG2 register. The dynamic range is set to ±2g and to achieve the highest resolution, the LNOISE bit is set and the lowest ODR (1.56Hz) and the High Resolution mode are selected (more details in AN4075).

void Accelerometer_Init (void)

{

     unsigned char reg_val = 0;

 

     I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG2, 0x40);           // Reset all registers to POR values

         do            // Wait for the RST bit to clear

     {

        reg_val = I2C_ReadRegister(MMA845x_I2C_ADDRESS, CTRL_REG2) & 0x40;

     }  while (reg_val);

 

     I2C_WriteRegister(MMA845x_I2C_ADDRESS, XYZ_DATA_CFG_REG, 0x00);    // +/-2g range -> 1g = 16384/4 = 4096 counts

     I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG2, 0x02);           // High Resolution mode

     I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG1, 0x3D);           // ODR = 1.56Hz, Reduced noise, Active mode  

}

3. A simple offset calibration method is implemented according to the AN4069. At the end of the calibration routine, the DRDY interrupt is enabled and routed to the INT1 interrupt pin that is configured to be a push-pull, active-low output.

void Calibrate (void)

{

     unsigned char reg_val = 0;

 

         while (!reg_val)           // Wait for a first set of data         

     {

        reg_val = I2C_ReadRegister(MMA845x_I2C_ADDRESS, STATUS_REG) & 0x08;

     }

        

     I2C_ReadMultiRegisters(MMA845x_I2C_ADDRESS, OUT_X_MSB_REG, 6, AccData);           // Read data output registers 0x01-0x06

                                          

     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

                                   

     Xoffset = Xout_14_bit / 8 * (-1);        // Compute X-axis offset correction value

     Yoffset = Yout_14_bit / 8 * (-1);        // Compute Y-axis offset correction value

     Zoffset = (Zout_14_bit - SENSITIVITY_2G) / 8 * (-1);          // Compute Z-axis offset correction value

                                   

     I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG1, 0x00);             // Standby mode to allow writing to the offset registers 

     I2C_WriteRegister(MMA845x_I2C_ADDRESS, OFF_X_REG, Xoffset);        

     I2C_WriteRegister(MMA845x_I2C_ADDRESS, OFF_Y_REG, Yoffset); 

     I2C_WriteRegister(MMA845x_I2C_ADDRESS, OFF_Z_REG, Zoffset); 

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

     I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG4, 0x01);             // Enable DRDY interrupt

     I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG5, 0x01);             // DRDY interrupt routed to INT1 - PTA14

     I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG1, 0x3D);             // ODR = 1.56Hz, Reduced noise, Active mode 

}

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_PCR14 |= PORT_PCR_ISF_MASK;            // Clear the interrupt flag

     DataReady = 1;     

}

5. The output values from accelerometer registers 0x01 – 0x06 are first converted to signed 14-bit values and afterwards to real values in g’s.

if (DataReady)             // Is a new set of data ready?

{           

     DataReady = 0;

                                                                                                               

     I2C_ReadMultiRegisters(MMA845x_I2C_ADDRESS, OUT_X_MSB_REG, 6, AccData);           // Read data output registers 0x01-0x06

      

     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_2G;              // Compute X-axis output value in g's

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

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

}

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 view both the 14-bit and real values in the FreeMASTER application, some USBDM drivers need to be first installed on your computer. They are available for download from SourceForge. Erich Styger described their installation in this tutorial. In addition to that, the USBDM_OpenSDA application that provides both debugging and a virtual serial port needs to be loaded into the MK20 debugger chip on the FRDM-KL25Z board. This installation follows the usual FRDM-KL25Z bootloader process:

  • Unplug the FRDM-KL25Z board.
  • Whilst holding the SW1/RST switch depressed plug in the FRDM-KL25Z board. The green LED should start blinking at a rate of about 1Hz.
  • Open a file explorer and locate the USB drive that has now appeared. It will have the drive name "BOOTLOADER".
  • Drag the file USBDM_OpenSDA.sx to the USB drive and wait a short while. The OpenSDA firmware on the FRDM-KL25Z board will program the USBDM firmware into the MK20 debugger chip on the board.
  • Remove and re-plug the FRDM-KL25Z board. The board will now appear as a USBDM device.

FRDM-KL25Z_MMA8451Q_BasicReadUsingInterrupt_HighResolution.JPG.jpg

FRDM-KL25Z_MMA8451Q_BasicReadUsingInterrupt_HighResolution_FreeMASTER.JPG.jpg

Attached you can find the complete source code written in the CW for MCU's v10.5 as well as the FreeMASTER project.

So make it, test it and keep in touch...

Regards,

Tomas

Labels (1)
Attachments
Comments

Hi,

I am using MMA8451Q in KL25Z board with Code Warrior 10.6 (processor expert). I have configured the board for transient detection but i was not able to generate the interrupt when the amplitude goes beyond threshold level. Is there any component that helps to write the ISR for the interrupt generated on PTA14.

Regards,

Charan

Hi Charan,

You might find useful my example code for the embedded transient detection function that is available here.

I hope it helps.

Regards,

Tomas

Hi Tomas,

thank you very much for your replay and It worked.

Regards,

Charan

Hi Tomas,

I tried your code on board FRDM KL43z. The difference between it and KL25z is that the pin INT1 is the pin PTC5. I tested initially communicate, therefore I read WHOIAM register (0x0D), but returns me sign 0xFF, but interesting is that once function return correct character 0x1A, but after restart again return 0xFF. Where could be a problem?

Thanks.

Hi Martin,

Since the FRDM-KL43Z board does not have both the communication pins (PTE24 – I2C0 SCL and PTE25 – I2C0 SDA) easily accessible to see what is going on on the I2C bus, it is hard to say where the problem might be. The MKL43Z256 MCU is not supported in the CW for MCU’s v10.6, so I have created another project in KDS 3.0.0 using KSDK 1.2.0 and Processor Expert. You can find it attached above in my original post.

Hope it helps.

Regards,

Tomas

Hi Tomas,

I´m not able to watch the variables at Freemaster (I´m new using this tool) and I don´t see its libraries, functions, etc. from your souce code, so how the application communicate with Freemaster and how to embedded in a new baremetal project?

Hi Tomas,
is there any chance you could upload your projects again as they're unfortunately deleted from NXP sites. Working on MMA8451Q with KL46Z and got hard stuck. Can't get ack after sending my address to I2C. I would really appreciate. I know it's been a long time since you posted this. 

Version history
Last update:
‎12-06-2013 01:59 AM
Updated by: