Using a PiicoDev Distance Sensor with an I2C address translator

I can’t get the PiicoDev VL53L1X Distance Sensor (PiicoDev Distance Sensor VL53L1X - Raspberry Pi Pico Guide - Tutorial Australia) to work with an Adafruit LTC4316 I2C Address Translator (Adafruit LTC4316 I2C Address Translator - Stemma QT / Qwiic | ADA5914 | Core Electronics Australia) with Python 3 on a Raspberry Pi Zero 2 W or a Raspberry Pi Pico. I’m using this translator so that I can have two of these sensors connected at the same time (they have a fixed I2C address of 0x29). It’s possible to change the device address by software, but a pin on the IC must be asserted while doing this which isn’t convenient with the PiicoDev module. I’m using the PiicoDev library, the device file is PiicoDev_VL53L1X.py.

With one device connected directly and one connected via the address translator (with the default switch settings which flips only address bit A6) the first sensor initialises at 0x29 but the second fails to initialise at 0x69 (0x29 XOR’d with 0100 0000 - but 6 inverted). The error I get is:

Traceback (most recent call last):
File “”, line 1, in
File “…/PiicoDev VL53L1X.py”, line 114, in init
raise RuntimeError(‘Failed to find expected ID register values. Check wiring!’)
RuntimeError: Failed to find expected ID register value
5. Check wiring!

The ID value being returned from the call to self.read_model_ID() is not the expected value of 0xEACC.

I made a copy of PiicoDev_VL53L1X.py from Github and added a print statement ahead of this test to see what the ID value is, plus also commenting out the raise exception line. Using this version shows that 0xEACC (60108) is returned without the translator but 0x0F0F (3855) is returned when the translator is inline. These patterns don’t seem relayed in an obvious way (inverted, byte swapped…) so perhaps a different register is being read?

PiicoDev_VL53L1X.read_model_ID() seems to be misbehaving when address bit 6 is inverted. I thought maybe the device would still work despite the incorrect ID but when I tested it with the modified library code and the code from the Raspberry Pi guide (PiicoDev Distance Sensor VL53L1X - Raspberry Pi Pico Guide - Tutorial Australia) the distance returned is fixed at 35209 mm. Looks like reading data is affected by address translation as well.

I switched the modules across to a Raspberry Pi Pico and tried the same code. Same result - works without the address translator but not with it:
Traceback (most recent call last):

  • File “”, line 1, in *
  • File “PiicoDev_VL53L1X.py”, line 115, in init*
    RuntimeError: Failed to find expected ID register values. Check wiring!

I’ve connected the sensors in different ways and swapped around sensors and cables with no joy; there seems to be something amiss with the library code when the address translator is inline. I can’t find any sign in the device library code of the address being hard coded or calculated that might fall over with a translated address. I haven’t looked at the PiicoDev Unified code yet. I’m studying the code and the VL53L1X data sheet (https://www.st.com/resource/en/datasheet/vl53l1x.pdf)) but perhaps somebody more familiar with the code and device can spot the problem.

I will be using PiicoDev 3 axis accelerometer modules (PiicoDev 3-Axis Accelerometer LIS3DH | Core Electronics Australia) with the address translator as well. These aren’t working with the address translator either but I have not investigated these yet.

I also have an Adafruit PCA9548 8-Channel STEMMA QT / Qwiic I2C Multiplexer (Overview | Adafruit PCA9548 8-Channel STEMMA QT / Qwiic I2C Multiplexer | Adafruit Learning System) which works differently, which I haven’t tried yet. I see that the VL53L1X uses different addresses for read and write (address LSB is different) so this device might not work.

2 Likes

Are you sure that Adafruit LTC4316 I2C Address Translator - Stemma QT / Qwiic | ADA5914 is compatible with piicodev sensors?

1 Like

Good question. I believe it could be compatible - I’m using the address translator for the purpose it was designed for, and the hardware interface is compatible (3.3 V I2C and JST-SH connectors) - the device logic level conforms to the supply voltage it’s given and I’m powering it through the I2C PiicoDev cable. It is also directional, and I’ve taken care with that.

It seems to be a software issue - that the library code has not been developed with this use case in mind. If that’s the case, then a change to the Python library code might resolve this. If there’s something more fundamental then I’ll add another microcontroller.

Adafruit outline some issues in using this translator as follows (Adafruit LTC4316 I2C Address Translator [Stemma QT / Qwiic] : ID 5914 : Adafruit Industries, Unique & fun DIY electronics and kits):
While this chip is magical, there’s a few things to watch for: it doesn’t seem to support clock-stretching so not for funky chips like BNO055. Just because you can change the address on the fly, doesn’t mean the drive supports it! Some firmware is expecting a specific address and it may not be trivial to change the address. Check the driver to make sure you know how to change the address, to the new value.

1 Like

It certainly should be! Addresses are translated at the hardware level so you ought to be able to get started by just defining the correct downstream-device address. There should be no need to modify the PiicoDev_VL53l1X.py file for this purpose.

Hi everyone! :smiley: I played a part in the design, delivery and education for this sensor. I’m really curious to see how the LTC4316 can integrate into your PiicoDev project for the exact purpose you’re looking at @Peter266808 - it’s like a zero-code way to add more modules to a bus and I’m stoked for that. It could solve a big constraint for multi-device PiicoDev projects.

I arrived at exactly the same outcome as you @Peter266808, :thinking: my working shown below…
What does a scan yield? Perhaps you and I are just off-by-one with our address logic?
eg. on a Pico

from machine import I2C, Pin
i2c=I2C(0, sda=Pin(8), scl=Pin(9)) 
print(i2c.scan())

Example working

The device upstream of the translator can be initialised as ‘normal’

sensorA = PiicoDev_VL35L1X() # address 0x29

and the downstream sensor will be initialised with the translated address - whatever you calculate that to be using the translator:

sensorB = PiicoDev_VL53L1X(address = translated_address) # whatever address you define

Working off Adafruit’s example…

If both DIP switches are ON, then only A6 is flipped.

:point_up_2: A6 is 0b0100 0000: the bit with value 64_{d}, expressed as 0x40 in Hexadecimal
So you could try using the device with both DIP switches ON, flipping A6 for the downstream device. That’s the same as XOR logic:

0x29 XOR 0x40 = 0x69

Which gives your downstream device an adjusted address of 0x69. Your initialisation code would be as follows. I’m explicitly defining the upstream device now for clarity rather than relying on defaults

sensorA = PiicoDev_VL35L1X(address = 0x29) # upstream
sensorB = PiicoDev_VL53L1X(address = 0x69) # downstream device

I would have expected this to work, as you did… but something else must be going on…

2 Likes

What an interesting device. The LTC4316 uses precision value resistors to change the bit in the I2C address. IMHO not the best way to do it, resistor tolerance and value can change with environmental conditions, age, etc.
Adafruit provide no schematic as the how they get it to change 3 address bits with the resistor values seen in the pics from their web site. Therefore, its a little hard to work out which address bit may actually be affected. They state A6, A5 & A4.

As two people have tried to get it to work unsuccessfully the conclusion could be the device does not work. Maybe its design is wrong. A read of the Linear Technology datasheet would be worth while, the resistor combinations are shown.

On the device there are a 120K, 280K, 86k6, and a couple of 10k & 100k. I don’t see how they get these values to match the table from the datasheet (below). If I was trying to get this device to work this would be a big red flag to me. Then I would try to determine the circuit diagram by visual examination and continuity testing. I would want to confirm the circuit will actually do what Adafruit say it will do.

Anyway, this little exercise had been interesting to me, thanks for posting, probably would not buy this device to do address translation.

EDIT: Found a schematic, from what I have calculated related to A6,A5,A4 and the four DIP switch positions; only 111 101 are within the XORH voltage range.Adafruit should have used the values from the table to get the right ratios.Also connecting resistors in parallel through a DIP switch often does not produce the resistance you want when you want something fairly accurate.

EDIT EDIT: I recalculated the voltage ratios for the XORH pin against the resistor values used on the Adafruit board and compared with the datasheet table. The situation with both dip switches ON is out by 0.00268 (range 0.29625 to 0.26625, calculated value 0.29893). The other 3 are within the ranges needed. I have more confidence the board should work now.

I have ordered one of these devices to do testing myself. 2 week delay on device delivery. The detection of address 0x40 by the scan routine intrigues me. The scan is pretty basic in micropython; writes to the address and checks for a low on the SDA line. If low it assumes device detection.

Regards
Jim

image

Yes it does work James46717 - I am seeing devices in a bus scan at the expected, translated addresses. I’m not using the resistor method with the LTC4316 , I’m using the default translation with the two switches on and no resistor which inverts the MSB of the 7 bit address, bit 6. The two switches on the LTC4316 and the optional resistor offer further translation options, but I’m not using these.

Yes I did do an address scan @Michael, and confirmed the translated device was appearing at 0x69 (0x29 untranslated).

I connected some other PiicoDev modules, daisy chained to a Pico, and did an address scan with and without the translator. These are the modules I used:

  • Button (default address 0x42, translated address 0x02)
  • Pressure sensor MS5637 (default address 0x76, translated address 0x36)
  • Atmospheric Sensor BME280 (default address = 0x77, translated address 0x37)
  • Precission Temperature TMP117 (default address 0x48, translated address 0x08)
  • Ambient Light Sensor VEML6030 (default address 0x10, translated address 0x50)
  • OLED SSD1306 (default address 0x3C, translated address 0x7C)

Without the translator a scan found: [‘0x10’, ‘0x3c’, ‘0x42’, ‘0x48’, ‘0x76’, ‘0x77’] and all devices worked.

With the translator a scan found: [‘0x8’, ‘0x36’, ‘0x37’, ‘0x40’, ‘0x50’] and no devices worked. This indicates that the devices are responding on their default address which is being translated by the LTC4316. Something odd though, with 0x40 appearing and 0x7C missing.

In continuing to investigate, I’m looking for other drivers to work with any of these modules, using Micropython or Arduino (with a level 3.3 V - 5 V translator where necessary) to demonstrate that they can work with the LTC4316, to remove the PiicoDev library from the equation. I’m writing code to interact directly via I2C, at a lower level; and I’m examining the I2C bus with SigRok and a Raspberry Pi Pico as a logic probe.

Peter

3 Likes

@Peter266808 Thanks for providing the scan information.

I put your results into a table so as to see it more clearly.
Most PiicoDev devices use a ATtiny1616 to interface to the I2C bus and whatever sensor is being used. The OLED and distance sensor do not use the ATtiny1616. The button does but it seems to have changed bit 2 not bit 6.

I assume this means the devices were seen in a scan but did not work when functionally tested.
Whatever code is in the ATtiny1616 might be stopping them working. This code is set during manufacture and cannot be changed by the user. (Core Electronics would have more information on this, I might not be 100% correct)

I have found an I2C scan will sometimes show devices connected but when trying to access them functionally they do not work. This has been very rare, in one case it related to the Python library code I was creating. The device has C++ Arduino drivers but no Python. In another case it was due to too many pullups or not enough.

Regards
Jim

Thanks for posting your troubleshooting steps @Peter266808 - it’s really helpful and I would have done similarly.
I’ll perform my own investigation too, but the part is currently on backorder so I’ll have to wait for it to be delivered.

Reserved Addresses

I2C actually has a pool of reserved address spaces. 0x00 → 0x07 all have some esoteric function, and 0x78 → 0x7F are reserved for 10-bit addressing (:exploding_head:) and future upgrade use presumably.
Be careful with translated addresses that fall into these pools, like 0x02 - they’re unlikely to be handled correctly. Even so, I would have expected no problems from the other devices.

A stop-gap: MUX

I’ve explored creating a PiicoDev MUX to solve this kind of problem - and the product is actually “close” to completion. It just requires all the assembly and guides which represents quite a bit of work :sweat_smile:
However, while incomplete, the code is compatible with an existing MUX product from Adafruit (it uses the same chip!). If you find that the address translator is intractible, you may like to take a look at the MUX alternative. In fact, during development, I was using the Adafruit unit to develop the PiicoDev code while I waited for my prototype PCBs to arrive… and the test case was to drive 4x Laser Distance Sensors :slight_smile:

2 Likes

Thanks Jim, that table is helpful :slight_smile:

After experimenting with entering commands manually at the Thonny console to communicate with the (PiicoDev Ambient Light Sensor VEML6030 | Core Electronics Australia) I wrote this script:

# read_I2C_device_IDs.py
#
#
from machine import I2C

i2c = I2C(freq=400000, id=0)
print("I2C devices found")
print(i2c.scan())
print([hex(a) for a in i2c.scan()])
print()
print("Reading device IDs:")
print()

try:
    print("Ambient Light sensor at 0x10 (normal), ID = ", str(i2c.readfrom_mem(0x10, 7, 1)))
except:
    try:
        print("Ambient Light sensor at 0x50 (translated), ID = ", str(i2c.readfrom_mem(0x50, 7, 1)))
    except:
        print("Ambient Light sensor not found")

With the (PiicoDev Ambient Light Sensor VEML6030 | Core Electronics Australia) connected directly to the Pico I get this result:

I2C devices found
[16]
['0x10'']

Reading device IDs:

Ambient Light sensor at 0x10 (normal), ID =  b'\x81'

With the (Adafruit LTC4316 I2C Address Translator - Stemma QT / Qwiic | ADA5914 | Core Electronics Australia) in series I get this result:

I2C devices found
[80]
[''0x50']

Reading device IDs:

Ambient Light sensor at 0x50 (translated), ID =  b'\x81'

In both cases the device ID is the same and is correct per the VEML6030 datasheet (https://www.vishay.com/docs/84367/designingveml6030.pdf). This demonstrates that a simple device like the (PiicoDev Ambient Light Sensor VEML6030 | Core Electronics Australia) can be accessed with the (Adafruit LTC4316 I2C Address Translator - Stemma QT / Qwiic | ADA5914 | Core Electronics Australia) in series translating its address. Next I’ll check some other devices, then I’ll compare what happens on the I2C bus with simple code like this compared to with the PiicoDev Unified library.

Nice that you’re working on a new device @Michael. PiicoDev is a vibrant community indeed. The limitation in device numbers due to address clashes is certainly a constraint to be overcome in applying PiicoDev devices. I’m curious what functionality you’ll develop compared to the existing (Adafruit LTC4316 I2C Address Translator - Stemma QT / Qwiic | ADA5914 | Core Electronics Australia) and others like the (Adafruit PCA9548 8-Channel STEMMA QT / Qwiic I2C Multiplexer - TCA9548A Compatible | ADA5626 | Core Electronics Australia). One thought bubble is that an addressable translator like (Adafruit PCA9548 8-Channel STEMMA QT / Qwiic I2C Multiplexer - TCA9548A Compatible | ADA5626 | Core Electronics Australia) could switch an address back and forth before and after accessing a particular device, so as to be completely flexible - especially if this was integrated with the unified library. To make this scalable to many devices would need separation between output connections (so that multiple devices on the same address aren’t in contention) hence perhaps a larger format board with more connectors that could be daisy chained to add more outputs. How would this improve on (Adafruit PCA9548 8-Channel STEMMA QT / Qwiic I2C Multiplexer - TCA9548A Compatible | ADA5626 | Core Electronics Australia) , I’m wondering.

Peter

2 Likes

I’ve got the (PiicoDev Ambient Light Sensor VEML6030 | Core Electronics Australia) and the (PiicoDev Precision Temperature Sensor TMP117 | Core Electronics Australia) working with the (Adafruit LTC4316 I2C Address Translator - Stemma QT / Qwiic | ADA5914 | Core Electronics Australia) now, using plain MicroPython and the machine.I2C module (without the PiicoDev library) as follows:

# read_light_and_temperature.py

from machine import I2C
import time

i2c = I2C(freq=400000, id=0)
print("I2C devices found")
print(i2c.scan())
print([hex(a) for a in i2c.scan()])
print()
print("Reading device IDs:")
print()

try:
    print("Ambient Light sensor at 0x10 (normal), ID = ", str(i2c.readfrom_mem(0x10, 7, 1)))
    addrLight = 0x10
except:
    try:
        print("Ambient Light sensor at 0x50 (translated), ID = ", str(hex(i2c.readfrom_mem(0x50, 7, 1)[0])))
        addrLight = 0x50
    except:
        print("Ambient Light sensor not found")
try:
    print("Precision Temperature sensor at 0x48 (normal), ID = ", str(i2c.readfrom_mem(0x48, 0x0F, 2)))
    addrTemp = 0x48
except:
    try:
        ID = i2c.readfrom_mem(0x08, 0x0F, 2)
        print("Precision Temperature sensor at 0x08 (translated), ID = ", str(hex(int.from_bytes(ID, 'big'))))
        addrTemp = 0x08
    except:
        print("Precision Temperature sensor not found")
print("Light          Temp")

# Initialize Ambient Light sensor:
# gain:1x, integration 100ms, persistence 1, disable interrupt
i2c.writeto_mem(addrLight, 0x00, b'\x00')
#

for i in range(10):
    light = int.from_bytes(i2c.readfrom_mem(addrLight, 0x04, 2), 'little')*0.0576
    tempDataRaw = int.from_bytes(i2c.readfrom_mem(addrTemp, 0x00, 2), 'big')
    if tempDataRaw >= 0x8000:
        temperature = -256.0 + (tempDataRaw - 0x8000) * 7.8125e-3 # One LSB equals 7.812 mdegC
    else:
        temperature = tempDataRaw * 7.8125e-3 # One LSB equals 7.812 mdegC
    print(str(light) + " lux", str(temperature) + " C")
    time.sleep(1)

The output from this code without the translator is:

I2C devices found
[16, 72]
[‘0x10’, ‘0x48’]

Reading device IDs:

Ambient Light sensor at 0x10 (normal), ID = b’\x81’
Precision Temperature sensor at 0x48 (normal), ID = b’\x01\x17’
Light Temp
2.8224 lux 22.14844 C
2.8224 lux 22.14844 C
2.8224 lux 22.14844 C
2.7648 lux 22.15625 C
2.8224 lux 22.15625 C

The output from this code with (Adafruit LTC4316 I2C Address Translator - Stemma QT / Qwiic | ADA5914 | Core Electronics Australia) in line:

I2C devices found
[8, 64, 80]
[‘0x8’, ‘0x40’, ‘0x50’]

Reading device IDs:

Ambient Light sensor at 0x50 (translated), ID = 0x81
Precision Temperature sensor at 0x08 (translated), ID = 0x117
Light Temp
0.0 lux 21.57031 C
6.7968 lux 21.53906 C
6.8544 lux 21.53125 C
6.8544 lux 21.51563 C
6.6816 lux 21.48438 C

I borrowed some code from the PiicoDev device drivers to scale the sensor data. This code gives the same output as the PiicoDev demo code when the translator isn’t in line. It is odd that an extra address (0x40) shows up in the scan with the translator present. It’s not the translator or the Ambient Light sensor, it only shows up when the Precision Temperature sensor is connected via the translator. The untranslated address would be a reserved one - maybe I2C library doesn’t show those in a scan.

So this confirms that these devices can work with the address translator. The (PiicoDev Laser Distance Sensor VL53L1X | Core Electronics Australia) and (PiicoDev 3-Axis Accelerometer LIS3DH | Core Electronics Australia) are slightly more complicated but with luck they will submit to the same approach.

My original query is resolved in so far as I’m back to developing my application but I’ll keep trying to understand what is happening with the PiicoDev library code, and look forward to your further creative output with device ideas @Michael.

Peter

3 Likes

Very interesting! I can see you’re using the MicroPython readfrom_mem() method for bus transactions in your test code - exactly like PiicoDev does…

I’m pretty stumped why there is any difference for now, but I’m glad your project is back on track @Peter266808 - great split testing :smiley:

1 Like

The Adafruit LTC4316 arrived yesterday, so I did some testing with the different types of PiicoDev modules, I have (15). Using the standard files provided by Core electronics I got every sensor to work with address translation except the Servo module.

When the TMP117 and the Servo modules were scanned with micropython i2c.scan(), an extra address was detected. More than one for the Servo module on 3 of the translation states. It also produced an extra address without the translator.

The following from the micropython documentation. The scanner is pretty basic.
I2C.scan()
Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of those that respond. A device responds if it pulls the SDA line low after its address (including a write bit) is sent on the bus.

I have looked at the circuits and cannot figure why they would be producing an extra address. I have to assume the module is doing it because when not connected the scan is correct.

Anyway … cheers
Jim

3 Likes

That sounds like the device is including special handling for the reserved I2C addresses. The recommended protocol for a translator is that when it detects a device with a reserved address it does a translation on the assumption that the device address has been set in error, but it passes through the actual device address in case that is actually required. What address is the device configured as, and what address is it getting converted to?

1 Like

It is a reserved address that is being translated, or at least that’s what I’ve seen. I’ve seen 0x40 appear when using the Precision Temperature sensor with an address translator. This page: microcontroller - I2C Address 0x00 not supposed to be showing up - Electrical Engineering Stack Exchange explains what is happening:

Address 0 is a special address named the “general call address.” The basic idea is that any slave device on the bus can respond to this address. Not all devices actually implement this behavior, though. I’ve never tried to use it myself. I’m not sure how common it is for slaves to respond to it.

See section 3.1.13 of the I2C specification from NXP: https://www.nxp.com/docs/en/user-guide/UM10204.pdf

Is it 0x40 that you’re seeing Jim?

I’ve noticed that the reserved addresses don’t show up in the linux i2cdetect scan (which prints a little table mapping what has been detected) so we don’t see the untranslated 0x00 but do see the translated 0x40. I figure the Python libraries may behave the same.

Peter

1 Like

TMP117 address 0x48
Works ok, with and without translation.
A6 A5 A4 translated, scan reports.
0x38
0x70

A6 A4 translated, scan reports.
0x18
0x50

A6 A5 translated, scan reports.
0x28
0x60

A6 translated, scan reports.
0x08
0x40

Servo address 0x44
Works without translation does not work with translation.
No translation, scan reports and works.
0x44
0x70

A6 A5 A4 translated, scan reports and does not work.
0x34
0x70

A6 A4 translated, scan reports and does not work.
0x14
0x20
0x50

A6 A5 translated, scan reports and does not work.
0x24
0x60

A6 translated, scan reports. Address would be 0x04 which is not scanned
0x40
0x30

Test results.
Regards
Jim

3 Likes

Nice work Jim. The results for the TMP117 agree with the LTC4316 data and binary arithmetic (bold bits below are inverted by the translation):
A6, A5, A4 TX:
0x48 (100 1000) → 0x38 (011 1000)
0x00 (000 0000) → 0x70 (111 0000)

A6, A4 TX:
0x48 (100 1000) → 0x18 (001 1000)
0x00 (000 0000) → 0x50 (101 0000)

A6, A5 TX:
0x48 (100 1000) → 0x28 (010 1000)
0x00 (000 0000) → 0x60 (110 0000)

A6 TX:
0x48 (100 1000) → 0x08 (000 1000)
0x00 (000 0000) → 0x40 (100 0000)

The bit names above are:
(A6 A5 A6 A3 A2 A1 A0)
In the address word, A6 is actually Most Significant Bit - bit 7, because the LSB is the R/W indicator bit. (7-bit 8-bit and 10-bit I2C Slave Addressing - Total Phase) MicroPython ignores the R/W bit and treats the address word as if the bits are shifted to the right.

The second translated address shows up because the TMP117 is a sensor that responds to special address 0x00. The untranslated address 0x00 doesn’t appear in the bus scan because the application library used for the scanning code won’t report special addresses.

I’ve made progress with investigating the original issue with using PiicoDev devices with the LTC4316 address translator. I have the VL35L1X Distance Sensor with address translator working with the RPi Zero 2 W now and I don’t know yet what has changed to make it work - ‘could not duplicate’, in other words. But I have found during troubleshooting this that there are a few variables that can stop the code from working.

I decided to approach troubleshooting by testing the devices with an Arduino to rule out sensor behaviour as the problem, so I soldered a 5 V ↔ 3.3 V level shifter and a PiicoDev breadboard adapter onto an Arduino Mega prototyping shield and used that to connect PiicoDev sensors to the Mega. This is a useful setup for troubleshooting as well as making the PiicoDev hardware more accessible to use with Arduinos with less risk of damaging 3.3 V inputs. I’ve made the same mod to an Arduino Uno and to a Pico running Arduino code mounted on a Raspberry Pi Pico to Uno FlexyPin Adapter | Pimoroni | Core Electronics Australia (I didn’t need the level translator for this).

Using the Adafruit VL35L1X library I was able to use two VL35L1Xs with a LTC4316 address translator with the Arduino Mega. I tested next with a Raspberry Pi Pico, using MicroPython machine.I2C and PiicoDev_VL53L1X and both worked with the address translator. Then I tested with a Pico W and they didn’t work. This puzzled me until I discovered that apparently some versions of MicroPython default to different pins for the I2C bus for Pico and Pico W - from I2C broken on RPi Pico-w v1.20.0-50-g786013d46 (and previous 1.20.0) · micropython · Discussion #11429 · GitHub
For the RPi Pico (not W) running MicroPython v1.20.0 on 2023-04-26, the default pins seem to be

I2C Configuration: I2C(0, freq=399361, scl=5, sda=4, timeout=50000)
I2C Configuration: I2C(1, freq=399361, scl=7, sda=6, timeout=50000)


For the RPi Pico-W running MicroPython v1.20.0-50-g786013d46 on 2023-05-04, the default pins are the same as the non-W Pico.

I’m running MicroPython v1.23.0 on my Pico W and it has this issue. Once I discovered this I was able to get the code working on the Pico W by explicitly defining the pins for SCL and SDA:
i2c = I2C(freq=400000, id=0, sda=Pin(8), scl=Pin(9)).

While investigating this with commands typed at the Thonny console I also noticed what the linked page above said:
One thing I did notice is that the device seems to need a hard reset when switching pins. i.e. If I had it working, then … updated the code to use the new pins, it would not work until I did a hard reset. The scan worked, but the first write raised EIO.
The fix wouldn’t work at the command line until I knew this.

In summary MicroPython I2C code that works on a Pico may not work on a Pico W, but by explicitly defining the pin allocation for SCL and SDA it should work for both. This applies to the machine.I2C library but seems not to affect PiicoDev_VL53L1X. With MicroPython explicitly defining addresses and pins seems best while with Arduinos the app sets the pin defaults for the particular processor board so I leave them as default.

By the time I have the RPi Zero application I’m developing working I may understand what caused the original issue.

Peter

2 Likes

@Peter266808 Thanks for your detailed response. Glad you have it working.

With respect to the I2C default pin settings.
The Raspberry Pi Pico documentation states GP4 & GP5 as the default. Why the Micropython developers choose GP8 & GP9 in the original python development for the Pico is unclear.
Possibly they tried to fix this for the Pico W but it has only lead to more confusion. Defining the pins is the fail safe option.

The explanation for the extra addresses for the TMP117 makes a lot of sense. Possible this is what is happening for the Servo module.

Anyway, its been interesting for me.
Cheers
Jim

3 Likes

The curse of the early adopter :sweat_smile:
Story time!

*Big breath in*

When the Pico was originally announced there was a stable (enough) release of MicroPython ready to go. That version of MicroPython defined the default I2C bus as Bus0 on GP8,9 and so we started developing our application around that. A default was not prescribed in the Pico Datasheet (yet).

Jump forward several months and we have our PiicoDev Expansion board developed and are pretty heavily committed to our guides and videos. The RPi Foundation then released an updated datasheet which defines the default I2C to Bus0, GP5,6.
A bit of a shame there, but we’re committed. We took the MicroPython build as the authority on what would be used as default, but then it was updated to suit what RPi prescribed later.

In any case - If I could go back in time I would structure the PiicoDev guides to first initialise a unifying bus object (with explicit pin definitions), and pass that object to each module initialisation function.

Lesson learned: be explicit every time. There is some small gain in abstracting the setup away (for a first time user, it’s less syntax to look at) but the moment you want to go off and do your own thing its a little bit trickier to get on board, because you can’t just follow patterns that we otherwise could have established implicitly in code examples.

3 Likes