1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FPGAとRaspberryPi picoWでSPI通信(その①ラズピコのSPIマスター)

Last updated at Posted at 2025-01-14

概要

FPGAとラズピコをSPI通信で連携して、ラズピコからFPGAのレジスタ設定を書き換えます。
今回はピコのSPIマスターの実装方法について紹介します。

image.png

通信フォーマット

SPI通信はタイミングについては規定があるものの、データの内訳についてはデバイス依存になります。
つまり、FPGAの場合はデータの内訳は自由ということになりますので、以下の通りの通信フォーマットを採用するものとします。

  • CSはLow有意
  • クロックエッジは立ち上がりでサンプリング
  • クロック周波数は1MHz
  • データは32bit(アドレス8bit + コマンド4bit + ダミー54bit + データ16bit)
  • データはMSBファースト

image.png

コード

main.py
from machine import Pin
from machine import SPI
import sys
import select
#================================================================
# SPI親分クラス
#================================================================
class SPI_master():
    def __init__(self):
        # SPI設定 (SPI0: CLK=GP2, MOSI=GP3, MISO=GP4)
        self.spi = SPI(0, baudrate=1000000, polarity=0, phase=0, sck=Pin(2), mosi=Pin(3), miso=Pin(4))
        # SPI Chip Selectピン設定
        self.cs = Pin(5, Pin.OUT)
        self.cs.value(1)  # 初期状態はHigh(非アクティブ)にしておく
    #-----------------------------------------------------------
    # SPI書込み
    #-----------------------------------------------------------
    def Write(self,adr: int, data: int):
        cmd=0x60    # 書込みコマンド
        __txData = bytearray([adr & 0xFF, cmd, (data >> 8) & 0xFF, data & 0xFF])  # 4バイトにパッキング
        self.cs.value(0)        # CSをLowにアサート
        self.spi.write(__txData)# パッキングしたデータを送信
        self.cs.value(1)        # CSをHighにネゲート

        print("Write   data:", [hex(b) for b in __txData])  # バイト単位で表示
    #-----------------------------------------------------------
    # SPI読み出
    #-----------------------------------------------------------
    def Read(self,adr: int):
        cmd=0x90    # 読み出しコマンド
        __txData = bytearray([adr & 0xFF, cmd, 0, 0])
        __rxData = bytearray(len(__txData))
        self.cs.value(0)
        #self.spi.write(__packet)
        #__packet = self.spi.read(4)
        self.spi.write_readinto(__txData, __rxData)
        self.cs.value(1)
        print("Send     data:", [hex(b) for b in __txData])  # バイト単位で表示
        print("Received data:", [hex(b) for b in __rxData])  # バイト単位で表示
        return __rxData
#===========================================================
# 非ブロッキングでキー入力をチェックする関数
def check_key_input():
    if select.select([sys.stdin], [], [], 0)[0]:
        return sys.stdin.read(1)
    return None
#=====================================================================
#
#=====================================================================
spi_master=SPI_master()
while True:
    #キー入力を受け取る
    user_input = check_key_input()
    #キー入力に応じてSPIライト
    if user_input == 'a':
        spi_master.Write(0x55, 0xFFFF)
    if user_input == 'b':
        spi_master.Write(0x55, 0x1234)
    if user_input == 'c':
        spi_master.Write(0x55, 0xEDCB)
    if user_input == 'z':
        spi_master.Write(0x55, 0x0000)
    if user_input == 'r':
        r=spi_master.Read(0x55)

余談:SPIのインターバル

データ送信する際にバイトデータをパッキングしないで送ることも可能ですが、インターバル時間が長いのでパックした方が良さげです。

    def SpiWrite(self,adr: int, data: int):
        cmd=0x60    # 書込みコマンド
        self.cs.value(0)  # CSをLowにアサート
        self.spi.write(bytearray([adr & 0xFF]))          # adrを1バイトに変換して送信
        self.spi.write(bytearray([cmd]))                 # cmdを1バイトに変換して送信
        self.spi.write(bytearray([(data >> 8) & 0xFF]))  # dataの上位Byte送信
        self.spi.write(bytearray([data & 0xFF]))         # dataの下位Byte送信
        self.cs.value(1)  # CSをHighにネゲート

image.png

image.png

おわりに

FPGA側のSPIスレーブについては別記事にして投稿したいと思います。

1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?