I2C.scan() returns nothing.

RP2040 based microcontroller boards running MicroPython.
Target audience: MicroPython users with an RP2040 boards.
This does not include conventional Linux-based Raspberry Pi boards.
User avatar
wittend
Posts: 8
Joined: Mon Aug 23, 2021 6:20 pm

I2C.scan() returns nothing.

Post by wittend » Wed Sep 22, 2021 9:16 pm

I'm trying to see the devices on the I2C bus on an AdaFruit QTPy RP2040. I know that there should be devices at 0x18 and 0x20:

Code: Select all

#==========================================================
# i2c-scan.py
#
#   Drive an i2c lcd display through an Adafruit MCP2040
# QT-PY 2040.  This file uses the MicroPython tools and
# was created in Thonny.
#
# Created: 	2021-09-15
#==========================================================
import rp2
import machine

lcdAddr = 0x72

# These all need to be used as a group or you get an error.
lcdBus0 = 0
sda0_pin = machine.Pin(8)
scl0_pin = machine.Pin(9)

# These all need to be used as a group or you get an error.
lcdBus1 = 1
sda1_pin = machine.Pin(6)
scl1_pin = machine.Pin(7)

print("hello")

i2c1 = machine.I2C(lcdBus1, scl=scl1_pin, sda=sda1_pin, freq=100000)
output = i2c1.scan()
print(output, len(output))

print("Done")
Output is:

>>> %Run -c $EDITOR_CONTENT
hello
b'123'
[] 0


Thanks,
Dave

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: I2C.scan() returns nothing.

Post by Roberthh » Thu Sep 23, 2021 5:55 am

If scan does not return to the device addresses, then there is a connection issue. Either with the wires, or with the baud rate. I2C.scan simply probes every address on the bus. And if it only receives NAKs, which is, bus stays high after the address bytes, then the list is empty.

fdufnews
Posts: 76
Joined: Mon Jul 25, 2016 11:31 am

Re: I2C.scan() returns nothing.

Post by fdufnews » Thu Sep 23, 2021 6:47 am

Are you sure there are pullup resistors on SDA and SCL signals?
AdaFruit QTPy RP2040 has none on either I2C0 or I2C1. So a pair of resistors shall be at least on one of the boards you are connecting, otherwise you 'll have to add them yourself.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: I2C.scan() returns nothing.

Post by Roberthh » Thu Sep 23, 2021 7:37 am

I was considering missing pull-up resistors as well. But in that case i2c.scan() typically reports all addresses as present, because the bus stays low after the last bit of the address, which is seen as an ACK.

User avatar
wittend
Posts: 8
Joined: Mon Aug 23, 2021 6:20 pm

Re: I2C.scan() returns nothing.

Post by wittend » Thu Sep 23, 2021 5:47 pm

Thanks, but I'm still getting nowhere.
I've tried the QtPy RP2040, the SparkFun Pro Micro RP2040, the Adafruit Feather RP2040.
I have tried each with the specific pin values that I have deduced by reading the rp2 module source code.
I have tried several different Qwiic-type sensors and LCD's (all known good).
I have tried new Qwiic wires.
I have tried each processor/sensor combination with an intervening LTC4311 I2C active terminator (which has worked well in the past to stabilize VERY long wiring runs).
I have tried code that just uses the default values for the hardware:

Code: Select all

import rp2
import machine

print("i2c bus: 0")
i2c0 = machine.I2C(0)
output = i2c0.scan()
print(output, len(output))

print("i2c bus: 1")
i2c1 = machine.I2C(1)
output = i2c1.scan()
print(output, len(output))

print("Done")
Response is always:

Code: Select all

>>> %Run -c $EDITOR_CONTENT
i2c bus: 0
[] 0
i2c bus: 1
[] 0
Done
>>> 
I haven't wanted to wire up terminator resistors because:
  • I have never needed to do so in the past when writing C code.
  • because it sort of defeats the purpose of using the Qwiic strategy.
  • somewhere on the Adafruit site they brag that it is unnecessary.
That seems to be my next step, however.
Then to do all the same tests using a fresh, out-of-box RP2040 from the Raspberry Pi people.
After that it is back to native C.
I haven't been able to get CircuitPython to install correctly on either of 2 Linux machines.
Dave

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: I2C.scan() returns nothing.

Post by Roberthh » Thu Sep 23, 2021 6:30 pm

Are you sure to connect to GPIO6 and 7 at Pins 9 and 10 of the RP2040?

User avatar
wittend
Posts: 8
Joined: Mon Aug 23, 2021 6:20 pm

Re: I2C.scan() returns nothing.

Post by wittend » Thu Sep 23, 2021 8:49 pm

I haven't gotten to it yet, but thanks for the reminder.
I had some other duties that interrupted that work.

Dave

User avatar
wittend
Posts: 8
Joined: Mon Aug 23, 2021 6:20 pm

Re: I2C.scan() returns nothing.

Post by wittend » Thu Sep 23, 2021 10:03 pm

Ok, success!
With the standard Raspberry Pi Pico board all my I2C devices appear as expected. (without pull ups or pull downs of any sort).
Now I need to discover the seemingly inscrutable pin mappings of the Qwiic connectors on all the other boards that I've tried.

Thanks!

Dave

User avatar
wittend
Posts: 8
Joined: Mon Aug 23, 2021 6:20 pm

Re: I2C.scan() returns nothing.

Post by wittend » Mon Sep 27, 2021 4:37 pm

On to the next obstacle.

Yes, the hardware I2C defaults work for the official RP2040 board. But there are now many alternative boards available form Adafruit, Sparkfun and others.

Most, if not all, of these offer many multiplexed mappings for the default ports. I am currently working mostly on the Sparkfun Pro Micro RP2040 and the Adafruit QtPy RP2040 boards. The attraction of these boards is a smaller footprint.

For me this is important. And for many MicroPython ports these alternative mappings are available. As best I can tell, these are commonly selected through the machine.Pin class.

The SoftI2C class gets me to the pins that I need to use...

Code: Select all

import rp2
import machine

print("Soft i2c bus: 1")
i2cs = machine.SoftI2C(scl=machine.Pin(17), sda=machine.Pin(16), freq=100000, timeout=200)
output = i2cs.scan()
print(output, len(output))

i = 0
#for i < len(output):
print("I2C Address : " + hex(output[0]).upper())
print("I2C Address : " + hex(output[1]).upper())
#    i = i + 1
    
print("I2C Configuration: " + str(i2cs))
print("Done")
... works as expected: output ...

Code: Select all

Soft i2c bus: 1
[24, 32] 2
I2C Address : 0X18
I2C Address : 0X20
I2C Configuration: SoftI2C(scl=17, sda=16, freq=100000)
Done
>>> 
...but for my purposes, this is neither good nor sufficient.

I need to use the hardware implementation of the I2C drivers, just on supposedly available alternate pins.

Close reading of the documentation for class machine.Pin seems to suggest that alternate pin functionality may be accessed using the Pin.ALT mode setting, at least where it is implemented.

I have tried to use many variations of this code (Warning: DOES NOT WORK!):

Code: Select all

import rp2
import machine

print("Hardware i2c bus: 1")
pin17 = machine.Pin(17, mode=machine.Pin.ALT)
pin16 = machine.Pin(16, mode=machine.Pin.ALT)

i2cAlt = machine.I2C(id=1, scl=pin17, sda=pin16, freq=100000)
output = i2cAlt.scan()
print(output, len(output))

print("Done")
... all with more or less the same result:

Code: Select all

Hardware i2c bus: 1
Traceback (most recent call last):
  File "<stdin>", line 18, in <module>
ValueError: bad SCL pin
>>> 
I am not sure if this can work and I'm just missing something, or if I am on the wrong track altogether.
Perhaps this ability to map alternate pin functionality simply does not exist in the RP2 MicroPython port.
If this does not work for the hardware I2C ports, I imagine that it does not work for any of the alternate functionality mappings in the RP2 port.

If not, this is a serious oversight and precludes my use of MicroPython.

Dave

User avatar
scruss
Posts: 360
Joined: Sat Aug 12, 2017 2:27 pm
Location: Toronto, Canada
Contact:

Re: I2C.scan() returns nothing.

Post by scruss » Mon Oct 11, 2021 1:23 am

wittend wrote:
Thu Sep 23, 2021 10:03 pm
Now I need to discover the seemingly inscrutable pin mappings of the Qwiic connectors on all the other boards that I've tried.
On a Pro Micro - RP2040, and with some assistance from the Graphical Datasheet, this gives me a working QWIIC port:

Code: Select all

# Pro Micro - RP2040
from machine import I2C, Pin
i2c=I2C(0, scl=Pin(17), sda=Pin(16))
As for the QtPy RP2040, the schematic (adafruit_products_QTRP_sch.png) shows the StemmaQT (= QWIIC) port on GPIO pins 22 (SDA1) and 23 (SCL1). I had to go to the RP2040 datasheet (page 14) to verify this. So something like this should work:

Code: Select all

# QtPy RP2040
from machine import I2C, Pin
i2c=I2C(1, scl=Pin(23), sda=Pin(22))
For the Feather RP2040, it's probably this (from adafruit_products_FeatherRP_sch.png):

Code: Select all

# Feather RP2040
from machine import I2C, Pin
i2c=I2C(0, scl=Pin(5), sda=Pin(4))
It doesn't help that Adafruit only use CircuitPython pin names because of course they would. All of these QWIIC/StemmaQT ports use hardware I²C.

Post Reply