Skip to content
Boris Lovosevic edited this page Mar 3, 2018 · 16 revisions

Editing in progress...

machine Module

Class I2C


This class includes full support for using ESP32 I2C peripheral
Both master and slave modes are supported.
Master and slave modes can be used at the same time, on different I2C interfaces.



Create the I2C instance object

i2c = machine.I2C(id, mode, speed, sda, scl, slave_addr, slave_bufflen)

Argument Description
id The hardware I2C peripheral ID; 0 or 1 can be used
Default: 0
mode I2C interface mode; master or slave
Use the constants machine.I2C.MASTER or machine.I2C.SLAVE
Default: master
speed
freq
I2C clock frequency in Hz
Default: 100000
sda I2C sda pin; can be given as integer gpio number or Pin object
scl I2C scl pin; can be given as integer gpio number or Pin object
slave_address I2C slave address to be assigned to this i2c interface.
Only used if SLAVE mode is selected
7-bit address, do not use reserved adresses 0x00-0x07 & 0x78-0x7F

Default: 32 (0x20)
slave_bufflen Size of slave buffer used for master<->slave comunication in bytes;
Range: 256 - 4096
Default: 256
Only used if SLAVE mode is selected

Only sda and scl are required, all the others are optional and will be set to the default values if not given.

i2c = machine.I2C(0, sda=21, scl=22)
si2c = machine.I2C(1, mode=machine.I2C.SLAVE, sda=25, scl=26, slave_bufflen=512)



i2c.deinit()

Deinitialize the I2C object, free all used resources.

i2c.scan()

Scan for i2c devices on I2C bus.
Returns the list of detected addresses.
Can only be used in master mode.

į2c.readfrom(addr, nbytes)

Read nbytes bytes from i2c device with address addr.
Bytearray of read bytes is returned.
Can only be used in master mode.

į2c.readfrom_into(addr, buf)

Read from i2c device with address addr into buffer object buf.
Size of buf bytes are read.
Can only be used in master mode.

i2c.writeto(addr, buf [,stop=True])

Write the content of the buffer object buf to the i2c device with address adr
If optional stop argument is set to False, the stop signal is not issued.
Can only be used in master mode.

į2c.readfrom_mem(addr, memaddr, n, adrlen, stop)

Argument Description
addr i2c device address
memaddr memory address to be wtitten before read
n number of bytes to read
adrlen optional; number of addres bytes to write, 1 - 4
If not given, number of bytes to send is determined from the memaddr value
stop optional; Default: True
If True, stop signal is issued after address write
If False, repeated start signal is issued after address write

Write the address to the i2c device with address addr, then read n bytes from it.
Bytearray of read bytes is returned.
Can only be used in master mode.

į2c.readfrom_mem_into(addr, memaddr, buf, adrlen, stop)

Argument Description
addr i2c device address
memaddr memory address to be wtitten before read
buf Buffer object to read into
adrlen optional; number of addres bytes to write, 1 - 4
If not given, number of bytes to send is determined from the memaddr value
stop optional; Default: True
If True, stop signal is issued after address write
If False, repeated start signal is issued after address write

Write the address to the i2c device with address addr, then read from itinto buffer object buf.
Size of buf bytes are read.
Can only be used in master mode.

i2c.writeto_mem(addr, memaddr, buf, adrlen)

Argument Description
addr i2c device address
memaddr memory address to be wtitten before read
buf Buffer object to write from
adrlen optional; number of addres bytes to write, 1 - 4
If not given, number of bytes to send is determined from the memaddr value

Write the address to the i2c device with address addr, then write the content of the buffer object buf to the device
Can only be used in master mode.


SLAVE mode

The I2C device can be configured to run in slave mode

The master <-> slave communication is performed via the slave bufer, size of which is configured on creating the I2C object.
The master can perform three kinds of operations with MicroPython I2C slave:

  • read from slave buffer issuing the following command sequence:
    • write the 2-byte address & 2-byte length to MicroPython I2C slave. The address range and lenght must be set according to MicroPython I2C slave buffer size
    • read length bytes from MicroPython I2C slave
  • write to the slave buffer issuing the following command sequence:
    • write 2-byte address following with data to MicroPython I2C slave.
      The address range must be from 0x1000 to 0x1000 + slave_buffer_size - 1
      The 0x1000 address offset is used to distingush the read and write operations.
  • send command with optional data to the slave
    • The master can send any command in range 0x20 to 0xFF to the MicroPython I2C slave.
      This command (and optional data) can be anylized in callback function and some action taken

The content of the slave buffer san be set or read from MicroPython at any time.

Separate callback functions can be defined for read, write and command events.

i2c.setdata(buf, addr)

Set the content of the slave buffer at address addr from buffer object buf
Can only be used in slave mode.

i2c.getdata(addr, length)

Get the length bytes from the slave buffer at address addr
Bytearray of read bytes is returned.
Can only be used in slave mode.

i2c.slavewrite(buf)

Write the content of the buffer object buf to the I2C slave transimt buffer
The master must ready to read that data.
Can be used, for example, from command callback function as a response to some master command.
Can only be used in slave mode.

i2c.callback(type, func)

Register the callback function for slave events.

The type argument can be:

  • machine.I2C.CB_READ the function is executed when master reads the data from the slave buffer
  • machine.I2C.CB_WRITE the function is executed when master writtes the data to the slave buffer
  • machine.I2C.CB_DATA the function is executed when master sends the command with optional data to the slave

read & write callback functions receives the tupple argument:
(type, address, length, data)
type is 0 for read operation and 1 for write operation
data is bytearray with data sent or received to/from master

data callback receives the tupple argument: (cmd, trans_len, data_len, data)
cmd is the command received from master in range 0x20 - 0xFF
trans_len is the total length of the i2c transaction data_len is the length of the received data data is bytearray of data received from master, or None if only command is received.

Can only be used in slave mode.


Example:

import machine

def i2c_cb(res):
    t = res[0] # i2c slave event type
    if t == 0:
        print("READ: addr={}, len={}, data={}".format(res[1], res[2], res[3]))
    elif t == 1:
        print("WRITE: addr={}, len={}, data={}".format(res[1], res[2], res[3]))

def data_cb(res):
    print("DATA received: cmd={}, trans_len={}, data_len={}, data={}".format(res[0], res[1], res[2], res[3]))

m = machine.I2C(0, sda=21, scl=22)
s = machine.I2C(1, mode=machine.I2C.SLAVE, sda=25, scl=26, slave_bufflen=512)

s.callback(s.CB_READ, i2c_cb)
s.callback(s.CB_WRITE, i2c_cb)
s.callback(s.CB_DATA, data_cb)

>>> m
I2C (Port=0, Mode=MASTER, Speed=100000 Hz, sda=21, scl=22)
>>> s
I2C (Port=1, Mode=SLAVE, Speed=100000 Hz, sda=25, scl=26, addr=32, buffer=512 B)
     ReadCB=True, WriteCB=True, DataCB=True
     I2C task minimum free stack: 432
>>> 

# Master: scan the I2C bus
>>> m.scan()
[32]
>>> 

# Master: write 8 bytes to the slave at address 0x0000
#         0x1000 offset is used to signal the write operation
>>> m.writeto_mem(32, 0x1000, "12345678")
8
>>> WRITE: addr=0, len=8, data=b'12345678'
>>> 

# Master: read 8 bytes from the slave at address 0x0000
>>> m.readfrom_mem(32, 0x08, 8, adrlen=4)
b'12345678'
>>> READ: addr=0, len=8, data=b'12345678'
>>> 

# Master: write command and data to slave 
>>> m.writeto(32, "\x7CHi, ESP32 i2c slave, please act according to mommand 0x7C.")
59
>>> DATA received: cmd=124, trans_len=59, data_len=58, data=b'Hi, ESP32 i2c slave, please act according to mommand 0x7C.'
>>> 

# Slave: send data directly to master
>>> s.slavewrite("Hi from MicroPython I2C slave")
29
>>> m.readfrom(32, 29)
b'Hi from MicroPython I2C slave'
>>> 

# Slave: Set the slave buffer content at address 0x0080
>>> s.setdata("ABCDEFGH", 0x80)
>>> s.getdata(0x80, 8)
b'ABCDEFGH'
# Master: read 8 bytes from the slave at address 0x0080
>>> m.readfrom_mem(32, 0x00800008, 8, adrlen=4)
b'ABCDEFGH'
>>> READ: addr=128, len=8, data=b'ABCDEFGH'

>>> 

I2C Low level commands

The low level I2C commands are provided.
It is not recommended to use them for comunication with with I2C devices, but they can be useful in some special usage cases.
They can also be used to demonstrate the I2C protocol for educational purposes.

All low level commands must be placed between begin and end command.
The individual comands are not sent to the device imediately, but are rather queued until the end command is executed.

The low level commands can only be used in master mode.



i2c.begin(rxbuf_len)

Initializes the low level queue and prepares for other low level commands.
If rxbuf_len is > 0, allocates the low lewel commands receive buffer.
If no read commands are used between begin - end sequence, no read buffer is used and rxbuf_len can be set to 0

isc.start()

Queues the I2C start signal.

isc.stop()

Queues the I2C stop signal.

isc.address(addr, mode)

Queues the I2C device address and transactiom mode (read or write).
For mode argument use the constants machine.I2C.WRITE (0) or machine.I2C.READ (1)

isc.write_byte(val)

Writes a single byte, val, to the queue.

isc.write_bytes(buf)

Writes bytes from buffer object buf to the queue.

isc.read_byte()

Queue reading single byte from I2C device.

isc.read_bytes(length)

Queue reading length bytes from I2C device.

i2c.end()

Execute all queued commands. The acctual I2C transaction to I2C slave is performed at this time. If there were some read commands in the command sequence, returns the bytearray of the read bytes.

Example
Configure master amd slave I2C instances as in previous example:

# ==============================
# Test low level commands usage
# Write to MicroPython I2C slave
# ==============================
def test(adr, data):
    address = bytearray(2)
    address[0] = ((adr >> 8) & 0x0F) | 0x10
    address[1] = adr & 0xFF

    adrlen = bytearray(4)
    adrlen[0] = (adr >> 8) & 0x0F
    adrlen[1] = adr & 0xFF
    adrlen[2] = (len(data) >> 8) & 0xFF 
    adrlen[3] = len(data) & 0xFF 

    # === write data to address ===
    m.begin(0)
    m.start()
    m.address(32, m.WRITE)
    m.write_bytes(address)
    m.write_bytes(data)
    m.stop()
    m.end()

    # === read the data back ===
    # send address and length
    m.begin(0)
    m.start()
    m.address(32, m.WRITE)
    m.write_bytes(adrlen)
    m.stop()
    m.end()
    # read data
    m.begin(256)
    m.start()
    m.address(32, 1)
    m.read_bytes(len(data))
    m.stop()
    res = m.end()
    print(res)

def testcmd(cmd, data):
    cmd = cmd & 0xFF
    if cmd < 0x20:
        cmd = 20
    m.begin(0)
    m.start()
    m.address(32, m.WRITE)
    m.write_byte(cmd)
    m.write_bytes(data)
    m.stop()
    m.end()

>>> test(64, "Test low level commands")
b'Test low level commands'
>>> WRITE: addr=64, len=23, data=b'Test low level commands'
READ: addr=64, len=23, data=b'Test low level commands'

>>> 
>>> testcmd(78, "Low level commands sending command&data")
>>> DATA received: cmd=78, trans_len=40, data_len=39, data=b'Low level commands sending command&data'

>>> 
Clone this wiki locally