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.
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);
Based on FRDM-KL25Z User's Manual , the RGB LED signals are connected as follow:
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
To utilize the single and/or double tap detection the following eight (8) registers must be configured.
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.
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);
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. :smileyhappy:
Regards,
David
Hello, I followed all the steps as it said, but when I triggerred a single tap, and "PULSE_SRC_val = I2C_ReadRegister(MMA845x_I2C_ADDRESS, PULSE_SRC_REG);" ran ,the PULSE_SRC_val is always all ZERO, why?
Hi David,
Your bare metal example for the MMA8451 is very useful to me as I have nearly completed a similar project. I have one question: you make extensive use of the "I2C_ReadRegister()" and "I2C_WriteRegister()" functions, but I cannot see the library where these functions are derived. Can you enlighten me please?
Many thanks,
Mark