Skip to main content
Jason Mount
Associate III
August 30, 2024
Solved

How to get the VL53L4CD to interrupt when nothing is detected

  • August 30, 2024
  • 3 replies
  • 1364 views

I am trying to use the VL53L4CD as a low power tamper sensor so that it interrupts when someone removes a lid.  I am using the ULP driver and I pulled in SetDetectionThresholds from the other driver.  I have been able to configure it to interrupt whenever the lid is outside of a threshold range (in case the lid is smashed in or removed), which seems to do exactly what I want.  However, if I quickly remove the lid completely so that the sensor detects nothing, it does not generate interrupts. 

Is there a configuration that tells it to interrupt when it sees nothing?

Best answer by John E KVAM

I think you've named it. The 'nothing' case. And it's a tricky one. 

It's actually in the VL53L4CD ULD threshold, but unfortunately it was left out of the UltraLowPower (ULP) driver. 

But anything used in the ULD can be used in the ULP. They are, after all, the same part. 

In the ULP is the comment:

0x20, /* 0x46 : interrupt configuration 
 0->level low detection, 
 1-> level high, 
 2-> Out of window, 
 3->In window, 0x20-> New sample ready , TBC */
In the ULP we only give you a choice between 0 (below a threshold) and 20 - (new sample ready).
I think you want Out of Window. 
Set a high, set a low and select Interrupt 2.  
The code from the ULD driver is below. You could actually stick that code in your ULP driver. 
VL53L1X_ERROR VL53L1X_SetDistanceThreshold(VL53L1_Dev_t dev, uint16_t ThreshLow,
			 uint16_t ThreshHigh, uint8_t Window,
			 uint8_t IntOnNoTarget)
{
	VL53L1X_ERROR status = 0;
	uint8_t Temp = 0;

	status = VL53L1_RdByte(&dev, SYSTEM__INTERRUPT_CONFIG_GPIO, &Temp);
	Temp = Temp & 0x47;
	if (IntOnNoTarget == 0) {
		status = VL53L1_WrByte(&dev, SYSTEM__INTERRUPT_CONFIG_GPIO,
			 (Temp | (Window & 0x07)));
	} else {
		status = VL53L1_WrByte(&dev, SYSTEM__INTERRUPT_CONFIG_GPIO,
			 ((Temp | (Window & 0x07)) | 0x40));
	}
	status = VL53L1_WrWord(&dev, SYSTEM__THRESH_HIGH, ThreshHigh);
	status = VL53L1_WrWord(&dev, SYSTEM__THRESH_LOW, ThreshLow);
	return status;
}

3 replies

John E KVAM
John E KVAMBest answer
ST Employee
September 3, 2024

I think you've named it. The 'nothing' case. And it's a tricky one. 

It's actually in the VL53L4CD ULD threshold, but unfortunately it was left out of the UltraLowPower (ULP) driver. 

But anything used in the ULD can be used in the ULP. They are, after all, the same part. 

In the ULP is the comment:

0x20, /* 0x46 : interrupt configuration 
 0->level low detection, 
 1-> level high, 
 2-> Out of window, 
 3->In window, 0x20-> New sample ready , TBC */
In the ULP we only give you a choice between 0 (below a threshold) and 20 - (new sample ready).
I think you want Out of Window. 
Set a high, set a low and select Interrupt 2.  
The code from the ULD driver is below. You could actually stick that code in your ULP driver. 
VL53L1X_ERROR VL53L1X_SetDistanceThreshold(VL53L1_Dev_t dev, uint16_t ThreshLow,
			 uint16_t ThreshHigh, uint8_t Window,
			 uint8_t IntOnNoTarget)
{
	VL53L1X_ERROR status = 0;
	uint8_t Temp = 0;

	status = VL53L1_RdByte(&dev, SYSTEM__INTERRUPT_CONFIG_GPIO, &Temp);
	Temp = Temp & 0x47;
	if (IntOnNoTarget == 0) {
		status = VL53L1_WrByte(&dev, SYSTEM__INTERRUPT_CONFIG_GPIO,
			 (Temp | (Window & 0x07)));
	} else {
		status = VL53L1_WrByte(&dev, SYSTEM__INTERRUPT_CONFIG_GPIO,
			 ((Temp | (Window & 0x07)) | 0x40));
	}
	status = VL53L1_WrWord(&dev, SYSTEM__THRESH_HIGH, ThreshHigh);
	status = VL53L1_WrWord(&dev, SYSTEM__THRESH_LOW, ThreshLow);
	return status;
}
Jason Mount
Associate III
September 4, 2024

I am currently using VL53L4CD_SetDetectionThresholds() that I copied from the ULD driver in STSW-IMG026 and I'm using 0x02 for the window value.  I have the test thresholds set at 50mm and 150mm with a 100mm tall grey test surface 85mm x 85mm.

It interrupts as expected if I move the test surface below 50mm or above 150mm but if I move the test surface beyond about a meter above the sensor, it stops interrupting (to measure the full distance, I held an 8.5x11 sheet of white paper to make sure there was a nice big target because manual alignment becomes difficult above 600mm).  For reference, as I raise the target, the values just before it stops interrupting are similar to this: 

Dist = 1004, Signal - 1200, Sigma = 12, Ambient = 128

Is that VL53LX1 code compatible with the VL53L4CD? I didn't see anything matching in the ULD code.  I modified it to match the ULP API so I could call the same way it and it didn't seem to behave any differently:

uint8_t VL53L1X_SetDistanceThreshold(
 uint16_t dev,
 uint16_t ThreshLow,
 uint16_t ThreshHigh,
 uint8_t Window,
 uint8_t IntOnNoTarget)
{
	uint8_t status = 0;
	uint8_t Temp = 0;

	status = VL53L4CD_ULP_RdByte(dev, VL53L4CD_ULP_SYSTEM__INTERRUPT, &Temp);
	Temp = Temp & 0x47;
	if (IntOnNoTarget == 0) {
		status = VL53L4CD_ULP_WrByte(dev, VL53L4CD_ULP_SYSTEM__INTERRUPT,
			 (Temp | (Window & 0x07)));
	} else {
		status = VL53L4CD_ULP_WrByte(dev, VL53L4CD_ULP_SYSTEM__INTERRUPT,
			 ((Temp | (Window & 0x07)) | 0x40));
	}
	status = VL53L4CD_ULP_WrWord(dev, VL53L4CD_ULP_THRESH_HIGH, ThreshHigh);
	status = VL53L4CD_ULP_WrWord(dev, VL53L4CD_ULP_THRESH_LOW, ThreshLow);
	return status;
}

Also, upon further examination, I probably don't need the lower threshold, just an upper will do fine as long as it interrupts when there is no target.

Am I missing or misunderstanding something? 

Jason Mount
Associate III
September 9, 2024

Thanks @John E KVAM, I was initially thrown off by the VL53LX1, but this worked.

The example I was using had multiple calls to re-configure the interrupt register I hadn't noticed; once the other calls were fixed it started generating interrupts even when nothing was detected.

For anyone else who might have this issue, the key was setting bit 0x40 in the VL53L4CD_ULP_SYSTEM__INTERRUPT register along with the desired window value.