I2C (Grove connector)
hub.i2c is a machine.I2C singleton — the same object
returned by machine.I2C(0). It speaks the internal I2C bus that
drives the PCA9685, SC16IS750 (I2C variant), BNO085 IMU and the on-board
Grove connector pads.
Because hub.i2c and machine.I2C(0) are the same singleton,
creating machine.I2C(0) explicitly is safe and returns the same
instance:
import hub, machine
assert hub.i2c is machine.I2C(0) # True
Pins are fixed to the board’s I2C_SDA / I2C_SCL definitions in
Board.h. Passing different sda / scl kwargs to .init()
is accepted but silently ignored.
Quickstart
Scan the bus and print anything that ACKs:
import hub
print("devices:", [hex(a) for a in hub.i2c.scan()])
Change the clock:
hub.i2c.init(freq=100_000) # slow down to 100 kHz
hub.i2c.init(freq=400_000) # back to default
Raw write / read
ADDR = 0x40
hub.i2c.writeto(ADDR, b"\\x00\\x01") # single transaction
data = hub.i2c.readfrom(ADDR, 4) # read 4 bytes
For a scatter/gather write in one transaction:
hub.i2c.writevto(ADDR, [b"\\x10", payload])
Register access
Convenience wrappers around the common register-file pattern (write memaddr, repeated-start, read/write):
who = hub.i2c.readfrom_mem(0x68, 0x75, 1) # MPU6050 WHO_AM_I
hub.i2c.writeto_mem(0x68, 0x6B, b"\\x00") # PWR_MGMT_1 = 0
buf = bytearray(6)
hub.i2c.readfrom_mem_into(0x68, 0x3B, buf) # 6-byte accel burst
16-bit register addresses:
hub.i2c.writeto_mem(0x50, 0x1234, b"\\xaa", addrsize=16)
hub.i2c.readfrom_mem(0x50, 0x1234, 1, addrsize=16)
Full example — MPU-6050 accelerometer on Grove
"""MPU-6050 accelerometer over the Grove I2C connector.
Reads WHO_AM_I, wakes the chip, then streams 6-byte accel bursts.
Uses the shared internal I2C bus via ``hub.i2c`` — coexists with the
PCA9685, SC16IS750, BNO085 and everything else already on Wire1.
"""
import hub, struct, time
ADDR = 0x68 # MPU-6050 / MPU-6500 default (AD0 low)
WHO_AM_I = 0x75
PWR_MGMT_1 = 0x6B
ACCEL_XOUT_H = 0x3B
print("scanning I2C bus...")
devs = hub.i2c.scan()
print("addresses:", [hex(a) for a in devs])
if ADDR not in devs:
print(f"MPU-6050 not found at {hex(ADDR)}")
else:
who = hub.i2c.readfrom_mem(ADDR, WHO_AM_I, 1)[0]
print(f"WHO_AM_I: 0x{who:02X}")
hub.i2c.writeto_mem(ADDR, PWR_MGMT_1, b"\x00")
_buf = bytearray(6)
_last_print = 0
while not hub.buttons.center():
now = time.ticks_ms()
if time.ticks_diff(now, _last_print) >= 200:
_last_print = now
hub.i2c.readfrom_mem_into(ADDR, ACCEL_XOUT_H, _buf)
ax, ay, az = struct.unpack(">hhh", _buf)
print(f"accel x={ax:+6} y={ay:+6} z={az:+6}")
API reference
hub.i2c is a machine.I2C instance — the full API is documented
under machine.I2C. Methods available:
.init(*, freq=-1)— apply new frequency..scan()— probe 0x08..0x77, return list of ACK’d addresses..readfrom(addr, nbytes, stop=True)→bytes..readfrom_into(addr, buf, stop=True)..writeto(addr, buf, stop=True)→ bytes-written count..writevto(addr, vector, stop=True)— scatter/gather..readfrom_mem(addr, memaddr, nbytes, *, addrsize=8)..readfrom_mem_into(addr, memaddr, buf, *, addrsize=8)..writeto_mem(addr, memaddr, buf, *, addrsize=8).
Errors:
OSError(ENODEV)— device NACK’d (bad address / not present).OSError(ETIMEDOUT)— bus timeout.OSError(EIO)— other bus error.