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

Hey Sebastiaan,

Are you using Zephyr? I'm running into the initial issue in this thread with the _vl53l5cx_poll_for_answer() timing out. Did you get this driver working on your end with Zephyr by chance? I am thinking the firmware did not upload correctly.

Thanks,

Jacob

Hi Jacob,

Yes I got this working. I indeed did some changes on the poll_for_answer function but not sure anymore why exactly. In general I also removed all the "p_dev" stuff from all calls. See the "//changed" comment in below, that's definitely something I changed, but I don't remember why exactly (maybe this was not necessary at all and I only used it during debugging?)

Are you using 100 kHz or 400 kHz I2C speed?

	uint8_t status = VL53L5CX_STATUS_OK;
	uint8_t timeout = 0;
 
	do
	{
		status |= RdMulti(address, p_dev->temp_buffer, size);
		status |= WaitMs(10);
 
		if (timeout >= (uint8_t)200) /* 2s timeout */
		{
			status |= p_dev->temp_buffer[2];
		}
		else
		{
			if ((size >= (uint8_t)4) && (p_dev->temp_buffer[2] >= (uint8_t)0x7f))
			{
                                timeout++; //changed...
				status |= VL53L5CX_MCU_ERROR;
			}
			else
			{
				timeout++;
			}
		}
	} while ((p_dev->temp_buffer[pos] & mask) != expected_value);
 
	return status;

Thanks for your reply,

I am using 400 kHz, these changes didn't seem to solve my issue since it never reaches the else if statement for me. The p_dev change should just depend on the scope of your Dev so mine is working ok in that sense. Did you make any other modifications to any other files other than platform.c? If not how did you do your RdMulti and WrMulti? Because mine have worked up until writing in the firmware where I encountered an I2C timeout so perhaps there is some more depth to that issue and my fix was only circumstantial.

This is how I did mine:

uint8_t WrMulti(
	VL53L5CX_Platform *p_platform,
	uint16_t RegisterAddress,
	uint8_t *p_values,
	uint32_t size)
{
	uint8_t status = 255;
	uint8_t *reg;
	reg = &RegisterAddress;
	RegisterAddress = ((RegisterAddress << 8) & 0xff00) | ((RegisterAddress >> 8) & 0x00ff);
 
	status = i2c_write(p_platform->i2c_dev, reg, 2U, p_platform->address);
	if (status)
	{
		printf("\nWrMulti: Failed to write reg: %d\n", status);
	}
	status = i2c_write(p_platform->i2c_dev, p_values, size, p_platform->address);
	if (status)
	{
		printf("\nWrMulti: Failed to write bytes: %d\n", status);
	}
 
	return status;
}

Thanks,

Jacob

Somewhere in the driver (I don't recall where exactly, should be in nrf i2c driver), there is a limit on the amount of data that you can transmit via I2C. Or rather, the driver functions somewhere use a uint8_t size (so I guess the limit is 256 even though I used 258 in below, not sure why anymore). Best to step through the code to verify where the amount of transmit or receive bytes is clipped.

Let me know if that helps. I don't have any hardware available right now so I can't confirm anything.

#define MAX_I2C_TX_SIZE 258
uint8_t writeBuf_pd[MAX_I2C_TX_SIZE];
#define MAX_I2C_RX_SIZE 128
uint8_t readBuf_pd[MAX_I2C_RX_SIZE];
 
uint8_t VL53L5CX_i2c_writeMultipleBytes(uint16_t registerAddress, uint8_t *buffer, uint16_t bufferSize)
{
    // Chunk I2C transactions into limit of 32 bytes (or wireMaxPacketSize)
    uint8_t i2cError = 0;
    uint32_t bytesToSend = bufferSize;
    uint16_t offset = 0;
    while (bytesToSend > 0 && i2cError == 0)
    {
        uint32_t len = bytesToSend;
        if (len > (MAX_I2C_TX_SIZE - 2)) // Allow 2 byte for register address
            len = (MAX_I2C_TX_SIZE - 2);
        
 
        writeBuf_pd[0] = registerAddress>>8;
        writeBuf_pd[1] = registerAddress & 0xff;
        memcpy(&(writeBuf_pd[2]), &(buffer[offset]), len);
 
        i2cError = i2c_write(dev_i2c, writeBuf_pd, len+2, VL53L5_DEFAULT_I2C_ADDR);
 
        bytesToSend -= len;
        registerAddress += len; // Move register address forward
        offset += len;
    }
    if(i2cError) {
      printk("i2c multiwrite error %d\n", i2cError);
    }
    return (i2cError);
}
 
uint8_t VL53L5CX_i2c_readMultipleBytes(uint16_t registerAddress, uint8_t *buffer, uint16_t bufferSize) {
 
    int i2cError = 0;
    uint32_t bytesToReceive = bufferSize;
    uint32_t offset = 0;
    while (bytesToReceive > 0 && i2cError == 0)
    {
      uint16_t len = bytesToReceive;
      if ( len > MAX_I2C_RX_SIZE) {
        //printk("reduced %d bufferSize ... %d\n", bufferSize, len);
        len = MAX_I2C_RX_SIZE;
      }
 
      writeBuf_pd[0] = registerAddress>>8;
      writeBuf_pd[1] = registerAddress & 0xff;
      i2cError = aggr_i2c_write_read(dev_i2c, VL53L5_DEFAULT_I2C_ADDR, writeBuf_pd, 2, &buffer[offset], len);
      offset += len;
      registerAddress += len;
      bytesToReceive -= len;
      if(i2cError) {
        printk("i2c multiread error %d\n", i2cError);
      }
    }
 
    return (0); // Success
}

Thanks that helps a lot, I will look into that. No worries about the hardware, do you recall if there was a way to increase the tx buffer size or did you have to transmit the firmware in sections? Also I believe those extra two bytes are for the register address.

I did not investigate if it was possible to increase the tx buffer size: that would require to look into the drivers and I always prefer to stick to the authentic drivers i.o. going for my own changes unless strictly required.

In fact, the "MAX_I2C_TX_SIZE" of 258 might not make sense at all, maybe you could try with 128 for both tx and rx. I should be able to re-verify this in a few days from now.

@Community member​ did you get it to work?

I could not find the place where there is a limit on I2C TX size, 258 should still work, just like e.g. 128.

Hey sorry for the late reply I was away last week.

Not yet, I followed the method you did and it solved some issues for me, however I am unable to figure out how to get rid of the start bit before the data on a sequential write. How did you manage to do this?0693W00000Nqy6jQAB.pngI am getting a S|ADDRESS[0:7] before the data

Hi,

Fair point, I didn't even pay that much attention to the figure. The figure is actually wrong IMO. It's a bit like a copy from the read function, but the "P" stop condition at the end of the line should not be there.

In fact, a sequential write is always just a full write procedure, where the first transmitted byte is the address+R/W, the second and third byte in this case are the register index, followed by the data to write. so this should just map onto the "i2c_write" function in i2c.h

I just implemented it in the standard way as you mentioned but I am still getting that initial timeout from this thread. Not sure why it's not working.