Skip to content

I2C API

Tom Lin edited this page Feb 2, 2020 · 3 revisions

I2C

Inter-Intergrated Circuit(積體電路之間)又名I2C(I-squared-C), I2C是兩條雙向漏極開路 (Open Drain)分別為串列資料(SDA)與串列時脈(SCL),I2C參考設計使用一個7位元長度為位址空間但保 留了16個位址,所以在一組匯流排最多可以和112個節點通訊。依I2C傳輸速率的不同有不同模式:標準模式 (100 kbit/s)、低速模式(10 kbits/s)、快速模式(400 kbit/s)、高速模式(3.4 Mbit/s)和超高速 模式(5 Mbit/s)

在MT7697的MicroPython可以分硬體I2C與軟體模擬I2C:

  • MT7697只有1組硬體I2C,其控制針腳為固定位置分別為Pin8與Pin9,初始傳輸速率為400kbit/s與初始 傳輸TimeOut值為1秒
  • 其軟體模擬的I2C作動,所以額外將import Pin,並且指定scl與sda針腳位置。

Constructors

硬體宣告方式

class machine.I2C(id=-1, *, scl, sda, freq=400000,timeout=1000)

可以使用以下參數建構一個新I2C物件

  • id:特別用定義I2C硬體設定值,這系統內部初始值為-1所表示使用者選用軟體模擬實踐I2C作動方式在 大多數情況可以作動,當id為-1並且需要額外import machine.Pin,並且指定SCL與SDA的任何針腳使用。
  • scl:串列時脈需指定SCL針腳,MT7697的I2C硬體部份被指定Pin8
  • sda:串列資料需指定SDA針腳,MT7697的I2C硬體部份被指定Pin9
  • freq:是設置SCL最大頻率的整數
  • timeout:設為定為MT7697傳送完後等待回應時間, 其單位為millisecond

Example:

採用I2C硬體方式

from machine import I2C

i2c = I2C(0, freq=400000, timeout=1000)

採用I2C軟體方式

from machine import I2C, Pin

i2c = I2C(scl=Pin(8), sda=Pin(9), freq=400000)

Methods

I2C.init(scl, sda, *, freq=400000)

重新設定I2C設定值,如果採用MT7697的硬體I2C,在重新設定I2C的freq需先使用 I2C.deinit 函式, 才可重新設定。

  • scl:是用SCL指定針腳
  • sda:是用SDA指定針腳
  • freq:是設置SCL最大頻率的整數
I2C.deinit()

關閉I2C, 當你需要重新設定MT7697硬體I2C傳送速率時,應先關閉I2C再重新使 I2C.init 函式設定。

I2C.scan()

掃描0x08到0x77之間所有I2C位址,並列表。當在I2C匯流排上發送其位址,設備將SDA拉低則做出回應。

Primitive I2C operations

如果你需要更多的操控I2C匯流排操作方式,下列函式將提供給下列方法提實現原始I2C為master使操作,透過 函式組合使用進行任何I2C傳送資料。 I2C data transfer 這些函式僅在宣告I2C軟體物件可用

I2C.start()

在I2C匯流排上產生一個啟動訊號(SCL為高準位時,SDA轉換為低準位)

I2C.stop()

在I2C匯流排上產生一個結束訊號(SCL為高準位時,SDA轉換為高準位)

I2C.readinto(buf, nack=True)

從I2C匯流排上讀到bytes將存入 buf , 讀取byte數量為 buf 的長度。接收到除最後一個字節以外的 所有字節後,將在總線上發送ACK,如果 nacktrue ,則將發送 NACK ,否則將發送ACK,在 這種情況下,告知Slave在之後還將要讀取更多字節。

I2C.write(buf)

buf的byte值傳送I2C匯流排上,檢查每一個byte之後是否回應ACK,如果收到NACK時則停止buf 剩於的bytes傳送,此函式將回應出所接收到ACK次數。

Standard bus operations

下列函式方法實現master讀/寫slave標準I2C操作。

I2C.readfrom(addr, nbytes, stop=True)

借由指定slave的 addr 讀取 nbytes 。如果 stopTrue 當傳送資料結束時產生 STOP 狀態,讀取返回 nbytes 的資料

I2C.readfrom_into(addr, buf, stop=True)

借由指定slave的 addr 讀入 buf ,將取得bytes的量將為buf的長度,如果 stopTrue 當傳送資料結束時產生 STOP 狀態

I2C.writeto(addr, buf, stop=True)

buf 的bytes寫入指定 addr 的Slave。如果 buf 每寫入 1 byte 後收到NACK, 則停傳送剩下的bytes。該函式將返回已接收到Slave的ACK的數量。當 stop 設定 true ,即 使接收到NACK,當結束時也會傳輸 Stop 狀態

I2C.writevto(addr, vector, stop=True)

將寫入指定addr的Slave的bytes資料放 vectorvector 應具有 tuple or list 的物件。 當 addr 發送一次之後依序傳送 vector 資料的每個byte資料給指定 addr 的Slave。當 vetor 的物件bytes長度為0,這樣狀態不會傳送。

如果 vecotr 物件每寫入 1 byte 後收到NACK,則停傳送剩下的bytes。當 stop 設定 true ,即使接收到NACK,當結束時也會傳輸 Stop 狀態, 該函式將返回已接收到Slave的 ACK的數量。

Memory operations

某些I2C元件為記憶元件或是暫存器,可以被讀取與寫入資料。這種情況下,需要有兩種地置分別為I2C address 與記憶體的address。先借由I2C address找到Slave元件,在經由記憶體address,存讀取或寫入資訊。 下列提供函式提供實作功能。

I2C.readfrom_mem(addr, memaddr, nbytes, *, addrsize=8)

addr指定從Slave取得memaddr指定的內存取器啟始地置讀取nbytes量。addrsize 用於指定位址大單位大小用bits為基本單位,讀取返回的byte單位物件。

I2C.readfrom_mem_into(addr, memaddr, buf, *, addrsize=8)

addr指定從Slave取得讀取從memaddr指定的內存取器啟始地置寫入bufaddrsize 用於指定位址單位大小用bits為基本單位。

I2C.writeto_mem(addr, memaddr, buf, *, addrsize=8)

buf 值從 addr 指定Slave寫入 memaddr 內存取器啟始地址,addrsize 用於 指定位址單位大小用bits為基本單位。

Exmaple

main.py 用於硬體設定

from machine import I2C
import mpu6050
i2c = I2C(0)
accelerometer = mpu6050.accel(i2c)
accelerometer.get_values()
accelerometer.val_test()

mpu6050.py

import machine


class accel():
    def __init__(self, i2c, addr=0x68):
        self.iic = i2c
        self.addr = addr
        self.iic.writeto(self.addr, bytearray([107, 0]))

    def get_raw_values(self):
        a = self.iic.readfrom_mem(self.addr, 0x3B, 14)
        return a

    def get_ints(self):
        b = self.get_raw_values()
        c = []
        for i in b:
            c.append(i)
        return c

    def bytes_toint(self, firstbyte, secondbyte):
        if not firstbyte & 0x80:
            return firstbyte << 8 | secondbyte
        return - (((firstbyte ^ 255) << 8) | (secondbyte ^ 255) + 1)

    def get_raw_accel_value(self):
        a = self.iic.readfrom_mem(self.addr, 0x3B, 8)
        return a

    def get_raw_gyro_value(self):
        a = self.iic.readfrom_mem(self.addr, 0x43, 6)
        return a

    def get_values(self):
        raw_ints = self.get_raw_accel_value()
        vals = {}
        vals["AcX"] = self.bytes_toint(raw_ints[0], raw_ints[1])
        vals["AcY"] = self.bytes_toint(raw_ints[2], raw_ints[3])
        vals["AcZ"] = self.bytes_toint(raw_ints[4], raw_ints[5])
        vals["Tmp"] = self.bytes_toint(raw_ints[6], raw_ints[7]) / 340.00 + 36.53
        raw_ints = self.get_raw_gyro_value()
        vals["GyX"] = self.bytes_toint(raw_ints[0], raw_ints[1])
        vals["GyY"] = self.bytes_toint(raw_ints[2], raw_ints[3])
        vals["GyZ"] = self.bytes_toint(raw_ints[4], raw_ints[5])
        return vals  # returned in range of Int16
        # -32768 to 32767

    def val_test(self):  # ONLY FOR TESTING! Also, fast reading sometimes crashes IIC
        from utime import sleep
        import gc
        while 1:
            print(self.get_values())
            gc.collect()
            sleep(0.5)

Clone this wiki locally