MMA8451Q -Single Tap Detection Bare metal example project

Document created by David Diaz Marin Employee on Feb 18, 2016Last modified by David Diaz Marin Employee on Feb 19, 2016
Version 4Show Document
  • View in full screen mode

Hello community,


As we know, The MMA8451Q has embedded single/double and directional tap detection.


This post describes an example project using the Single Tap detection for the MMA8451Q included on the FRDM-KL25Z.




Figure 1. Depending on the tapping direction, positive or negative of each axis, the RGB LED will turn into a different color.



For more detailed information on how to configure the device for tap detection please refer to NXP application note, AN4072.



Configuring the MCU

Enable the I2C module of the KL25Z MCU and turn on all the corresponding clocks.

In this case, the INT1 output of the MMA8451Q is connected to the PTA14 pin and both SCL and SDA lines are connected to the I2C0 module (PTE24 and PTE25 pins). Please review the FRDM-KL25Z schematic.



     //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);





Configure the RBG LED of the FRDM-KL25Z

Based on FRDM-KL25Z User's Manual , the RGB LED signals are connected as follow:

RGB led2.jpg


The pins mentioned, are configured as output.


     //Configure PTB18, PTB19 and PTD1 as output for the RGB LED

       SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK;    // Turn on clock to Port B module

       SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK;    // Turn on clock to Port D module


       PORTB_PCR18 |= PORT_PCR_MUX(0x1);     // PTB18 is configured as GPIO

       PORTB_PCR19 |= PORT_PCR_MUX(0x1);     // PTB19 is configured as GPIO

       PORTD_PCR1 |= PORT_PCR_MUX(0x1);      // PTD1 is configured as GPIO


       GPIOB_PDDR |= (1 << 18);              //Port Data Direction Register (GPIOx_PDDR)

       GPIOB_PDDR |= (1 << 19);              //Set GPIO direction set bit corresponding bit on the direction

       GPIOD_PDDR |= (1 << 1);               //register for each port, set the bit means OUTPUT



Initialize and configure the MMA8451Q for Tap Detection

To utilize the single and/or double tap detection the following eight (8) registers must be configured.

  1. Register 0x21: PULSE_CFG Pulse Configuration Register
  2. Register 0x22: PULSE_SRC Pulse Source Register
  3. Register 0x23 - 0x25: PULSE_THSX,Y,Z Pulse Threshold for X, Y and Z Registers
  4. Register 0x26: PULSE_TMLT Pulse Time Window 1 Register
  5. Register 0x27: PULSE_LTCY Pulse Latency Timer Register
  6. Register 0x28: PULSE_WIND Second Pulse Time Window Register


Please review the MMA8451Q datasheet in order to get more information about the registers mentioned.




For a single tap event, the PULSE_TMLT, PULSE_THSX/Y/Z and PULSE_LTCY registers are key parameters to consider.


  1. Note in condition (a) the interrupt is asserted since the acceleration due to a pulse exceeds the specified acceleration threshold (value set in the PULSE_THSX) and crosses up and down before the specified Pulse Time Limit (value set in PULSE_TMLT) expires.
  2. Note that in condition (b) the acceleration due to a pulse exceeds the specified acceleration threshold limit, but does not go below the threshold before the specified Pulse Time Limit expires. Therefore, this is an invalid pulse and the interrupt will not be triggered. Also note that the Latency is not shown for this example.


             unsigned char reg_val = 0, CTRL_REG1_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, CTRL_REG1, 0x0C);             // ODR = 400Hz, Reduced noise, Standby mode

       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, PULSE_CFG_REG, 0x15);         //Enable X, Y and Z Single Pulse

       I2C_WriteRegister(MMA845x_I2C_ADDRESS, PULSE_THSX_REG, 0x20);        //Set X Threshold to 2.016g

       I2C_WriteRegister(MMA845x_I2C_ADDRESS, PULSE_THSY_REG, 0x20);        //Set Y Threshold to 2.016g

       I2C_WriteRegister(MMA845x_I2C_ADDRESS, PULSE_THSZ_REG, 0x2A);        //Set Z Threshold to 2.646g

       I2C_WriteRegister(MMA845x_I2C_ADDRESS, PULSE_TMLT_REG, 0x28);        //Set Time Limit for Tap Detection to 25 ms

       I2C_WriteRegister(MMA845x_I2C_ADDRESS, PULSE_LTCY_REG, 0x28);        //Set Latency Time to 50 ms


       I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG4, 0x08);             //Pulse detection interrupt enabled

       I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG5, 0x08);             //Route INT1 to system interrupt


       CTRL_REG1_val = I2C_ReadRegister(MMA845x_I2C_ADDRESS, CTRL_REG1);   //Active Mode

       CTRL_REG1_val |= 0x01;

       I2C_WriteRegister(MMA845x_I2C_ADDRESS, CTRL_REG1, CTRL_REG1_val);




Handle the Interrupt

The PULSE_SRC register indicates a double or single pulse event has occurred and also which direction.

In this case the value of the register mentioned is passed to the PULSE_SRC_val variable and evaluated.

Reading the PULSE_SRC register clears all bits. Reading the source register will clear the interrupt.


     void PORTA_IRQHandler()


       PORTA_PCR14 |= PORT_PCR_ISF_MASK;               // Clear the interrupt flag      

       PULSE_SRC_val = I2C_ReadRegister(MMA845x_I2C_ADDRESS, PULSE_SRC_REG); //Read Pulse Source Register






Please find attached the complete source code written in the CodeWarrior for Microcontrollers-Eclipse IDE|NXP .

As I mentioned before, you can find more detailed information at application note AN4072.

Useful information about handling the MMA8451 can be founded in MMA8451Q - Bare metal example project.



I hope you find useful and funny this sample project.