2019年7月8日月曜日

NodeMCU DevKit & MicroPython & SPI MCP23S17 x 2

2つのMCP23S17をSPIで接続使用するテスト。
動作環境はNodeMCU DevKitとMicroPython。
NodeMCU DevKitで使用するのは以下のピン。
SPIは、 CSで使用するデバイスを選択します。
つまりデバイスが2個だとSPIピンと合わせて、5ピン。4個だと7ピン、8個では11ピンと、デバイスの数だけGPIOを消費します。
論理回路つ組み合わせれば、最大6ピンに抑える事も可能ですが、NodeMCU DevKitは元からGPIOピンが少ないので削減は控えたいところ。
で、MCP23S17にはアドレス指定のモードもあるので、そちらを使用してみます。

とりあえず、MCP23S17とLEDを配線。
MCP23S17のアドレスは、0x20(0x41/0x40)と0x21(0x43/0x42)に設定。
NodeMCUを起動して、必要となるSPIとPinクラスををインポート。
Ctrl + eを押してからコピペしてCtrl + d。
MicroPython v1.10-8-g8b7039d7d on 2019-01-26; ESP module with ESP8266
Type "help()" for more information.
>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
===
===
===
===
from machine import SPI, Pin
spi = SPI(1, baudrate=10000000, polarity=0, phase=0)
cs = Pin(15, Pin.OUT)
cs.value(1)
# SPI、Pinクラスのインポート
# SPIオブジェクトの作成
# CSピンのアサイン
# CSピンをHIGHに

===
>>>
以上でSPIを使用するための準備は完了。
アドレスでデバイス選択を行うための設定方法を確認。
IOCON : コンフィグレーションレジスタ(0x0A:0x0B:0x05:0x15)
bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL -
0 0 0 0 0 0 0 0 0x00
1 1 1 1 1 1 1 0 0xFE
BANK レジスタのアドレス指定を制御する
1 各ポートに関連付けられているレジスタが別々のバンクに分かれる
0 レジスタが全部同じバンクに入れられる(アドレスが連続した状態)
MIRROR INT ピンの Mirror ビット
1 INT ピン同士を内部接続する
0 INT ピン同士を接続しない。INTA は PORTA に関連付けられ、INTB は PORTB に関連付けられる。
SEQOP シーケンシャル動作モードビット
1 シーケンシャル動作が無効になり、アドレスポインタはインクリメントされない
0 シーケンシャル動作が有効になり、アドレスポインタがインクリメントされる
DISSLW SDA 出力のスルーレート制御ビット
1 スルーレートは無効
0 スルーレートは有効
HAEN ハードウェア アドレス イネーブル ビット
1 MCP23S17 のアドレスピンを有効にする
0 MCP23S17 のアドレスピンを無効にする
ODR INT ピンをオープンドレイン出力として設定する
1 オープンドレイン出力 (INTPOL ビットよりも優先される )
0 アクティブ ドライバ出力 ( 極性は INTPOL ビットで設定する )
INTPOL このビットで INT 出力ピンの極性を設定する
1 アクティブ High
0 アクティブ Low
で、使用するのは、HAENの箇所。
アドレスピンを有効化するので、0x08(0b00001000)を指定。
>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
===
===
===
cs.value(0)
spi.write(b'\x40\x0A\x08')
cs.value(1)
# CSピンをLOWに変更
# 制御バイト(0x40)、レジスタアドレス(0x0A)に"0x08"を送信
# CSピンをHIGHに戻す

>>>
2個目のMCP23S17のLED"だけ"を点灯してみます。
>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
===
===
===
===
===
===
cs.value(0)
spi.write(b'\x42\x00\x00')
cs.value(1)
cs.value(0)
spi.write(b'\x42\x12\xFF')
cs.value(1)
# CSピンをLOWに変更
# 制御バイト(0x42)、レジスタアドレス(0x00)に"0x00"を送信
# CSピンをHIGHに戻す
# CSピンをLOWに変更
# 制御バイト(0x42)、レジスタアドレス(0x12)に"0xFF"を送信
# CSピンをHIGHに戻す

>>>
両方のLEDが点灯したようなら、もう一度配線を含め設定を見直してみましょう。
問題なければ恒例のLチカしてみます。
そのまま書くと長くなるので、I2Cでの命令っぽく関数化。
>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
===
===
===
===
===
===
===
def writeto_mem(addr, memaddr, bufs):
    global spi, cs
    cs.value(0)
    spi.write((addr*2).to_bytes(1, 'big'))
    spi.write(memaddr.to_bytes(1, 'big'))
    spi.write(bufs)
    cs.value(1)

>>>
初めての関数なので超適当です。ちゃんとクラス化した方が良さそうですね。
動作テスト。
>>>
>>>
>>>
>>>
>>>
>>>
writeto_mem(0x20,0x12, b'\x00')
writeto_mem(0x21,0x12, b'\xff')
writeto_mem(0x20,0x12, b'\xff')
writeto_mem(0x21,0x12, b'\x00')
writeto_mem(0x20,0x12, b'\x00')
writeto_mem(0x21,0x12, b'\x00')

>>>
一応動いたっぽいので、Lチカ。
from time import sleep
from machine import SPI, Pin

def writeto_mem(addr, memaddr, bufs):
	global spi, cs
	cs.value(0)
	spi.write((addr*2).to_bytes(1, 'big'))
	spi.write(memaddr.to_bytes(1, 'big'))
	spi.write(bufs)
	cs.value(1)

spi = SPI(1, baudrate=10000000, polarity=0, phase=0)
cs = Pin(15, Pin.OUT)
cs.value(1)

writeto_mem(0x20, 0x00, b'\x00')
writeto_mem(0x21, 0x00, b'\x00')

for i in range(10) :
	writeto_mem(0x20, 0x12, b'\xFF')
	writeto_mem(0x21, 0x12, b'\x00')
	sleep(0.5)
	writeto_mem(0x20, 0x12, b'\x00')
	writeto_mem(0x21, 0x12, b'\xFF')
	sleep(0.5)
LEF8個づつが交互に点滅。
from time import sleep
from machine import SPI, Pin

def writeto_mem(addr, memaddr, bufs):
	global spi, cs
	cs.value(0)
	spi.write((addr*2).to_bytes(1, 'big'))
	spi.write(memaddr.to_bytes(1, 'big'))
	spi.write(bufs)
	cs.value(1)

mods = bytearray(2) 
bits = [1,2,4,8,16,32,64,128]
spi = SPI(1, baudrate=10000000, polarity=0, phase=0)
cs = Pin(15, Pin.OUT)
cs.value(1)

writeto_mem(0x20, 0x00, b'\x00')
writeto_mem(0x21, 0x00, b'\x00')

while True:
	for b in range(len(mods)) :
		m = 1 - b
		addr = 0x20+1
		for i in bits :
			mods[m] += i
			writeto_mem(addr, 0x12, mods[m].to_bytes(1, 'big'))
			sleep(0.5)
writeto_mem(0x20, 0x12, b'\x00')
writeto_mem(0x21, 0x12, b'\x00')
LEDの右から順番に左端までの点灯を繰り返すだけの動作。
とりあえず、使えるところまで。
う~ん、やっぱりクラス化したりメソッド化したりしないと手間が多いかな。

0 件のコメント:

コメントを投稿