Skip to content
Boris Lovosevic edited this page Jul 19, 2019 · 2 revisions

machine Module

Class I2C


This class includes full support for using K210 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, slave_rolen, slave_busy)

Argument Description
id The hardware I2C peripheral ID; 0, 1 or 2 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<brrange: 50000 ~ 5000000
sda I2C sda pin; integer, any valid and not used K210 pin
scl I2C scl pin; integer, any valid and not used K210 pin
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: 128 - 4096
Default: 256
For buffer sizes 128-256 bytes 8-bit addressing is used
For buffer sizes >256 bytes 16-bit addressing is used
Only used if SLAVE mode is selected
slave_rolen Size of read-only area at the end of the slave buffer in bytes;
Range: 1 - slave_bufflen/2
Default: 0
Master device can only read from that area
Only used if SLAVE mode is selected
slave_busy If set to True, the last byte of the slave buffer will be used as status register.
Bit #8 of that register will be set to 1 by the driver after the write transaction is finished, as indication to the master that the slave is busy processing request.
User program must reset this bit using i2c.resetbusy() function.
Default: False
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.

m = machine.I2C(0, sda=20, scl=21)
s = machine.I2C(1, mode=machine.I2C.SLAVE, sda=18, scl=19, slave_bufflen=512)



i2c.init(args)

Reinitialize an existing I2C object.
The arguments are the same as for creating a new i2c instance object.

i2c.deinit()

Deinitialize the I2C object, free all used resources.

i2c.scan()

Scan for i2c devices on I2C bus. Does not scan reserved 7-bit addresses: 0x00-0x07 & 0x78-0x7F
Returns the list of detected addresses.
Can only be used in master mode.

>>> m = machine.I2C(0, sda=20, scl=21)
>>> s = machine.I2C(1, mode=machine.I2C.SLAVE, sda=18, scl=19, slave_bufflen=512)
>>> m.scan()
[32, 118]



i2c.is_ready(addr)

Check if i2c device with address addr is present on i2c bus
Returns True if the device was detected, `False if not.
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)

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

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

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

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)

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

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.

In slave mode i2c device with 128-4096 memory is emulated, via the slave buffer. All master's read/write requests for data are handled by the driver's interrupt routine. The user only needs to provide the initial buffer content and, optionally, to handle the master's request from callbacks.

Master can read from or write to the K210 i2c device, providing the memory (slave buffer) address to read from or write to.

For buffer sizes 128-256 bytes, 8-bit addressing is used, for buffer sizes >256 bytes, 16-bit addressing is used.

Typical master write sequence is as follows:

For slave buffer size <= 256 8-bit addressing is used

_____________________________________________________________________________________
| start | slave_addr + wr_bit + ack | buff_addr + ack | write n bytes + ack  | stop |
--------|---------------------------|-----------------|----------------------|------|

For slave buffer size > 256 16-bit addressing is used

_____________________________________________________________________________________________________________
| start | slave_addr + wr_bit + ack | buff_addr_hi + ack | buff_addr_lo + ack | write n bytes + ack  | stop |
--------|---------------------------|--------------------|--------------------|----------------------|------|

Typical master read sequence is as follows:

For slave buffer size <= 256 8-bit addressing is used

_________________________________________________________________________________________________________________________________________________
| start | slave_addr + wr_bit + ack | buff_addr + ack | start | slave_addr + rd_bit + ack | read n-1 bytes + ack | read n-th byte + nack | stop |
--------|---------------------------|-----------------|-------|---------------------------|----------------------|-----------------------|------|

For slave buffer size > 256 16-bit addressing is used

_________________________________________________________________________________________________________________________________________________________________________
| start | slave_addr + wr_bit + ack | buff_addr_hi + ack | buff_addr_lo + ack | start | slave_addr + rd_bit + ack | read n-1 bytes + ack | read n-th byte + nack | stop |
--------|---------------------------|--------------------|--------------------|-------|---------------------------|---------  -----------|-----------------------|------|

Optional read only area at the end of the slave buffer can be set. Master can only read from that area, writing to it by the master will be ignored.

If slave_busy is set to True when the slave i2c object is initialized, the last byte of the slave buffer will be used as status byte.
Bit #7 of the status byte will be set to 1 by the driver when master sends some data, indicating the slave is busy processing the request.
Master should read the status register to detect when the slave has precessed the request.
The application (callback function) should reset the busy bit after processing the request using resetbusy() function.
Bits 0-6 of the status register can be used as user defined flags.

The functions to read and write data from/to the slave buffer at any time are provided: setdata() and getdata().

A callbacks are provided which receives notifications from the i2c driver about the slave events: address set, data sent to master, data received from master. Slave buffer address, number of bytes sent or received and overflow status are available to the slave callback to take some action on slave events.

It is up to the user to organize the slave buffer in a way most appropriate for the application. Writting to some addresses can, for example, be treated by the slave as commands with optional arguments and some action taken.

Read only area can contain the slave ID, revision number, sensor data etc.



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.
Returns True on success, False if failed.

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.resetbusy()

Reset the busy bit of the status byte (if used)
Can only be used in slave mode.

i2c.callback(func, type)

Register the callback function for slave events.

The type argument can be:

  • machine.I2C.CBTYPE_NONE no callback enabled
  • machine.I2C.CBTYPE_ADDR execute callback when master sets the slave buffer address
  • machine.I2C.CBTYPE_RXDATA execute callback when master reads data from slave buffer
  • machine.I2C.CBTYPE_TXDATA execute callback when master writes data to slave buffer

Multiple callback types can or-ed together.

The callback functions receives the 5-item tupple argument:
(cb_type, address, length, overflow, data)
cb_type the callback type
address the address in the slave buffer
length number of bytes read or written by master
overflow number of bytes master has atempted to read or write past the slave buffer size
data bytearray with data sent or received to/from master

Can only be used in slave mode.


Example:

import machine

def i2c_cb(res):
    cbtype = res[0] # i2c slave cllback type
    if cbtype == machine.I2C.CBTYPE_TXDATA:
        print("[I2C] Data sent to master: addr={}, len={}, ovf={}, data={}".format(res[1], res[2], res[3], res[4]))
    elif cbtype == machine.I2C.CBTYPE_RXDATA:
        print("[I2C] Data received from master: addr={}, len={}, ovf={}, data: [{}]".format(res[1], res[2], res[3], res[4]))
    elif cbtype == machine.I2C.CBTYPE_ADDR:
        print("[I2C] Addres set: addr={}".format(res[1]))
    else:
        print("Unknown CB type, received: {}".format(res))

# Create two i2c instance objects, master and slave
m = machine.I2C(0, sda=20, scl=21, speed=400000)

# no buffer length is specified, default 256 bytes buffer will be used
# with 8-bit addressing
s = machine.I2C(1, mode=machine.I2C.SLAVE, sda=18, scl=19)

# Enable all slave callbacks
s.callback(i2c_cb, s.CBTYPE_ADDR | s.CBTYPE_RXDATA | s.CBTYPE_TXDATA)

#Set some data in slave buffer
s.setdata("1234567890abcdefghij", 0)
s.setdata("ABCDEFGHabcdefgh", 0x80)
s.setdata("BUFFEREND", 0xF7)

I2C (Device=0, Mode=MASTER, Speed=400000 Hz, sda=20, scl=21)
>>> s
I2C (Device=1, Mode=SLAVE, Speed=100000 Hz, sda=18, scl=19, addr=32 (0x20), buffer=256 B, read-only=0 B)
     Callback=True (7)
     I2C task minimum free stack: 925
>>> 

# Master: scan the I2C bus
>>> m.scan()
[32, 118]
>>> [I2C] Data sent to master: addr=0, len=1, ovf=0, data=b'1'

>>> 
# Check if device 32 is ready
>>> m.is_ready(32)
True
>>> [I2C] Data sent to master: addr=1, len=1, ovf=0, data=b'2'
>>> 

# Master: write 14 bytes message to the slave at address 40
#         8-bit addressing is used
>>> m.writeto_mem(32, 40, "Hi from master")
14
>>> [I2C] Data received from master: addr=40, len=14, ovf=0, data: [b'Hi from master']

>>> 

# Master: read 10 bytes from the slave at address 0
>>> m.readfrom_mem(32, 0x00, 10)
b'1234567890'
>>> [I2C] Data sent to master: addr=0, len=10, ovf=0, data=b'1234567890'

# Master: read 16 bytes from the slave at address 0x80
>>> m.readfrom_mem(32, 0x80, 16)
b'ABCDEFGHabcdefgh'
>>> [I2C] Data sent to master: addr=128, len=16, ovf=0, data=b'ABCDEFGHabcdefgh'

# Try to read behind the buffer size
# requested number of bytes is returned, bytes behind the buffer end are filled with 0xFE
# Overflow is reported by callback function
>>> m.readfrom_mem(32, 0xF7, 16)
b'BUFFEREND\xfe\xfe\xfe\xfe\xfe\xfe\xfe'
>>> [I2C] Data sent to master: addr=247, len=9, ovf=7, data=b'BUFFEREND'

BME280 module is included in k210-freertos/mpy_support/examples directory.
Copy it to the /flash/lib directory on internal file system (create the lib directory if it doesn't exists).

import machine, time
import bme280

i2c=machine.I2C(scl=21,sda=20,speed=400000)
bme=bme280.BME280(i2c=i2c)

def bmevalues():
    t, p, h = bme.read_compensated_data()

    p = p // 256
    pi = p // 100
    pd = p - pi * 100
    p = pi + (pd / 100)

    hi = h // 1024
    hd = h * 100 // 1024 - hi * 100
    h = hi + (hd / 100)

    return "[{}] T={:.1f}\xb0C, P={:.2f}hPa, H={:.2f}%".format(time.strftime("%H:%M:%S",time.localtime()), t/100, p, h)

>>> print(bmevalues())
[12:38:48] T=26.0°C, P=1000.41hPa, H=66.88%
>>> 
Clone this wiki locally