cancel
Showing results for 
Search instead for 
Did you mean: 

Please provide guidance on VL53L3 calibration.

charles23
Associate III

The "VL53LX API Specification" 1.1.4.2352 lists 13 "calibration functions" but provides little guidance on what they do and when they should be called. The VL53L3 data sheet says calibration is required and "The detailed procedure is provided in the device driver user manual" - but I do not see such a user manual (is it the "VL53LX API Specification", or something different?). The example application does not perform calibration.

Is there any guidance on the use of these functions to optimise performance of the VL53L3? What about sample code that shows them in use?

9 REPLIES 9
John E KVAM
ST Employee

I'm sorry this isn't more obvious.

Download:

STSW-IMG015 VL53L3CX API (Application Programming Interface)

from the ST web site.

In there you will find a manual.

There are several VL53 sensors. They are the L0X, the L1X, the L1CB and the L3CX

All the sensors are pretty similar, differing in the max distance and the type of processing they use.

All the calibration data is in the API user guides, but the user guides are hidden in the API code itself.

So go with the download, for your particular sensor, and go from there.

And you are right the examples don't do calibration, because it takes a setup.

But the set up is defined in the manual.

I'll see what I can do about putting the API user manual on the WebSite and not quite so hidden.

  • john

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.
charles23
Associate III

Hi John

Thanks for your quick reply. The link you provide unzips to a folder named "en.en.bare_driver_VL53L3CX" which has TWO folders with documentation:

(1) en.en.bare_driver_VL53L3CX\ExampleCode\X-CUBE-53L3A2_V1.0.0\Documentation

   Contains documentation on the X-NUCLEO-53L3A2 Expansion Board (but no references to calibration)

(2) en.en.bare_driver_VL53L3CX\BareDriver\VL53L3CX_API_1.1.4\doc

   Contains:

       UM2267-VL53L3CX-User_Manual.pdf  (has considerable info on calibration)

       VL53LX_API.chm (documents the calibration functions but not the context of their use)

Earlier I had downloaded the X-CUBE-53L3A2 package which unzips and contains this documentation:

(3) STM32CubeExpansion_53L3A2_V1.0.1\Documentation

   Contains the same files as (1) plus a .chw file but _not_ the files in (2) 

Is what I found what you expect? It does not quite seem to match your answer, which says "hidden in the API code itself" - when I look at the source files here:

en.en.bare_driver_VL53L3CX\BareDriver\VL53L3CX_API_1.1.4\core\src\vl53lx_api_calibrate.c (and the corresponding .h file) there is no documentation at all.    

According to UM2267: "VL53L3CX driver includes calibration functions to be run once at customer production line... Calibration data stored in the host have to be loaded in VL53L3CX at each startup using a dedicated driver function."

Am I correct in this analysis:

(1) Calibration code must be executed during manufacturing and parameters stored in non-volatile memory on the target device.

(2) Every time the target device boots, these parameters must be read from non-volatile memory and written into the VL53L03.

(3) No further use of the 13 "VL53LX Calibration Functions" is required.

Clearly ST have implemented this algorithm - could you share sample code? It would make life easier for your users.

John E KVAM
ST Employee

You are exactly correct.

(1) Calibration code must be executed during manufacturing and parameters stored in non-volatile memory on the target device.

(2) Every time the target device boots, these parameters must be read from non-volatile memory and written into the VL53L03.

(3) No further use of the 13 "VL53LX Calibration Functions" is required.

The calibration functions are pretty simple, but a target has to be arranged prior to running them.

We had the cal functions in the code, but people were more confused, and tried to run it every time.

It didn't work well - and there were too many hardware restrictions outside our control.

Our sensor works on all MCUs (although we suggest an ST MCU works best) and I have no idea of your hardware.

So we leave it up to you to :

1) prompt the user how to set up the offset calibration.

2) call the RefSpad cal function.

3) call the offset calibration function

4) prompt the user to set up the crosstalk calibration

5) call the crosstalk function

6) 'get' the result,

7) find somewhere to store the data.

😎 at next boot 'put' the result back into our sensor.


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.

At the risk of moving a little off-topic, can you give guidance to the use of Flash memory for storing calibration data? I am using the Nucleo F401, and found this example of using flash: https://github.com/fboris/STM32Cube_FW_F4/tree/master/Projects/STM32F4-Discovery/Examples/FLASH/FLASH_EraseProgram - which I have used as a model.

I have ended up using the final flash sector (128k bytes at address 0x08060000) since if I used 16k byte sectors earlier in memory it looked like I was trashing my own code. A quick attempt at using the first 16k byte sector at 0x08000000 and editing the linker file so FLASH started at 0x08004000 was not successful.

Where can I find guidance on user Flash with STM32CUBE, in particular the necessary adjustments to the linker process?

John E KVAM
ST Employee

you are not the only one to ask this question.

https://www.st.com/en/embedded-software/stsw-stm32066.html

is what I got when I googled it.

(And if you get an answer, could you post it back here, please?)

Another good try is from MBED:

https://os.mbed.com/questions/76613/NUCLEO-F401RE-something-like-EEPROM/

Both these approaches use Flash to simulate EEPROM.

I'm concerned that when you flash new code, the Link processor would do a bulk erase and kill your calibration data as well.

It's been a long time since I've done anything with Flash, so I cannot answer.

Perhaps you could ask this on the STM32 community page.

  • john

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.
John E KVAM
ST Employee

Exactly.

and to help verify you got it right, consider including the following code.

(Remove it once you get the test to pass.)

#define I2C_TEST
#ifdef I2C_TEST
int rd_write_verification( VL53L1_Dev_t *dev, uint16_t addr, uint32_t expected_value)
{
	VL53L1_Error Status  = VL53L1_ERROR_NONE;
	uint8_t bytes[4],mbytes[4];
	uint16_t words[2];
	uint32_t dword;
	int i;
	VL53L1_ReadMulti(dev, addr, mbytes, 4);
	for (i=0; i<4; i++){ VL53L1_RdByte(dev, addr+i, &bytes[i]); }
	for (i=0; i<2; i++){ VL53L1_RdWord(dev, addr+i*2, &words[i]); }
	Status = VL53L1_RdDWord(dev, addr, &dword);
	
	printf("expected   = %8x,\n",expected_value);
	printf("read_multi = %2x, %2x, %2x, %2x\n", mbytes[0],mbytes[1],mbytes[2],mbytes[3]);
	printf("read_bytes = %2x, %2x, %2x, %2x\n", bytes[0],bytes[1],bytes[2],bytes[3]);
	printf("read words = %4x, %4x\n",words[0],words[1]);
	printf("read dword = %8x\n",dword);
	
	if((mbytes[0]<<24 | mbytes[1]<<16 | mbytes[2]<<8 | mbytes[3]) != expected_value) return (-1);
	if((bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3]) != expected_value) return (-1);
	if((words[0]<<16 | words[1]) != expected_value) return (-1);
	if(dword != expected_value) return(-1);
	return Status;
	
}
#define REG 0x3A
void i2c_test(VL53L1_Dev_t *dev)
{
	VL53L1_Error Status  = VL53L1_ERROR_NONE;
	int err_count = 0;
	uint8_t buff[4] = {0x11,0x22,0x33,0x44};
	uint8_t long_out[135] ={0x29, 0x02, 0x10, 0x00, 0x22, 0xBC, 0xCC, 0x81, 0x80, 0x07, 0x16, 0x00, 0xFF, 0xFD,
							0xF7, 0xDE, 0xFF, 0x0F, 0x00, 0x15, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
							0x44, 0x00, 0x2C, 0x00, 0x11, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
							0x00, 0x11, 0x02, 0x00, 0x02, 0x08, 0x00, 0x08, 0x10, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF,
							0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0B, 0x00, 0x00, 0x02, 0x14, 0x21, 0x00, 0x00,
							0x02, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x38, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00,
							0x9D, 0x07, 0x00, 0xD2, 0x05, 0x01, 0x68, 0x00, 0xC0, 0x08, 0x38, 0x00, 0x00, 0x00, 0x00, 0x03,
							0xB6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x05, 0x06, 0x06, 0x01, 0x00, 0x02,
							0xC7, 0xFF, 0x8B, 0x00, 0x00, 0x00, 0x01, 0x01, 0x40};
	uint8_t long_in[135]= {0xff};
  	int i=0;
 
	Status = rd_write_verification(dev, 0x10f, 0xeacc10ff);			// verify the Chip ID works
 
	Status += VL53L1_WriteMulti(dev, 0x01,  long_out, 135);			// check if WriteMulti can write 135 bytes
	Status += VL53L1_ReadMulti(dev, 0x01,  long_in, 135);			// check if WriteMulti can read 135 bytes
 
	for (i=0; i<135; i++) if(long_in[i] != long_out[i])err_count++;
	if (err_count > 10) Status++;
 
	Status += VL53L1_WriteMulti(dev, REG,  buff, 4);				// check WriteMulti
	if (rd_write_verification(dev, REG, 0x11223344) <0) err_count++;
 
	Status += VL53L1_WrDWord(dev, REG, 0xffeeddcc);				// check WrDWord
	if (rd_write_verification(dev, REG, 0xffeeddcc) <0) err_count++;
 
	Status += VL53L1_WrWord(dev, REG, 0x5566);					// check WrWord
	Status += VL53L1_WrWord(dev, REG+2, 0x7788);
	if (rd_write_verification(dev, REG, 0x55667788) <0) err_count++;
 
	for (i=0; i<4; i++){ VL53L1_WrByte (dev, REG+i, buff[i]); }
	if (rd_write_verification(dev, REG,0x11223344) <0) Status++;
	if (Status > 0)
	{
		printf("i2c test failed - please check it. Status = %d\n", Status);
	}
}
 
#endif

It verifies the long I2C long I/O operations and the 'byte endianness' of the operations.

  • john

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.

Posted to the wrong topic?

With regards to trashing my user flash, this is not a problem. The download console output includes these lines:

 Size         : 116152 Bytes

 Address      : 0x08000000

 Erasing memory corresponding to segment 0:

 Erasing internal memory sectors [0 4]

Also, the highest flash address I can see in the .map file is 801c3ac, so I would say that my application requires just under 128k bytes, so (I am guessing here) the downloader decides to erase sectors 0-4 which totals 128k - enough for my code. Thus sectors 5-7 (including my configuration flash at sector 7) remain untouched.

This link gives some advice on using the linker to allocate flash memory:

   https://stackoverflow.com/questions/44443619/how-to-write-read-to-flash-on-stm32f4-cortex-m4

Following this advice, I edited STM32F401RETX_FLASH.ld to read as follows:

MEMORY

{

 RAM   (xrw)   : ORIGIN = 0x20000000,  LENGTH = 96K

 FLASH   (rx)   : ORIGIN = 0x8000000,  LENGTH = 384K

 DATA (rx)      : ORIGIN = 0x08060000, LENGTH = 128K

}

Then I find I can access my user flash with this:

uint8_t userConfig[400] __attribute__ ((section(".user_data")));

Of course, it would be more efficient if I could set sector 0 (16k) as my user flash. However my attempt at allocating sector 0 for the DATA and starting the FLASH in sector 1 fails:

MEMORY

{

 RAM   (xrw)   : ORIGIN = 0x20000000,  LENGTH = 96K

 FLASH   (rx)   : ORIGIN = 0x8000000,  LENGTH = 384K

 DATA (rx)      : ORIGIN = 0x08060000, LENGTH = 128K

}

The downloader prints these lines, which look promising:

 Address      : 0x08004000

 Erasing internal memory sectors [1 5]

and the .map output looks promising, but the program does not run. I suspect I need to make a change to the startup .s file, or make further changes to the .ld file, but don't know what to change. Ideas?

(what creates the .ld and .s files in STM32CUBE, BTW?)

John E KVAM
ST Employee

Oops. Thanks for pointing it out.

I have a pretty active community page. (Something I'm kind of proud of.) But I'm a log way from perfect.

I'm out of ideas on your flash issue.

I really think you should copy your post over to the STM32 community page.

You appear to be trying to modify your ROM data inside your program.

And I don't think that is going to work.

You need to bring the ST flash driver into your program and treat the flash as a peripheral.

Then you can issue commands to it - like erase sector and write data.


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.