cancel
Showing results for 
Search instead for 
Did you mean: 

VL53L5CX address changes not working.

FY
Visitor

I am trying to run multiple VL53L5CX-TOF-sensors with a single Pi Pico to be able to stitch together multiple of the sensor images.However for this to work I have to change the i2c addresses of the sensors.

I am trying to use the set_i2c_address function for this.

I have read the steps from the usage guide about enabling/disabling additional sensors on the same i2c bus via the LPn pin but whenever I try to call the set_i2c_address even with just a single sensor connected I get  RuntimeError: VL53L5CX: set_i2c_address error.

Currently I am using the Pimoroni Firmware that provides a driver accessible via micropython that just calls the ULD firmware / driver for the VL53L5CX. 


I am not sure if something about my approach/order is wrong or if there might be an issue with the ULD driver itself.

I would greatly appreciate any help/advise. This is the code I am currently using:

 

 

 

import pimoroni_i2c
import breakout_vl53l5cx
import time
from time import sleep
import machine

PIN_CONFIG_1 = {"sda": 6, "scl": 7}
#The following 2 lines are necessary if LPN is connected to the sensor.
#When there is no connection between a GPIO and LPN of the sensor this and the following line are not required.
#LPN would be needed to activate/decactivate when there are multiple devices on one i2c bus. 
lpn_pin = machine.Pin(10, machine.Pin.OUT) 
lpn_pin.value(1)  # Enable sensor_1

time.sleep(3) #wait a long duration in case the sensor takes a long time to start. 

i2c_1 = pimoroni_i2c.PimoroniI2C(**PIN_CONFIG_1, baudrate=400_000) #same error with baud rate at 100k, 400k and 2_000k
print("I2C_1 devices found:", i2c_1.scan())

# Initialize sensor_1 with default address
sensor_1 = breakout_vl53l5cx.VL53L5CX(i2c_1)

# Change to a new 7-bit address (e.g., 0x2A)
new_i2c_address_7bit = 0x09  # Valid 7-bit address (0x00 to 0x7F)
sensor_1.set_i2c_address(new_i2c_address_7bit) #this always throws the error.

# Verify address change
print("Scanning I2C after address change:", i2c_1.scan())

# Continue with configuration...
sensor_1.set_resolution(breakout_vl53l5cx.RESOLUTION_8X8)
sensor_1.set_ranging_frequency_hz(30)
sensor_1.start_ranging()

while True:
    if sensor_1.data_ready():
    avg_distance_1 = sensor_1.get_data().distance_avg
    avg_reflectance_1 = sensor_1.get_data().reflectance_avg 
    print(f"Sensor 1 Avg Distance: {avg_distance_1:.2f} mm, Avg Reflectance: {avg_reflectance_1:.2f}")
       sleep(1)

 

 

Edit: As I thought my issue might lie with the fact that I initialize the sensor before attempting to change the address I implemented the set_i2c_address function myself now using the ULD driver as inspiration. However even with this the address doesn't seem to get changed and stays at 0x52 (0x29 as a 7 bit due to the bitshift or 41 in decimal):

 

MPY: soft reboot
Available i2c before  attempting address change [41]
Tried to change I2C address from 41 to 32
Available i2c after address change [41]
Available i2c devices after attempting address change [41]
Traceback (most recent call last):
  File "<stdin>", line 44, in <module>
RuntimeError: VL53L5CX: init error

 

This is the code I used for the approach to change the address before initializing the sensor:

 

import pimoroni_i2c
import time
import machine
import breakout_vl53l5cx


# Function to change the I2C address
def vl53l5cx_set_i2c_address(i2c, old_address, new_address):

    i2c.writeto_mem(old_address, 0x7fff, bytes([0x00]))
    time.sleep(1)
    i2c.writeto_mem(old_address, 0x04, bytes([(new_address << 1)]))
    time.sleep(1)
    i2c.writeto_mem(old_address, 0x7fff, bytes([0x02]))  #I believe this might need to be new_address but that results in [Errno 5] EIO as the address isn't actually changed before.
    time.sleep(1)
    print(f"Tried to change I2C address from {old_address} to {new_address}")
    print("Available i2c after address change", i2c_1.scan())
    

# Configuration
PIN_CONFIG_1 = {"sda": 6, "scl": 7}
#The following 2 lines are necessary if LPN is connected to the sensor.
#When there is no connection between a GPIO and LPN of the sensor this and the following line are not required.
#LPN would be needed to activate/decactivate when there are multiple devices on one i2c bus.
lpn_pin = machine.Pin(10, machine.Pin.OUT)
lpn_pin.value(1)  # Enable sensor_1
time.sleep(3) #wait a long duration in case the sensor takes a long time to start. 



i2c_1 = pimoroni_i2c.PimoroniI2C(**PIN_CONFIG_1, baudrate=2_000_000)
default_address = 0x29 # default 7 bit address, shifted from 0x52, is 41 in decimal. 
new_i2c_address_7bit = 0x20  # Example: new address

print("Available i2c before  attempting address change", i2c_1.scan())

# Change the I2C address BEFORE initializing the sensor
vl53l5cx_set_i2c_address(i2c_1, default_address, new_i2c_address_7bit)
print("Available i2c devices after attempting address change", i2c_1.scan()) 

# Initialize the sensor with the new address 
sensor_1 = breakout_vl53l5cx.VL53L5CX(i2c_1, new_i2c_address_7bit )  
   # this fails to initialize. Makes sense as the address wasn't changed. When using default_address here it still connects to the sensor just fine. 

# Verify address change
print("Scanning I2C after address change:", i2c_1.scan())

# Continue with sensor configuration
sensor_1.set_resolution(breakout_vl53l5cx.RESOLUTION_8X8)
sensor_1.set_ranging_frequency_hz(30)
sensor_1.start_ranging()

while True:
    if sensor_1.data_ready():
        data = sensor_1.get_data()
        avg_distance_1 = data.distance_avg
        avg_reflectance_1 = data.reflectance_avg
        print(f"Sensor 1 Avg Distance: {avg_distance_1:.2f} mm, Avg Reflectance: {avg_reflectance_1:.2f}")
        time.sleep(1)

 

 I would really appreciate any hints to what I am doing wrong.

1 ACCEPTED SOLUTION

Accepted Solutions
John E KVAM
ST Employee

I'm not familiar with that code, but I'm going to make some guesses.

the lines:

# Initialize sensor_1 with default address
sensor_1 = breakout_vl53l5cx.VL53L5CX(i2c_1)

# Change to a new 7-bit address (e.g., 0x2A)
new_i2c_address_7bit = 0x09  # Valid 7-bit address (0x00 to 0x7F)
sensor_1.set_i2c_address(new_i2c_address_7bit) #this always throws the error.

seem problematic. 

One must send the new address to the device at the old address. 

So if you initialize the sensor with:

sensor_1 = breakout_vl53l5cx.VL53L5CX(i2c_1)

Then you would have to change the address with something like:

sensor_1.set_i2c_address(i2c_1,new_i2c_address_7bit)

So you are talking to the current address (i2c_1) and sending the command to change it to new_i2c_address-7bit)

I think you were heading in the right direction with your last bit of code. 

Also, I'm not a big fan of small i2c addresses. I'd suggest going higher than lower. 0x39 and 0x49 are what I use.

(Might just be superstition on my part though.)


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.

View solution in original post

2 REPLIES 2
John E KVAM
ST Employee

I'm not familiar with that code, but I'm going to make some guesses.

the lines:

# Initialize sensor_1 with default address
sensor_1 = breakout_vl53l5cx.VL53L5CX(i2c_1)

# Change to a new 7-bit address (e.g., 0x2A)
new_i2c_address_7bit = 0x09  # Valid 7-bit address (0x00 to 0x7F)
sensor_1.set_i2c_address(new_i2c_address_7bit) #this always throws the error.

seem problematic. 

One must send the new address to the device at the old address. 

So if you initialize the sensor with:

sensor_1 = breakout_vl53l5cx.VL53L5CX(i2c_1)

Then you would have to change the address with something like:

sensor_1.set_i2c_address(i2c_1,new_i2c_address_7bit)

So you are talking to the current address (i2c_1) and sending the command to change it to new_i2c_address-7bit)

I think you were heading in the right direction with your last bit of code. 

Also, I'm not a big fan of small i2c addresses. I'd suggest going higher than lower. 0x39 and 0x49 are what I use.

(Might just be superstition on my part though.)


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.

Thanks for the help.
The last part I posted was like you wrote actually quite close to working. I needed to modify one part about the address shifting and had to specify a 2 byte length for the memory writes. Thanks for the advise about going higher with my i2c-addresses.

In case somebody else comes across this post: Here is a working version I cleaned up a bit that supports 2 sensors and easily allows the addition of more sensors all with their own specified i2c-addresses.

import pimoroni_i2c
import time
import machine
import breakout_vl53l5cx

# Function to change the I2C address
def vl53l5cx_set_i2c_address(i2c, old_address, new_address):
    # Unlock the sensor's I2C address change functionality
    i2c.writeto_mem(old_address, 0x7fff, bytes([0x00]), addrsize=16)
    # Write the new I2C address 
    i2c.writeto_mem(old_address, 0x04, bytes([(new_address)]), addrsize=16)
    # Lock the sensor's I2C address change functionality
    i2c.writeto_mem(new_address, 0x7fff, bytes([0x02]), addrsize=16)
    time.sleep(1)
    
    print(f"Changed I2C address from {hex(old_address)} to {hex(new_address)}")
    print("Available I2C devices after address change:", i2c.scan())

# Configuration
PIN_CONFIG = {"sda": 6, "scl": 7}
I2C_BAUDRATE = 2_000_000
DEFAULT_ADDRESS = 0x29  # Default 7-bit address (0x52 shifted right by 1)

# Sensor configuration
SENSORS = {
    "sensor_1": {
        "lpn_pin": machine.Pin(10, machine.Pin.OUT),
        "new_address": 0x40,
    },
    "sensor_2": {
        "lpn_pin": machine.Pin(11, machine.Pin.OUT),
        "new_address": 0x50,
    },
}

# Initialize I2C
i2c = pimoroni_i2c.PimoroniI2C(**PIN_CONFIG, baudrate=I2C_BAUDRATE)

# Disable all sensors initially
for config in SENSORS.values():
    config["lpn_pin"].value(0)

# Initialize and configure sensors
sensors = {}
for name, config in SENSORS.items():
    # Disable all sensors except the one being configured
    for sensor_name, sensor_config in SENSORS.items():
        sensor_config["lpn_pin"].value(1 if sensor_name == name else 0)
    time.sleep(3)  # Wait for the sensor to stabilize

    # Change the I2C address
    vl53l5cx_set_i2c_address(i2c, DEFAULT_ADDRESS, config["new_address"])

    # Initialize the sensor
    sensors[name] = breakout_vl53l5cx.VL53L5CX(i2c, config["new_address"])
    sensors[name].set_resolution(breakout_vl53l5cx.RESOLUTION_8X8)
    sensors[name].set_ranging_frequency_hz(30)
    sensors[name].start_ranging()

    print(f"{name} initialized with address {hex(config['new_address'])}")

# Enable all sensors after configuration
for config in SENSORS.values():
    config["lpn_pin"].value(1)
time.sleep(3)  # Wait for all sensors to stabilize

# Main loop to read sensor data
while True:
    for name, sensor in sensors.items():
        if sensor.data_ready():
            data = sensor.get_data()
            avg_distance = data.distance_avg
            avg_reflectance = data.reflectance_avg
            print(f"{name} - Avg Distance: {avg_distance:.2f} mm, Avg Reflectance: {avg_reflectance:.2f}")
    time.sleep(1)