本記事について
pythonでシリアル通信制御してI2C通信する(USBGPIO8デバイスを使用します)の系列記事となりますので先にI2C編をお読みください。
SPI通信について
基本的な仕様はありますがIC毎のデータシートを参照したほうが良いと思います。
一般的なSPI通信については下記が分かりやすく説明されています。
http://www.picfun.com/f1/f05.html
https://lab.fujiele.co.jp/articles/8191/
注意
本記事で使用するEEPROM(AT93C46) はCS(チップセレクト)が通常と逆で
HIGHで通信開始、LOWで通信終了となります。
一般的にははLOWで通信開始、HIGHで通信終了です。
一般的なICで実験すれば良かったのですがSPIを使うICの中でAT93C46が30円と一番安かったのでAT93C46にしました、その結果汎用性に欠けた記事となりました。
なにをするか
pythonでシリアル通信を使いUSBGPIO8を制御、USBGPIO8からIC(EEPROM)を制御、2バイト書き込みその後2バイト読み込み書き込んだ値が読み込める事を確認します。
回路図
USBGPIO8 の 0番ポートを CS とします
USBGPIO8 の 1番ポートを SK とします(クロック)
USBGPIO8 の 2番ポートを DI とします
USBGPIO8 の 3番ポートを DO とします
EEPROM(AT93C46)の使い方
ハード設定
6番(ORG)をVcc接続で16bitモード
6番(ORG)をGND接続で8bitモード
となります、今回は16bitモードで動作させます。
16bitモードでは64アドレスx2バイト、合計128バイトのデータを保存できます。
AT93C46命令セット
・EWEN 書き込み許可状態
・WRITE 書き込み
・READ 読み込み
今回はこの3命令を使います。
書き込むためには起動時にEWENモードにする必要があります、一度EWENモードにしたら電源を切るまでモードは維持されます。
送信データは
SB + OP + [データ等...]
という構成を取ります。
SB = [00000001] 固定
OP = [????????] モードにより定められているパターン+アドレス等を付加する
データ等はあれば追加する。
具体的な例を示す
※ ? 記号は任意の 0 か 1 を設定する
EWENモード
SB[00000001]
OP[00110000]
>0000000100110000
と続けて送信
WRITEモード
SB[00000001]
OP[010?????] 下位5ビットは書き込みアドレス
上位バイト[????????]
下位バイト[????????]
>00000001010?????????????????????
と続けて送信
READモード
SB[00000001]
OP[100?????] 下位5ビットは読み込みアドレス
上位バイト用ダミー[00000000] DOから受信するためのダミーデータ
下位バイト用ダミー[00000000] DOから受信するためのダミーデータ
>00000001100?????0000000000000000
と続けて送信
プログラム構造
pythonでシリアル通信制御してI2C通信する(USBGPIO8デバイスを使用します)と同様ですのでそちらを参照
ソースコード
# usbgpio8_spi_read_write_sample.py
import serial
import sys
import time
SerialInstance = None
def SerialInit(comString):
global SerialInstance
#SerialInstance = serial.Serial(comString, 115200, timeout=0.01)
SerialInstance = serial.Serial(comString, 19200, timeout=0.1)
def SerialEnd():
SerialInstance.close()
def SerialTalk(cmd, response=False):
readLen = len(cmd) + 1 # gpio read 0\n\r # 最初から \r が付いているので +2 ではなく +1 する
if response == True:
readLen += 3 # N\n\r
readLen += 1 # >
cnt = SerialInstance.write(cmd.encode())
res = SerialInstance.read(readLen)
res = res.decode("utf-8").strip()
return res
def gpioHigh(n):
SerialTalk("gpio set {}\r".format(n))
def gpioLow(n):
SerialTalk("gpio clear {}\r".format(n))
def gpioRead(n):
res = SerialTalk("gpio read {}\r".format(n), response=True)
return res
def ByteToLH(b):
lh = []
for i in range(8):
if (b << i & 128) == 0:
lh.append(0)
else:
lh.append(1)
return lh
def CS_LOW():
gpioLow(0)
def CS_HIGH():
gpioHigh(0)
def SCK_LOW():
gpioLow(1)
def SCK_HIGH():
gpioHigh(1)
def DI_LOW():
gpioLow(2)
def DI_HIGH():
gpioHigh(2)
def READ_DATA():
return gpioRead(3)
def parseData(all):
res = []
for l in all:
a = l.split("\n\r")
res.append(a[1])
return res
def SPI_CommandExec(cmd):
# start condition
size = len(cmd)
data = []
SCK_LOW()
for i in range(size):
d = cmd[i]
if d == 0:
DI_LOW()
elif d == 1:
DI_HIGH()
SCK_HIGH()
if d == 2:
b = READ_DATA()
data.append(b)
SCK_LOW()
return parseData(data)
def WriteBytes(addr, buffer1, buffer2):
# EWEN command
SB = ByteToLH(0b00000001)
OP = ByteToLH(0b00110000)
cmdEWEN = SB + OP
# exec
CS_HIGH()
resEWEN = SPI_CommandExec(cmdEWEN)
CS_LOW()
# write command
SB = ByteToLH(0b00000001)
OP = ByteToLH(0b01000000 | (addr & 0x3f))
buffer1 = ByteToLH(buffer1)
buffer2 = ByteToLH(buffer2)
cmdWrite = SB + OP + buffer1 + buffer2
# exec
CS_HIGH()
resWrite = SPI_CommandExec(cmdWrite)
CS_LOW()
# 書き込み待ち、仕様では5msだが適当に長く待つ
time.sleep(0.01)
response = resEWEN + resWrite
return response
def ReadBytes(addr):
# create command
SB = ByteToLH(0b00000001)
OP = ByteToLH(0b10000000 | (addr & 0x3f))
buffer1 = [2] * 8
buffer2 = [2] * 8
cmd = SB + OP + buffer1 + buffer2
CS_HIGH()
response = SPI_CommandExec(cmd)
CS_LOW()
return response
def Test_WriteBytes(comString):
SerialInit(comString)
response = WriteBytes(7, 0x34, 0x56)
print(response)
SerialEnd()
def Test_ReadBytes(comString):
SerialInit(comString)
response = ReadBytes(7)
print(response)
SerialEnd()
def run(comString):
Test_WriteBytes(comString)
Test_ReadBytes(comString)
if __name__ == "__main__":
run(sys.argv[1])
# python usbgpio8_spi_read_write_sample.py COM4
使い方
Linuxの場合
python usbgpio8_spi_read_write_sample.py /dev/ttyUSB0
Windowsの場合
python usbgpio8_spi_read_write_sample.py COM4
戻り値の見方
[] # 書き込み時は特に無し
['0', '0', '1', '1', '0', '1', '0', '0', '0', '1', '0', '1', '0', '1', '1', '0'] # 先頭8ビットは読み込んだ上位バイト、続く8ビットは読み込んだ下位バイト