2023年7月10日月曜日

adafruitのcircuit pythonでSPIの通信速度を通信先によって変える


背景

SPIとは通信方式の一つです。
SPIで制御するタッチ機能付きのLCDをRaspberry Piで扱った際にタッチ機能のICに合わせてプログラム全体の通信速度を落としましたが通信相手によって通信速度の切り替えはできるはずだと思ったので、調べて把握しました。

把握した内容を共有します。

使ったもの


書き方1 adafruit_bus_deviceのspi_device.SPIDeviceを使う

参考にしたadafruitのlcdのライブラリはSPIDeviceを使っており、それをwithで利用する度busioのspiのconfigureを呼び出して通信速度の設定とcsピンの切り替えが行われていました。
ということで、下記のように通信相手ごとにSPIDeviceで速度とcsを指定すると、withで呼び出す度に通信速度とcsピンを切り替えてくれます。
from adafruit_bus_device import spi_device
import board
from busio import SPI
from digitalio import DigitalInOut

cs_pin_device_A = DigitalInOut(board.D1)
cs_pin_device_B = DigitalInOut(board.D7)

baudrate_device_A = 24000000
baudrate_device_B = 4000000

spi = SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO)
spi_device_A = spi_device.SPIDevice(
spi, chip_select=cs_pin_device_A, baudrate=baudrate_device_A)
spi_device_B = spi_device.SPIDevice(
spi, chip_select=cs_pin_device_B, baudrate=baudrate_device_B)

while True:
rx_buf = bytearray(3)
tx_buf = bytearray(3)
with spi_device_A as spi_A:
# do something
spi_A.write_readinto(tx_buf, rx_buf)
print(rx_buf)
with spi_device_B as spi_B:
# do something
tx_buf[0] = 0b11010000
spi_B.write_readinto(tx_buf, rx_buf)
print(rx_buf)

書き方2 busioのspiのconfigure関数を使う

既存のライブラリを利用しつつ通信速度だけ変えたいなど何らかの理由でSPIDeviceに頼らず通信速度を切り替えたい場合は、busioのspiの__enter__で行われるようにconfigure関数を呼び出せば通信速度を再設定できます。
import board
from busio import SPI
from digitalio import DigitalInOut, Direction

cs_pin_device_A = DigitalInOut(board.D1)
cs_pin_device_B = DigitalInOut(board.D7)

cs_pin_device_A.direction = Direction.OUTPUT
cs_pin_device_A.value = True
cs_pin_device_B.direction = Direction.OUTPUT
cs_pin_device_B.value = True

baudrate_device_A = 24000000
baudrate_device_B = 4000000

spi = SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO)


def change_baudrate_of_spi(new_baudrate: SPI):
while not spi.try_lock():
pass
spi.configure(baudrate=new_baudrate)
spi.unlock()


while True:
rx_buf = bytearray(3)
tx_buf = bytearray(3)

while not spi.try_lock():
pass
spi.configure(baudrate=baudrate_device_A)
cs_pin_device_A.value = False
# do something for device A
spi.write_readinto(tx_buf, rx_buf)
cs_pin_device_A.value = True
spi.unlock()

while not spi.try_lock():
pass
spi.configure(baudrate=baudrate_device_B)
cs_pin_device_B.value = False
tx_buf[0] = 0b11010000
# do something for device B
spi.write_readinto(tx_buf, rx_buf)
cs_pin_device_B.value = True
spi.unlock()
print(rx_buf)

configure呼び出し前はspiのlockが必要です。
通信後はunlockしてください。
    while not spi.try_lock():
pass
spi.configure(baudrate=baudrate_device_A)
    spi.unlock()

なお、configure関数はbaudrate以外の値(polrity, phase, bits)も上書きするので、それらを標準設定以外で使う場合は接い速度設定の際に一緒に書き込んでください。
書き方1のSPIDeviceを使うとそれらの値もコンストラクタ作成時に渡した値で再設定されるので、なるべくSPIDeviceの利用をお勧めします。

おわり

adafruitのSPIClassを利用してRaspberry PiのSPIの通信速度を通信先ごとに切り替える方法を把握しました。

参考

CurcuitPython busdeviceライブラリ
通信速度の更新が行われるbusioのspiの__enter__

0 件のコメント :