LoginSignup
0
1

More than 3 years have passed since last update.

pythonでシリアル通信制御してSPI通信する(USBGPIO8デバイスを使用します)

Last updated at Posted at 2020-04-03

本記事について

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 とします

GPIO8_SPI_回路図.png

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ビットは読み込んだ下位バイト

以上です

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1