Nucleo-F767ZI + SSD1306(I2C)の接続

以下のやり取りで、MicroPythonのI2C APIについて一部誤解していたことが分かりました・・・

Pyboard + SSD1306 – Page 3 – MicroPython Forum

以下を実行すると、スレーブアドレスaddrのデバイスに対してbuf1とbuf2を連結したデータが送られると思っていたのですが

i2c.writeto(addr, buf1, False)
i2c.writeto(addr, buf2)

そうではなく、I2Cバス上では「start bit + addr + buf1 + restart bit + addr + buf2 + stop bit」が送られるのでした。
データとしてはbuf1とbuf2はaddrで分断されてしまい、連結することはできません。

分断せずにデータをつなげて送るには、低レイヤAPIのi2c.write(buf)を使えば実現可能ですが、低レイヤAPIはI2Cのソフトウェア実装でしかサポートされていません。
このため、writeto()において送信データのリストを受け取れるようにする仕様拡張が以下で検討されています。

docs/library/machine.I2C.rst: Extend writeto to support a list of bufs. by dpgeorge · Pull Request #4020 · micropython/micropython

この仕様が実現されると、writeto(addr, [buf1, buf2])という記法が可能になるようです。

以下、STM32(Nucleo-F767ZI)のMicroPythonでSoftware I2CとHardware I2Cの確認をしたのでメモです。
OLEDをI2Cで接続しました。

この接続で、Hardware I2Cを使用する場合のコードは以下のようになります。

import machine
i2c=machine.I2C(1)

同じ接続でSoftware I2Cを使うこともできます。
この場合はピンをGPIOとして使用し、以下のようなコードになります。

import machine
pscl = machine.Pin('B8', machine.Pin.OPEN_DRAIN)
psda = machine.Pin('B9', machine.Pin.OPEN_DRAIN)
i2c = machine.I2C(scl=pscl, sda=psda)

両者はいずれも同じAPIを持ちますが、

>>> dir(i2c)
['__class__', 'init', 'readfrom', 'readfrom_into', 'readfrom_mem', 'readfrom_mem_into', 'readinto', 'scan', 'start', 'stop', 'write', 'writeto', 'writeto_mem']

Hardware I2Cの場合は実装されていないメソッドを呼ぶとエラーが返ります。

>>> i2c.write([])
Traceback (most recent call last):
  File "", line 1, in 
OSError: I2C operation not supported

ベアメタルRaspberry Piでの実装は後ほど修正する予定です。

コメント