

こんにちは，  
現在，ラズパイが4byteを生成し，それを1byteずつSPIで送り，Arduinoが4byte受け取ったら繋げて情報を復元する，というプログラムを作っています．floatを送りたかったのです．(正直，小数点の数字さえ送れるなら
I2CでもSPIでも良いですが，海外サイトを含めて統一的に書いているサイトが見つけられませんでした．もう五日くらい探しています）

うまいこと作れたのですが，早いループだと受信側?がきちんと数を再構成できずに，メチャクチャな数字を吐き出します．これはおそらく，Arduinoが受け取りのタイミングをミスして，間違った結合で数を再構築しているからだと思います．Arduinoは，「1bye受け取るたびに
counter に+1して，counter==4
になると，つまり4byte揃うと今までのデータを結合する」という単純な処理になっています．これはつまり，”4回受信さえ”すれば，とにかくくっつけて吐き出してください，という処理のため，メチャクチャな数字を吐き出すのだと考えます．  
ラズパイ側がそもそもbyteを伝えられていない(レベルシフターを使っていないので，Arduinoは3.3Vの矩形波を受け取っていて，それがよくない?)
など他にも問題があるかもしれませんが，まずは一番考えられそうな，タイミングずれてる問題について質問します．何かうまいこと，「4byteの数字を受け取ったら結合」という指示にできませんでしょうか，あるいはそれ以外でまずいことをしていたら教えていただきたいです．

[code]

    //Arduinoスレーブコード
    #include <SPI.h>
    
      
    
    volatile uint32_t data[4];
    volatile uint8_t count=0;
    
    union my_receive_data_converter_type {
        uint8_t bytes[4]; // SPI 受信１回に含まれるペイロードバイト
        float value; // SPI 受信４回で成立する float の値
    };
    
    
    
    
    void setup(){
        Serial.begin(115200);
        SPCR |= _BV(SPE);
        SPI.attachInterrupt();  // (3)
      
        
        
    }
    
    void loop(){
    
    
      
    }
    
    
    
    
    ISR(SPI_STC_vect){  // (4)
    
        
      data[count]=SPDR;
      count += 1;
      
      if(count==4){
        count=0;
    
    
      my_receive_data_converter_type f;
      for (int i=0; i<4; ++i) { f.bytes[i]=(uint8_t)(data[i]&0xFF); }
      Serial.println((f.value));
    
      }
    
    
    }
    
[/code]

次にマスターです．piを一回こっきり送るだけは成功します．が，While loopのように連続送信ではクラッシュします．

[code]

    #Raspiマスターコード
    
    
    import spidev
    import RPi.GPIO as GPIO
    import struct
    
    
    spi=spidev.SpiDev()
    spi.open(0,0)
    spi.max_speed_hz =250000
    spi.lsbfirst=False
    channel=2
    TIME=0
    
    buff=struct.pack("<f",3.141592)
    bytelist=list(buff)
    spi.xfer2(bytelist)
    #spi.xfer2([1])
    spi.close()
    
    """
    #------RUN main------------------
    while True:
       
        Timer = time.perf_counter()
        TIME += dt
        
    
        buff=struct.pack("<f",TIME)
        bytelist=list(buff)
        spi.xfer2(bytelist)
    
    
        dt = time.perf_counter() - Timer
    """
    
[/code]


CC BY-SA 4.0
2022-09-21T05:32:02.137
91206
2022-09-21T07:25:44.070
41334
question
python c++ c raspberry-pi arduino
ラズパイ to Arduino: SPI送受信のタイミングが合わずに乱れる


その使用している相手のデバイスのデータシートをよく読もう。

SPIってのは単にバイトデータを連続して送るだけなので、途中でなにかあって余計なビットが欠落したり余分に認識したりするとあとのデータ送信/受信が破綻します。  
こうならないように、SPIデバイス側ではCS(ChipSelect)信号などで同期を取ります  
提示のコードでは、こういう同期用の操作というのが見えません

あまつさえ、一つの信号を送るたびに、いちいちSPIデバイスのOpen/Closeを繰り返しているというのは非常にマズイです。デバイスをCloseすると言うのは当該ポートを開放するってことなので、その間にポートになにがあっても知ったこっちゃないということになります

＃別質問の質疑応答もそうですが、まだまだそういうのを扱うスキルがついてないような気がします。


CC BY-SA 4.0
2022-09-21T07:25:44.070
91213
2022-09-21T07:25:44.070
27481
91206
answer