I am trying to configure the FXOS8700CQR in magnetic threshold interrupt mode. I am using SPI to communicate witth the sensor.
Whenever a magnet is in the vicinity of the sensor, the programmed magnetic threshold values is supposed to trigger an interrupt.
When the data is streaming I can clearly see the spikes on the signal passing the programmed threshold.
The interrupt pin does not go high however. I checked with a scope.
I don't see the magnetic interrupts happening.The problem is that the magnetic interrupts in the ISR are not triggered.
Even if I trigger them manually by the shaking the unit I cannot clear them. Pin stays always high.
Is there any application note with regard to the magnetic threshold interrupt specifically. (not the vector magnitude)?
void FXOS8700CQ_ConfigMagTHS(void){
MAG_RST_HIGH(); // Hard Reset , RST active HIGH
__delay_ms(5);
MAG_RST_LOW();
__delay_ms(1);
FXOS8700CQ_WriteByte(CTRL_REG2, SMOD_LOW_NOISE|SLPE_MASK|MOD_LOW_NOISE); // Low noise, low power, auto-sleep mode enabled
FXOS8700CQ_WriteByte(CTRL_REG3, IPOL_MASK); // Active HIGH on INT, push-pull mode
FXOS8700CQ_WriteByte(CTRL_REG4, 0x00 ); // No interrupt enabled here
FXOS8700CQ_WriteByte(CTRL_REG5, 0x00 ); // No interrupt routed to pin 2
FXOS8700CQ_WriteByte(ASLP_COUNT, 0x05); // 20 ms - if not interrupt is asserted in 20 ms the system will go back to sleep mode
FXOS8700CQ_WriteByte(M_CTRL_REG1, M_ACAL_MASK| M_OSR_50_HZ | M_HMS0_MASK); // automatic calibration, one shot magnetic reset, only mag active
FXOS8700CQ_WriteByte(M_CTRL_REG2, M_MAXMIN_DIS_MASK | M_MAXMIN_DIS_THS_MASK | M_MAXMIN_RST_MASK | RST_DISABLED); //Magnetic min/max enabled
FXOS8700CQ_WriteByte(M_CTRL_REG3, M_ASLP_OSR_100_HZ | M_THS_XYZ_MASK | M_ST_Z_MASK | M_ST_XY_MASK); // all updated when THS ISR happens
FXOS8700CQ_WriteByte(M_THS_CFG, M_THS_ELE | M_THS_OAE | M_THS_WAKE_EN | M_THS_ZEFE | M_THS_YEFE | M_THS_XEFE| M_THS_WAKE_EN | M_THS_INT_EN ); //M_INT_threshold on INT2 pin OR INT of all axes for threshold, latch disabled.
uint16_t magThreshold = 0x200; //counts;
uint8_t magThresholdHi = (magThreshold & 0xFF00) >> 8;
uint8_t magThresholdLo = magThreshold & 0xFF;
FXOS8700CQ_WriteByte(M_THS_Z_MSB, magThresholdHi); // Debounce countered cleared to zero when threshold is not longer true
FXOS8700CQ_WriteByte(M_THS_Z_LSB, magThresholdLo);
magThreshold = 0x200; //counts;
magThresholdHi = (magThreshold & 0xFF00) >> 8;
magThresholdLo = magThreshold & 0xFF;
FXOS8700CQ_WriteByte(M_THS_X_MSB, magThresholdHi); // Debounce countered cleared to zero when threshold is not longer true
FXOS8700CQ_WriteByte(M_THS_X_LSB, magThresholdLo);
magThreshold = 0x200; //counts;
magThresholdHi = (magThreshold & 0xFF00) >> 8;
magThresholdLo = magThreshold & 0xFF;
FXOS8700CQ_WriteByte(M_THS_Y_MSB, magThresholdHi); // Debounce countered cleared to zero when threshold is not longer true
FXOS8700CQ_WriteByte(M_THS_Y_LSB, magThresholdLo);
FXOS8700CQ_WriteByte(M_THS_COUNT, 1); //debounce sample counts required before a magnetic threshold event is triggered, depends on ODR
FXOS8700CQ_WriteByte(CTRL_REG1, ASLP_RATE_20MS | DATA_RATE_100HZ |LNOISE_MASK ); // in sleep mode data rate 50Hz, awake ODR = 100Hz, low noise mode, in standby
}
The code above is executed between:
FXOS8700CQ_StandbyMode();
...
FXOS8700CQ_ActiveMode();
On the interrupt I try to clear the interrupt and in the main () function I try to print the source but I don't see anything at all.
void _INTInterrupt(void){
MagTHSEvent = 1;
magintsrc = FXOS8700CQ_ReadByte(M_INT_SRC);
//Read interrupt source to clear int
srcmag = FXOS8700CQ_ReadByte(M_THS_SRC);
magintsrc = FXOS8700CQ_ReadByte(M_INT_SRC);
//Read interrupt source to clear int
..... //Clear the INT interrupt flag
}
I am looking to do a similar thing - count cars and I have some FXOS8700OS devices on-hand. Is there an example of using the hardware interrupt for magnetic threshold detection I could use as a staring point?
Thanks, Chip
Hello, were you able to carry out your project, I have a similar project, could you help me?
Hi,
I will try to reproduce your settings and get back to you soon. At first glance everything seems to be correct. Can you please try to test the magnetometer threshold function without using the sleep mode?
Best regards,
Tomas
Hi Tomas,
I already tried disabling the sleep mode with the same results.
The sleep mode functionality is needed however since this is a long term solution where you can't easily replace the batteries.
I also tried changing the threshold on z axis. Still the same issue.
When a magnetic object (ex headphone) is in the vicinity all 3 axis are above 100 counts.
As it stands right now the magnetometer streams data correctly however the interrupt functionality is not responsive and does not change as per spec even if taking into account the debouncing counter (M_THS_COUNT)
Regards,
Di
Hi Di,
I have just done a simple test using the following settings (without the sleep mode) and it works well as you can see on the picture below.
void FXOS8700CQ_Init (void)
{
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_THS_X_MSB_REG, 0x00); // Threshold value MSB
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_THS_X_LSB_REG, 0x80); // Threshold value LSB
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_THS_CFG_REG, 0xCB); // Event flag latch enabled, logic OR of enabled axes, only X-axis enabled, threshold interrupt enabled and routed to INT1
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_THS_COUNT_REG, 0x0A); // 100ms at 100Hz ODR and magnetometer mode only
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_CTRL_REG1, 0x1D); // Max OSR, only magnetometer is active
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG3, 0x00); // Push-pull, active low interrupt
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG1, 0x19); // ODR = 100Hz, Active mode
}
void PORTD_IRQHandler()
{
PORTD_PCR4 |= PORT_PCR_ISF_MASK; // Clear the interrupt flag
M_Ths_Source = I2C_ReadRegister(FXOS8700CQ_I2C_ADDRESS, M_THS_SRC_REG); // Read the M_THS_SRC register to clear the SRC_M_THS flag in the M_INT_SRC register and deassert the INT1 pin
}
Can you please try to reproduce it?
Meanwhile I will try to implement the sleep mode.
Best regards,
Tomas
Hi Tomas,
I implemented thefirst snippet without the asleep configuration and indeed it works.
The issue is with the
M_THS_COUNT_REG
which determines the debouncing interval. Specifically the interrupt triggers very late with regards to the project requirements. Initially this was set to 1.
Would this sensor work, assuming you have to track very fast moving object such as cars. (transient magnetic fields)?
The datasheet suggests the minimum time is 20ms but from experimental results the delay is much larger than that.
Best,
Di
Hi Di,
The time step used by the debounce counter depends on the chosen ODR and m_hms[1:0] bits.
So the only way to reduce the time step is to increase the ODR and eventually use only the magnetometer (m_hms[1:0] = 0b01).
Best regards,
Tomas
Hi Di,
I successfully implemented the sleep mode, here is my code:
void FXOS8700CQ_Init (void)
{
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_THS_X_MSB_REG, 0x00); // Threshold value MSB
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_THS_X_LSB_REG, 0x80); // Threshold value LSB
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_THS_CFG_REG, 0xCF); // Event flag latch enabled, logic OR of enabled axes, only X-axis enabled, wake on magnetic threshold event, threshold interrupt enabled and routed to INT1
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_THS_COUNT_REG, 0x0A); // 100ms at 100Hz ODR and magnetometer mode only
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, M_CTRL_REG1, 0x1D); // Max OSR, only magnetometer is active
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG3, 0x00); // Push-pull, active low interrupt
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG2, 0x04); // Auto-sleep mode enabled
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, ASLP_COUNT_REG, 0x06); // Auto-sleep counter set to 1.92s (6 x 0.32s = 1.92s)
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG4, 0x80); // Auto-sleep/wake interrupt enabled
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG5, 0x80); // Route auto-sleep/wake interrupt to INT1
I2C_WriteRegister(FXOS8700CQ_I2C_ADDRESS, CTRL_REG1, 0x19); // ODR = 100Hz, Active mode
}
void PORTD_IRQHandler()
{
PORTD_PCR4 |= PORT_PCR_ISF_MASK; // Clear the interrupt flag
Int_Flag = 1;
}
while(1)
{
if (Int_Flag)
{
Int_Flag = 0;
Int_Source = I2C_ReadRegister(FXOS8700CQ_I2C_ADDRESS, M_INT_SRC_REG);
if (Int_Source & 0x04) // Magnetic threshold event detected?
{
M_Ths_Src = I2C_ReadRegister(FXOS8700CQ_I2C_ADDRESS, M_THS_SRC_REG); // Read the M_THS_SRC register to clear the SRC_M_THS flag in the M_INT_SRC register and deassert the INT1 pin
Event_Counter++;
}
Int_Source = I2C_ReadRegister(FXOS8700CQ_I2C_ADDRESS, INT_SOURCE_REG);
if (Int_Source & 0x80) // Auto-sleep/wake interrupt?
{
Sysmod = I2C_ReadRegister(FXOS8700CQ_I2C_ADDRESS, SYSMOD_REG);
}
}
}
I hope it will help you.
Best regards,
Tomas