cancel
Showing results for 
Search instead for 
Did you mean: 

VL53L5CX driver vl53l5cx_init() fails

Peter111
Associate II

The Ultra Light Driver (STSW-IMG023) init function vl53l5cx_init() fails in this section :

/* Get offset NVM data and store them into the offset buffer */
 
	status |= WrMulti(&(p_dev->platform), 0x2fd8,
 
		(uint8_t*)VL53L5CX_GET_NVM_CMD, sizeof(VL53L5CX_GET_NVM_CMD));
 
	status |= _vl53l5cx_poll_for_answer(p_dev, 4, 0,
 
		VL53L5CX_UI_CMD_STATUS, 0xff, 2);

The sensor does not answer with '2' as expected by _vl53l5cx_poll_for_answer. (The senosr answers '0')

This results in a failed initialization.

How can this be fixed?

50 REPLIES 50
jspiller
Associate II

Did you end up solving this issue?

tekochip
Associate II

Like so many of you, I have visited this site trying to get an answer on making this sensor work. I didn’t get any usable guidance, but I figured quite a few things out, so here’s a few answers.

The reason why initialization fails at /* Get offset NVM data and store them into the offset buffer */ Is because this is where the ToF sensor is asked to start responding to commands from the firmware that was downloaded in the previous steps. I don’t know what is checked during the comment /* Check if FW correctly downloaded */, but it’s not a CRC or anything that verifies the firmware transfer. This exposes the first issue with the sensor, and that’s that it requires the firmware to be transferred in rather large, 32KB chunks. Whatever I2C driver you are using needs to handle transfers of that size. You cannot break the transfer up into smaller blocks, it must be sent as called in the API. Make sure your driver can handle that size, and in the case of Nordic, you may have to copy the FLASH transfer over to RAM, because the DMA cannot handle transfers originating in FLASH.

The second issue is that the API is written in such a way that it requires an enormous amount of stack space. Many compilers optimize their code so that the stack space inside a function is not reserved until an instruction inside the function addresses the local variable. I am using Zephyr with Nordic’s nRF52, and the code would always fail during a memcpy(), rather than at the start of the function that blew the stack. The cure here is to declare variables static so that they are not being created on the stack. In example1() this would be:

               static VL53L5CX_Configuration  Dev ;                                     /* Sensor configuration */

               static VL53L5CX_ResultsData     Results;               /* Results data from VL53L5CX */

The other examples have additional variables that you will want to make static or global, just to keep them off the stack. I presently have everything running in nRF52’s Zephyr, and also in Nordic’s SDK.

I hope this helps, and if anyone needs some details, let me know.

I was able to get it working by breaking up the transfer. Things to keep in mind in doing so is incrementing the register address accordingly when breaking it up, and comply with the standard I2C spec as there is an error in one of their diagrams in the datasheet.

tekochip
Associate II

I stand corrected, I have also able to break the transfer into pieces.

mute Am 19.07.2022 23:45 schrieb ST Community : I stand corrected, I have also able to break the transfer into pieces. [https://community.st.com/img/userprofile/default_profile_45_v2.png?fromEmail=1]<> tekochip<> (Community Member) I stand corrected, I have also able to break the transfer into pieces. View/Answer<> or reply to this email Replying to [https://community.st.com/img/userprofile/default_profile_45_v2.png?fromEmail=1]<> Peter111<> (Community Member) asked a question. Wednesday, August 11, 2021 2:47 AM<> VL53L5CX driver vl53l5cx_init() fails The Ultra Light Driver (STSW-IMG023) init function vl53l5cx_init() fails in this section : /* Get offset NVM data and store them into the offset buffer */ status |= WrMulti(&(p_dev->platform), 0x2fd8, (uint8_t*)VL53L5CX_GET_NVM_CMD, sizeof(VL53L5CX_GET_NVM_CMD)); status |= _vl53l5cx_poll_for_answer(p_dev, 4, 0, VL53L5CX_UI_CMD_STATUS, 0xff, 2); The sensor does not answer with '2' as expected by _vl53l5cx_poll_for_answer. (The senosr answers '0') This results in a failed initialization. How can this be fixed? [https://community.st.com/img/userprofile/default_profile_45_v2.png?fromEmail=1]<> tekochip<> (Community Member) I stand corrected, I have also able to break the transfer into pieces. Tuesday, July 19, 2022 2:44 PM<> You're receiving emails when someone "Comments on my posts." To change or turn off ST Community email, log in<> as felix.hundhausen@kit.edu.st. Are notifications about this post getting annoying? Reply to this email with the word " mute ". STMicroelectronics N.V. [ST Community]
WParr.1
Associate II

I am also getting an error here:

	/* Get offset NVM data and store them into the offset buffer */
	status |= WrMulti(&(p_dev->platform), 0x2fd8,(uint8_t*)VL53L5CX_GET_NVM_CMD, sizeof(VL53L5CX_GET_NVM_CMD));

	status |= _vl53l5cx_poll_for_answer(p_dev, 4, 0, VL53L5CX_UI_CMD_STATUS, 0xff, 2);

	status |= RdMulti(&(p_dev->platform), VL53L5CX_UI_CMD_START, p_dev->temp_buffer, VL53L5CX_NVM_DATA_SIZE)); //ErrorHere

status errors with  VL53L5CX_COMMS_ERROR thrown by the following use in "platforms.c": int32_t write_read_multi function:

			if (ioctl(fd, I2C_RDWR, &packets) < 0)
				return VL53L5CX_COMMS_ERROR;
			position +=  data_size;

It appears that ioctl throws an error:

 

		do {
			data_size = (count - position) > VL53L5CX_COMMS_CHUNK_SIZE ? VL53L5CX_COMMS_CHUNK_SIZE : (count - position);

			i2c_buffer[0] = (reg_address + position) >> 8;
			i2c_buffer[1] = (reg_address + position) & 0xFF;

			messages[0].addr = i2c_address >> 1;
			messages[0].flags = 0; //I2C_M_WR;
			messages[0].len = 2;
			messages[0].buf = i2c_buffer;

			messages[1].addr = i2c_address >> 1;
			messages[1].flags = I2C_M_RD;
			messages[1].len = data_size;
			messages[1].buf = pdata + position;

			packets.msgs = messages;
			packets.nmsgs = 2;

//			int ret = ioctl(fd, I2C_RDWR, &packets);
//			if (ret < 0){		//throws error here
//				return VL53L5CX_COMMS_ERROR;
//			}
			if (ioctl(fd, I2C_RDWR, &packets) < 0)
				return VL53L5CX_COMMS_ERROR;

			position += data_size;

		} while (position < count);

 

I'm struggling to find the issue, as this read function is used regularly throughout the initialisation before the error occurs.

 

How can this be fixed?

AA.16
Associate III

I have the same exact issue. It stops at the VL53L8CX_UI_CMD_STATUS with a timeout after not receiving the number 2 as answer.

 

 

I rewrote my WrMulti to deal with bigger data and break it down into chunks:

 

uint8_t WrMulti(VL53L8CX_Platform *p_platform, uint16_t RegisterAddress, uint8_t *p_values, uint32_t size) {
    // Initialize buffer for register address
    uint8_t regBuff[2] = { RegisterAddress >> 8, RegisterAddress & 0xFF };

    // Loop through the data in chunks of 255 bytes
    for (uint32_t offset = 0; offset < size; offset += 255) {
        uint8_t chunkSize = (size - offset > 255) ? 255 : (size - offset);

        // Send register address
        if (HAL_I2C_Master_Transmit(&hi2c2, addr, regBuff, 2, 5000) != HAL_OK) {
        	APP_LOG(TS_ON, 3, "[PLAT] WrMulti  Send register address failed\n");
            return -1;
        }

        // Write data chunk
        if (HAL_I2C_Master_Transmit(&hi2c2, addr, p_values + offset, chunkSize, 5000) != HAL_OK) {
        	APP_LOG(TS_ON, 3, "[PLAT] WrMulti  Write data chunk failed\n");
            return -1;
        }

        // Delay between chunks
        HAL_Delay(2);
    }

    return 0;
}

 This code should  write only chunks of 255 bytes at once and adjust the register perfectly. This seems to work until we reach the dreaded lines:

status |= _vl53l8cx_poll_for_answer(p_dev, 4, 0,VL53L8CX_UI_CMD_STATUS, 0xff, 2); // ### ERROR HERE!!! TIMEOUT !!!

 

The status is always 0 up until this line where it changes into a 1. looking into it its a timeout issue because we never receive the 2 as answer.

 

Please advise on how to get the 8x8 ToF to work properly.

I think I see your issue.

The chip starts when the last byte is written. 

But your chunk size of 255 is not a sub-multiple of the larger write.

So, you end up needing one last write to complete the download.

 


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.

i rewrote it to this:

 

uint8_t WrMulti(VL53L8CX_Platform *p_platform, uint16_t RegisterAddress, uint8_t *p_values, uint32_t size) {
	// Send register address
	uint8_t regBuff[2] = { RegisterAddress >> 8, RegisterAddress & 0xFF };
	if (HAL_I2C_Master_Transmit(&hi2c2, addr, regBuff, 2, 5000) != HAL_OK) {
		APP_LOG(TS_ON, 3, "[PLAT] WrMulti  Send register address failed\n");
		return -1;
	}

	// Loop through the data in chunks of 255 bytes // #define chunk 1<<8
	for (uint32_t offset = 0; offset < size; offset += chunk) {
        uint8_t chunkSize = (size - offset > chunk) ? chunk : (size - offset);
        // Write data chunk
        if (HAL_I2C_Master_Transmit(&hi2c2, addr, p_values + offset, chunkSize, 5000) != HAL_OK) {
            APP_LOG(TS_ON, 3, "[PLAT] WrMulti  Write data chunk failed\n");
            return -1;
        }
    }

    // If the size is not a multiple of 255, we need to write the remaining bytes
    if (size % chunk != 0) {
        // Write remaining data
        if (HAL_I2C_Master_Transmit(&hi2c2, addr, p_values + size - (size % chunk), size % chunk, 5000) != HAL_OK) {
            APP_LOG(TS_ON, 3, "[PLAT] WrMulti  Write remaining data failed\n");
            return -1;
        }
    }
    return 0;
}

However the same problem occurs.

 

this passes:

VL53L8CX_GET_NVM_CMD returns status 0 -> success

 

however this does not

VL53L8CX_UI_CMD_STATUS returns status 1 -> fail

AA.16
Associate III

i also tried this version where i resend the register addresses and adjust them according to the offset of already sent data. the same error and behaviour occurs:

 

 

uint8_t WrMulti(VL53L8CX_Platform *p_platform, uint16_t RegisterAddress, uint8_t *p_values, uint32_t size) {
    //#define addr (uint16_t)0x29<<1
    // Loop through the data in chunks of 255 bytes
    for (uint32_t offset = 0; offset < size; offset += chunk) {
        // Initialize buffer for register address, adjusting it with the offset
        uint16_t currentRegisterAddress = RegisterAddress + offset;
        uint8_t regBuff[2] = { currentRegisterAddress >> 8, currentRegisterAddress & 0xFF };

        uint8_t chunkSize = (size - offset > chunk) ? chunk : (size - offset);

        // Send register address
        if (HAL_I2C_Master_Transmit(&hi2c2, addr, regBuff, 2, 5000) != HAL_OK) {
            APP_LOG(TS_ON, 3, "[PLAT] WrMulti  Send register address failed\n");
            return -1;
        }

        // Write data chunk
        if (HAL_I2C_Master_Transmit(&hi2c2, addr, p_values + offset, chunkSize, 5000) != HAL_OK) {
            APP_LOG(TS_ON, 3, "[PLAT] WrMulti  Write data chunk failed\n");
            return -1;
        }

        // Delay between chunks
        HAL_Delay(2);
    }

    // If the size is not a multiple of 255, we need to write the remaining bytes
    if (size % chunk != 0) {
        // Initialize buffer for register address, adjusting it with the offset
        uint16_t currentRegisterAddress = RegisterAddress + size - (size % chunk);
        uint8_t regBuff[2] = { currentRegisterAddress >> 8, currentRegisterAddress & 0xFF };

        // Send register address
        if (HAL_I2C_Master_Transmit(&hi2c2, addr, regBuff, 2, 5000) != HAL_OK) {
            APP_LOG(TS_ON, 3, "[PLAT] WrMulti  Send register address failed\n");
            return -1;
        }

        // Write remaining data
        if (HAL_I2C_Master_Transmit(&hi2c2, addr, p_values + size - (size % chunk), size % chunk, 5000) != HAL_OK) {
            APP_LOG(TS_ON, 3, "[PLAT] WrMulti  Write remaining data failed\n");
            return -1;
        }

        // Delay after writing remaining data
        HAL_Delay(2);
    }

    return 0;
}