board.I2C() .vs. board.STEMMA_I2C()

CircuitPython on hardware including Adafruit's boards, and CircuitPython libraries using Blinka on host computers.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
robcranfill
 
Posts: 142
Joined: Wed Feb 13, 2013 4:14 pm

board.I2C() .vs. board.STEMMA_I2C()

Post by robcranfill »

I have an Adafruit RP2040 attached via the STEMMA QT connector to 3 breakout boards. It's working fine, but I am now confused as to *why* it's working! This is the code:

Code: Select all

""" (based on) I2C rotary encoder simple test example."""

import board
from adafruit_seesaw import seesaw, rotaryio, digitalio

print("hello test!")

i2c = board.I2C()  # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller

print("- I2C scan -----------")
i2c.try_lock()
print(f"{i2c.scan()}")
print("----------------------")
i2c.unlock()

seesaw = seesaw.Seesaw(i2c, addr=0x36)
seesaw_product = (seesaw.get_version() >> 16) & 0xFFFF
print("Found product {}".format(seesaw_product))
if seesaw_product != 4991:
    print("Wrong firmware loaded?  Expected 4991")
else:
    print("Found correct device code!")
and I get the output:
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
main.py output:
hello test!
- I2C scan -----------
[41, 54, 57]
----------------------
Found product 4991
Found correct device code!

Why does this work? I've attached the devices to the STEMMA connector, not directly to the pins labeled SCL/SDA. Isn't that what the code is supposed to do? I am so confused. :-) Please enlighten me.

/rob

User avatar
adafruit_support_carter
 
Posts: 29168
Joined: Tue Nov 29, 2016 2:45 pm

Re: board.I2C() .vs. board.STEMMA_I2C()

Post by adafruit_support_carter »

Which RP2040 board are you using? Most likely, for that board both board.I2C() and board.STEMMA_I2C() are the same pins.

User avatar
blakebr
 
Posts: 957
Joined: Tue Apr 17, 2012 6:23 pm

Re: board.I2C() .vs. board.STEMMA_I2C()

Post by blakebr »

Rob,

If you uncomment the second i2c line and get an 'inuse' error on the STEMMA line then they are using the same pins. e.g:

Code: Select all

i2c = board.I2C()  # uses board.SCL and board.SDA
i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller
Bruce

User avatar
robcranfill
 
Posts: 142
Joined: Wed Feb 13, 2013 4:14 pm

Re: board.I2C() .vs. board.STEMMA_I2C()

Post by robcranfill »

adafruit_support_carter wrote: Mon Jan 23, 2023 2:03 pm Which RP2040 board are you using? Most likely, for that board both board.I2C() and board.STEMMA_I2C() are the same pins.
Oops, sorry, I forgot to say it's an Adafruit Feather RP2040!

User avatar
robcranfill
 
Posts: 142
Joined: Wed Feb 13, 2013 4:14 pm

Re: board.I2C() .vs. board.STEMMA_I2C()

Post by robcranfill »

Ah, I see now that the product page says
board.STEMMA_I2C() uses SCL/SDA
which is pretty clear, I guess! Sorry for the dumb question. :-]

User avatar
neradoc
 
Posts: 542
Joined: Wed Apr 27, 2016 2:38 pm

Re: board.I2C() .vs. board.STEMMA_I2C()

Post by neradoc »

Yes, they are the same pins. board.I2C on this board is an alias to board.STEMMA_I2C.
You can call either or both, they will return the same bus every time.
The presence of both allows for code to be written that will work on boards where they are not.

User avatar
adafruit_support_carter
 
Posts: 29168
Joined: Tue Nov 29, 2016 2:45 pm

Re: board.I2C() .vs. board.STEMMA_I2C()

Post by adafruit_support_carter »

They may or may not be the same depending on the board. The QT Py RP2040 is an example of where they are different:
https://learn.adafruit.com/adafruit-qt-py-2040/pinouts

There's history to all of this.

Originally, the only way to create an I2C bus was by explicitly specifying the pins:

Code: Select all

i2c = busio.I2C(board.SCL, board.SDA)
The vast majority of boards end up using those pins, so to reduce the amount of boiler plate code, a convenience shortcut was added:

Code: Select all

i2c = board.I2C()
This is how things were for a while. And then came the STEMMA QT connectors.

While a lot of boards route the same board.SCL and board.SDA pins to the STEMMA QT connector, some (like QT Py RP2040) route different pins from secondary I2C peripherals. This led to a lot of confusion from tons of code and guides that show board.I2C() and lots of "sensor not found" issues when using the STEMMA QT connector. The simple immediate fix was to revert to the original explicit pin setup and specify the actual pins on the STEMMA QT connector:

Code: Select all

i2c = busio.I2C(board.SCL1, board.SDA1)
But in short order, the idea of providing a new convenience shortcut for the STEMMA QT connector was added. Thus:

Code: Select all

i2c = board.STEMMA_I2C()
So now we have:
  • board.I2C() is a shortcut for busio.I2C(board.SCL, board.SDA)
  • board.STEMMA_I2C() is a shortcut for *whatever* I2C pins are on the STEMMA_QT connector
  • board.I2C() and board.STEMMA_I2C() may or may not be the same - the only way to know is to consult the pinout for the given board
  • the original busio.I2C() usage is still supported

User avatar
blakebr
 
Posts: 957
Joined: Tue Apr 17, 2012 6:23 pm

Re: board.I2C() .vs. board.STEMMA_I2C()

Post by blakebr »

Hello,

This code chunk will print the pin assignments to REPL plus some additional things about your operating environment.

Code: Select all

if True: # if True show Pin Assignments
  import board
  import microcontroller
  print("\t\tMicrocontroller Pin Assignments:")
  board_pins = []
  for pin in dir(microcontroller.pin):
    if isinstance(getattr(microcontroller.pin, pin), microcontroller.Pin):
      pins = []
      for alias in dir(board):
        if getattr(board, alias) is getattr(microcontroller.pin, pin):
          pins.append("board.{}".format(alias))
      if len(pins) > 0:
        board_pins.append(" ".join(pins))
  for pins in sorted(board_pins):
    print(pins)
  import board
  print('\n>>> dir(board)')
  print(dir(board))
  import supervisor
  print('\n>>> dir(supervisor)')
  print(dir(supervisor))
  import microcontroller
  print('\n>>> dir(microcontroller)')
  print(dir(microcontroller))
  print('\n>>> help("modules")')
  print(help("modules"))
You can cut-n-paste the results into a *.txt file on the target board for future reference.

Bruce

Locked
Please be positive and constructive with your questions and comments.

Return to “Adafruit CircuitPython”