class I2C -- 2線式シリアルプロトコル

I2C はデバイス間で通信を行うための2線式プロトコルです。物理レベルでは、それぞれクロック線とデータ線である SCL と SDA の2本の線で構成されます。

I2C オブジェクトは特定のバスに接続された状態で生成されます。生成時に初期化することも、後から初期化することもできます。

I2C オブジェクトを出力すると、その設定に関する情報が表示されます。

I2C の実装には、I2C クラスと SoftI2C クラスによるハードウェアとソフトウェアの両方が存在します。ハードウェア I2C はシステムの基盤となるハードウェアサポートを利用して読み書きを行い、通常は効率的で高速ですが、使用できるピンに制約がある場合があります。ソフトウェア I2C はビットバンギングで実装されており、任意のピンで使用できますが効率は劣ります。これらのクラスは同じメソッドを備えており、主に構築方法が異なります。

注釈

I2C バスは動作のために SDA と SCL の両方にプルアップ回路を必要とします。通常これは 1 - 10 kOhm 程度の抵抗で、各 SDA/SCL から Vcc に接続されます。これがないと動作は未定義となり、ブロッキングや予期しないウォッチドッグリセット、あるいは単に誤った値が返るなど、さまざまな問題が生じる可能性があります。多くの場合、このプルアップ回路は MCU ボードやセンサーのブレークアウトボードにあらかじめ組み込まれていますが、必ずそうとは限りません。そのため、問題が発生した場合は確認してください。I2C の配線については、Adafruit による優れた learning guide も参照してください。

使用例:

from machine import I2C

i2c = I2C(freq=400000)          # create I2C peripheral at frequency of 400kHz
                                # depending on the port, extra parameters may be required
                                # to select the peripheral and/or pins to use

i2c.scan()                      # scan for peripherals, returning a list of 7-bit addresses

i2c.writeto(42, b'123')         # write 3 bytes to peripheral with 7-bit address 42
i2c.readfrom(42, 4)             # read 4 bytes from peripheral with 7-bit address 42

i2c.readfrom_mem(42, 8, 3)      # read 3 bytes from memory of peripheral 42,
                                #   starting at memory-address 8 in the peripheral
i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of peripheral 42
                                #   starting at address 2 in the peripheral

コンストラクタ

class machine.I2C(id: int, *, scl: Pin | None = None, sda: Pin | None = None, freq: int = 400000, timeout: int = 50000)

以下のパラメータを使用して新しい I2C オブジェクトを構築して返します:

  • id は特定の I2C ペリフェラルを識別します。指定できる値はポートやボードによって異なります

  • scl は SCL に使用するピンを指定するピンオブジェクトである必要があります。

  • sda は SDA に使用するピンを指定するピンオブジェクトである必要があります。

  • freq は SCL の最大周波数を設定する整数である必要があります。

  • timeout は I2C トランザクションに許容される最大時間(マイクロ秒単位)です。このパラメータは一部のポートでは使用できません。

一部のポートやボードでは sclsda にデフォルト値があり、このコンストラクタで変更できます。その他のポートでは sclsda が固定値で変更できない場合があります。

一般的なメソッド

init(scl: Pin, sda: Pin, *, freq: int = 400000) None

指定された引数で I2C バスを初期化します:

  • scl は SCL 線用のピンオブジェクトです

  • sda は SDA 線用のピンオブジェクトです

  • freq は SCL のクロックレートです

ハードウェア I2C の場合、実際のクロック周波数は要求した周波数より低くなることがあります。これはプラットフォームのハードウェアに依存します。実際のレートは I2C オブジェクトを出力することで確認できます。

scan() List[int]

0x08 から 0x77 まで(両端を含む)のすべての I2C アドレスをスキャンし、応答したもののリストを返します。デバイスは、バス上でそのアドレス(書き込みビットを含む)が送信された後に SDA 線を Low に引き下げると応答したとみなされます。

プリミティブな I2C 操作

以下のメソッドはプリミティブな I2C コントローラのバス操作を実装しており、組み合わせることで任意の I2C トランザクションを構成できます。これらはバスをより細かく制御する必要がある場合に提供されますが、そうでない場合は標準的なメソッド(後述)を使用できます。

これらのメソッドは SoftI2C クラスでのみ使用できます。

start() None

バス上に START 条件を生成します(SCL が High の間に SDA が Low に遷移します)。

stop() None

バス上に STOP 条件を生成します(SCL が High の間に SDA が High に遷移します)。

readinto(buf: bytearray, nack: bool = True, /) None

バスからバイトを読み込み、buf に格納します。読み込まれるバイト数は buf の長さです。最後のバイトを除くすべてのバイトを受信した後、バスに ACK が送信されます。最後のバイトを受信した後、nack が真の場合は NACK が送信され、そうでなければ ACK が送信されます(この場合、ペリフェラルは後続の呼び出しでさらにバイトが読み込まれると想定します)。

write(buf: bytes) int

buf のバイトをバスに書き込みます。各バイトの後に ACK が受信されたことを確認し、NACK が受信された場合は残りのバイトの送信を停止します。この関数は受信した ACK の数を返します。

標準的なバス操作

以下のメソッドは、指定したペリフェラルデバイスを対象とする標準的な I2C コントローラの読み書き操作を実装します。

readfrom(addr: int, nbytes: int, stop: bool = True, /) bytes

addr で指定されたペリフェラルから nbytes を読み込みます。stop が真の場合、転送の最後に STOP 条件が生成されます。読み込んだデータを格納した bytes オブジェクトを返します。

readfrom_into(addr: int, buf: bytearray, stop: bool = True, /) None

addr で指定されたペリフェラルから buf に読み込みます。読み込まれるバイト数は buf の長さになります。stop が真の場合、転送の最後に STOP 条件が生成されます。

このメソッドは None を返します。

writeto(addr: int, buf: bytes, stop: bool = True, /) int

buf のバイトを addr で指定されたペリフェラルに書き込みます。buf のあるバイトの書き込みに続いて NACK が受信された場合、残りのバイトは送信されません。stop が真の場合、NACK が受信されたとしても転送の最後に STOP 条件が生成されます。この関数は受信した ACK の数を返します。

writevto(addr: int, vector: tuple | list, stop: bool = True, /) int

vector に含まれるバイトを addr で指定されたペリフェラルに書き込みます。vector はバッファプロトコルを持つオブジェクトのタプルまたはリストである必要があります。addr は一度だけ送信され、その後 vector 内の各オブジェクトのバイトが順次書き出されます。vector 内のオブジェクトは長さが0バイトであってもよく、その場合は出力に寄与しません。

vector 内のいずれかのオブジェクトのあるバイトの書き込みに続いて NACK が受信された場合、残りのバイトおよび残りのオブジェクトは送信されません。stop が真の場合、NACK が受信されたとしても転送の最後に STOP 条件が生成されます。この関数は受信した ACK の数を返します。

メモリ操作

一部の I2C デバイスは、読み書きが可能なメモリデバイス(またはレジスタのセット)として動作します。この場合、I2C トランザクションには2つのアドレス、すなわちペリフェラルアドレスとメモリアドレスが関連付けられます。以下のメソッドは、このようなデバイスと通信するための便利な関数です。

readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes

memaddr で指定されたメモリアドレスから開始して、addr で指定されたペリフェラルから nbytes を読み込みます。引数 addrsize はアドレスサイズをビット単位で指定します。読み込んだデータを格納した bytes オブジェクトを返します。

readfrom_mem_into(addr: int, memaddr: int, buf: bytearray, *, addrsize: int = 8) None

memaddr で指定されたメモリアドレスから開始して、addr で指定されたペリフェラルから buf に読み込みます。読み込まれるバイト数は buf の長さです。引数 addrsize はアドレスサイズをビット単位で指定します。

このメソッドは None を返します。

writeto_mem(addr: int, memaddr: int, buf: bytes, *, addrsize: int = 8) None

memaddr で指定されたメモリアドレスから開始して、bufaddr で指定されたペリフェラルに書き込みます。引数 addrsize はアドレスサイズをビット単位で指定します。

このメソッドは None を返します。

class SoftI2C -- ソフトウェアでエミュレートされた I2C バス

SoftI2C クラスは、任意の GPIO ピンをビットバンギングすることで I2C を実装します。I2C と同じメソッド群に加え、非標準のトランザクションを組み立てる必要がある呼び出し元のために低レベルのプリミティブなバス操作(start()stop()readinto()write())を公開します。必要なピンがハードウェア I2C ブロックに配線されていない場合、ハードウェアが提供する数より多くのバスが必要な場合、あるいは特殊なシーケンス(追加のクロック、書き込み後のリピーテッドスタートなど)を要求するデバイスと通信する場合に使用してください。

コンストラクタ

class machine.SoftI2C(scl: Pin, sda: Pin, *, freq: int = 400000, timeout: int = 50000)

scl / sda によって駆動されるソフトウェア I2C バスを構築します。

freq は目標とする SCL クロックレート(Hz 単位)です(ビットバングループのオーバーヘッドにより、実際のレートは通常これより低くなります)。

timeout はクロックストレッチング(バス上の別のデバイスによって SCL が Low に保持されること)を待機する最大時間(マイクロ秒単位)です。これを超過すると OSError(ETIMEDOUT) が送出されます。

一般的なメソッド

init(scl: Pin, sda: Pin, *, freq: int = 400000) None

指定されたピンと周波数でソフトウェア I2C バスを再初期化します。同じオブジェクト上で新しい SoftI2C を構築するのと同等です。

scan() List[int]

0x08 から 0x77 まで(両端を含む)のすべての I2C アドレスをスキャンし、応答したもののリストを返します。

プリミティブな I2C 操作

以下のメソッドはプリミティブな I2C コントローラのバス操作を実装しており、組み合わせることで任意の I2C トランザクションを構成できます。これらは SoftI2C 専用です。ハードウェアの I2C クラスでは公開されていません。

start() None

バス上に START 条件を生成します(SCL が High の間に SDA が Low に遷移します)。

stop() None

バス上に STOP 条件を生成します(SCL が High の間に SDA が High に遷移します)。

readinto(buf: bytearray, nack: bool = True, /) None

バスから buf にバイトを読み込みます。len(buf) バイトが読み込まれ、最後のバイトを除く各バイトの後に ACK が送信されます。最後のバイトの後、nack=True(デフォルト)の場合は NACK を送信して転送を終了します。nack=False の場合は ACK を送信し、後続の readinto() のためにデバイスが選択されたままになります。

write(buf: bytes) int

buf をバスに書き込み、各バイトの後に ACK を確認します。最初の NACK で送信を停止します。受信した ACK の数を返します。

標準的なバス操作

以下のメソッドは、指定したペリフェラルデバイスを対象とする標準的な I2C コントローラの読み書き操作を実装します。

readfrom(addr: int, nbytes: int, stop: bool = True, /) bytes

7ビットアドレス addr のデバイスから nbytes を読み込みます。stop が真の場合、転送の最後に STOP 条件が生成されます。

readfrom_into(addr: int, buf: bytearray, stop: bool = True, /) None

addr のデバイスから buflen(buf) バイトを読み込みます。stop が真の場合、転送の最後に STOP 条件が生成されます。

writeto(addr: int, buf: bytes, stop: bool = True, /) int

bufaddr のデバイスに書き込みます。最初の NACK で送信を停止します。stop が真の場合、(早期に NACK が発生しても)転送の最後に必ず STOP 条件が生成されます。受信した ACK の数を返します。

writevto(addr: int, vector: tuple | list, stop: bool = True, /) int

vector 内のバッファを連結したものを、単一のトランザクションとして addr のデバイスに書き込みます。空のバッファは無視されます。stop のセマンティクスと戻り値については writeto() と同様に動作します。

メモリ操作

一部の I2C デバイスは、読み書きが可能なメモリデバイス(またはレジスタのセット)として動作します。この場合、I2C トランザクションには2つのアドレス、すなわちペリフェラルアドレスとメモリアドレスが関連付けられます。以下のメソッドは、このようなデバイスと通信するための便利なヘルパーです。

readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes

レジスタ memaddr から開始して、addr のデバイスから nbytes を読み込みます。addrsize はレジスタアドレスの幅をビット単位で指定します(通常は 8 または 16)。

readfrom_mem_into(addr: int, memaddr: int, buf: bytearray, *, addrsize: int = 8) None

レジスタ memaddr から開始して、addr のデバイスから buf に読み込みます。

writeto_mem(addr: int, memaddr: int, buf: bytes, *, addrsize: int = 8) None

レジスタ memaddr から開始して、bufaddr のデバイスに書き込みます。