Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

異なるマイコン同士でSPI通信をしたい

解決したいこと

マイコン同士でSPI通信をしたいが、うまく受信できないのでアドバイスいただきたい。

発生している問題・エラー

以下の図のように配線して、STMマイコン(センサを統合してpicoに送信)→pico(気象データを受信)に風速と風向のデータを送信したいです。
ラズパイ:Raspberry Pi Pico, 電源はUSB(micro Python)
STMマイコン:NUCLEO-F303K8, 電源はUSB(c++)
開発環境:Thonny V4.1.6
USBは同じPCのUSBポートに接続

image.png

NUCLEO-F303K8 (STM32ピン) Raspberry Pi Pico (SPI1ピン) 機能
PA_5 GP10 SCK (クロック)
PA_6 GP11 MOSI (送信)
PA_7 GP12 MISO (受信)
PA_4 GP13 CS (チップセレクト)

STMマイコンのプログラム(mbed Keil Studio Cloudでコンパイル)

#include "mbed.h"

// SPIオブジェクトの作成 (SPI1: PA_7=MOSI, PA_6=MISO, PA_5=SCK, PA_4=CS)
SPI spi(PA_7, PA_6, PA_5); // MOSI, MISO, SCK
DigitalOut led(LED1);      // デバッグ用LED

int main() {
    printf("NUCLEO-F303K8 SPI Slave Example\n");

    while (true) {
        // スレーブとしてデータを返送
        uint8_t wind_speed = 52;  // 例: 5.2 m/s を10倍して送信
        uint8_t wind_dir = 73;   // 例: 73度

        // マスターからの要求に応答してデータを送信
        uint8_t received = spi.write(wind_speed);  // 1バイト目(風速を送信)
        received = spi.write(wind_dir);            // 2バイト目(風向を送信)

        // デバッグ情報
        printf("Sent: Wind Speed=%d, Wind Direction=%d\n", wind_speed, wind_dir);
        led = !led;  // デバッグ用LEDをトグル
    }
}

実行結果:
Sending: Wind Speed=52, Wind Direction=73
Sending: Wind Speed=52, Wind Direction=73
Sending: Wind Speed=52, Wind Direction=73
・・・・

Rasp picoのプログラム(Thonnyでコード)

from machine import Pin, SPI
import time

# SPI1の初期化 (GP10=SCK, GP11=MOSI, GP12=MISO, GP13=CS)
spi = SPI(1, baudrate=500000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, 
          sck=Pin(10), mosi=Pin(11), miso=Pin(12))
cs = Pin(13, Pin.OUT)  # CSピン(アクティブLow)

cs.value(1)  # CSピンを初期状態で非アクティブ (High)

print("SPI Master Ready")

while True:
    cs.value(0)  # CSピンをアクティブ (Low)

    # スレーブにダミーデータを送信しながらデータを受信
    data = spi.read(2, 0xFF)  # 2バイトを受信(ダミーデータとして0xFFを送信)

    cs.value(1)  # CSピンを非アクティブ (High)

    wind_speed = data[0] / 10.0  # 風速デコード(例: 52 → 5.2 m/s)
    wind_dir = data[1]           # 風向デコード

    print(f"Received: Wind Speed={wind_speed} m/s, Wind Direction={wind_dir}°")
    time.sleep(1)  # 1秒待機


実行結果:
Received: Wind Speed=0.0 m/s, Wind Direction=0°
Received: Wind Speed=0.0 m/s, Wind Direction=0°
Received: Wind Speed=0.0 m/s, Wind Direction=0°
・・・・

できていないこと

受信の値が指定した数値になりません。
原因は何でしょうか。

0

2Answer

こんにちは。MasterとSlaveの送信受信の役割を逆にするのではないか思い回答させていただきます。
Masterが送信して、Slaveが応答を返す時にセンサのデータを入れるイメージになるのではないかと思いました。

Google AI Studioで生成したコードしてみて、
Master側は何となくイメージ通りのコードが出てきたので参考情報として貼り付けています。

質問:
Micro Pythonをマスタ側、C++をスレーブ側とするSPI通信のサンプルプログラムを出力して

出力コード:

master.py
from machine import Pin, SPI
import time

# SPIの設定
spi = SPI(0,
          baudrate=1000000, # クロック周波数 (調整可能)
          polarity=0,      # クロック極性 (調整可能)
          phase=0,         # クロック位相 (調整可能)
          sck=Pin(6),       # SCKピン
          mosi=Pin(7),      # MOSIピン
          miso=Pin(4))      # MISOピン
cs = Pin(5, Pin.OUT)  # CSピン

def spi_transfer(data):
    cs.value(0)   # CSピンをLOWにしてスレーブを選択
    time.sleep_us(1) # 安定化のための少しの遅延
    result = spi.write_readinto(data, bytearray(len(data)))
    time.sleep_us(1)
    cs.value(1)  # CSピンをHIGHにしてスレーブの選択を解除
    return result

# メイン処理
while True:
    # 送信するデータ
    send_data = bytearray([0x12, 0x34, 0x56, 0x78]) 
    
    # データ送信と受信
    recv_data = spi_transfer(send_data) #ここで適当なデータを送信して、応答として測定データを受け取る
    
    # 受信したデータの表示
    print("Sent: ", [hex(x) for x in send_data])
    print("Received: ", [hex(x) for x in recv_data])
    
    time.sleep(1)  # 1秒待機 
0Like

SPIは、通常はマイコン側が「マスター」、デバイス(センサー)側が「スレーブ」となって、同一のSPIバスに、複数のSPIスレーブデバイスを接続することができます。UARTのような、一対一通信ではありませんが、複数のスレーブと同時に通信することはできないため、通信するスレーブを指定するためにマスター側が SS (Slave Select) を LOW にするのが一般的です。
よって、マイコン同士のSPIにおいても、どちらかが「マスター」、他方が「スレーブ」として振る舞う必要があります(そのように振る舞うプログラムを作成するということです)。

ピン割り当て(接続)ですが、MOSI(Master Out Slave In)は MOSI、MISO(Master In Slave Out)は MISO と接続します(クロス接続ではありません)。

なお、マイコンでスレーブ側を実装するのは少々面倒かも知れません。一対一通信であれば UART接続の方が簡単だと思いますが、通信速度はSPIに劣ります。

追伸;
どちらのマイコンもPCのUSBから電源を得るなら、VINーVSYSの接続は不要(やめた方はよいと思う)。GND同士の接続だけとする(同一PCなら、これも不要)。

0Like

Your answer might help someone💌