title: Unreliable SPI byte array transfer from Arduino to Raspberry Pi
body: <p>I'm working on a project that collects data from an Arduino Pro Mini and sends it using SPI to a raspberry Pi for storage.</p>
  
  <p>The Pro Mini will be reading analog input and calculating voltage (once I finish), and passing values to the Pi when prompted using an ISR.</p>
  
  <p>I'm using C/C++ for both platforms to keep it uniform. The slave code is snipped together using Arduino IDE and the master code is based off a BCM2835 SPI library example for the Pi. </p>
  
  <p>Arduino code is meant to calculate a <strong>float</strong> value and pre-process the float value into an array of 4 bytes/chars (I'm shooting for binary because I think it is the best way to go).
  Once prompted by the Pi, each byte is sent and will be recompiled into a float.</p>
  
  <p>Here is what I have now:</p>
  
  <p>Slave</p>
  
  <pre><code>/*************************************************************
  ARDUINO BREAKER READ/SPI PRE-PROC/TRANSMIT CASES
  ****************************************************************/
  
  /***************************************************************
   Global Variables
  ***************************************************************/
  
  byte command = 0; //command from PI
  byte bytes[4];    //
  
  int sensorVoltage, sensorCurrent; //eventual live reading vars
  float Voltage, Current, RealCurrent, RealVoltage, Power;
  
  /***************************************************************
   Set Up
    -designate arudino as slave
    -turn on interrupts
  ***************************************************************/
  
  void setup (void)
  {
    //debugging with serial monitor
    Serial.begin(9600);
  
    // Set up arduino as slave
    pinMode(MOSI, INPUT);
    pinMode(SCK, INPUT);
    pinMode(SS, INPUT);   
    pinMode(MISO, OUTPUT);
  
    // turn on SPI in slave mode
    SPCR |= _BV(SPE);
  
    // turn on interrupts
    SPCR |= _BV(SPIE);
  
  }  // end of setup
  
  /*************************************************************
   Interrupt Service Routine 
   ************************************************************/
  
  // SPI interrupt routine
  ISR (SPI_STC_vect)
  {
    delay(500); //for errors
  
    // Create union of shared memory space
    union 
    {
      float f_var;
      unsigned char bytes[4];
    } u;
  
    // Overwrite bytes of union with float variable
    u.f_var = RealVoltage;
  
    // Assign bytes to input array
    memcpy(bytes, u.bytes, 4);
  
    byte c = SPDR;
    command = c; 
  
    switch (command)
    {
    // null command zeroes register
    case 0:
  
      SPDR = 0;
      break;
  
    // case a - d reserved for voltage
    case 'a':
      SPDR = bytes[3];  
      break;
  
    // incoming byte, return byte result
    case 'b':
  
      SPDR = bytes[2];  
      break;
  
    // incoming byte, return byte result    
    case 'c':
  
      SPDR =  bytes[1];  
      break;
  
  
    // incoming byte, return byte result    
    case 'd':
  
      SPDR = bytes[0];  
      break;
  
   /**  // case e -h reserved for current
    case 'e':
  
      SPDR = amps.b[0];  
      break;
  
    // incoming byte, return byte result
    case 'f':
  
      SPDR = amps.b[1];  
      break;
  
    // incoming byte, return byte result    
    case 'g':
  
      SPDR = amps.b[2];  
      break;
  
    // incoming byte, return byte result    
    case 'h':
  
      SPDR = amps.b[3];  
      break;
  
     // case i - l reserved for wattage
    case 'i':
  
      SPDR = watts.b[0];  
      break;
  
    // incoming byte, return byte result
    case 'j':
  
      SPDR = watts.b[1];  
      break;
  
    // incoming byte, return byte result    
    case 'k':
  
      SPDR = watts.b[2];  
      break;
  
    // incoming byte, return byte result    
    case 'l':
  
      SPDR = watts.b[3];  
      break;**/
  
    } // end of switch
  
  }  // end of interrupt service routine (ISR) SPI_STC_vect
  
  /***************************************************************  
   Loop until slave is enabled by Pi.
  ****************************************************************/
  void loop (void)
  {
  /*************************************************************
  Read and Calculate
  ****************************************************************/
  
    /**
    sensorVoltage = analogRead(A2);
    sensorCurrent = analogRead(A3);
    Voltage = sensorVoltage*(5.0/1023.0);
    Current = sensorCurrent*(5.0/1023.0);
    RealCurrent = Current/0.204545;
    RealVoltage = (Voltage/0.022005);
    Power = RealVoltage*RealCurrent;
  **/
    RealVoltage = 1.234;
  /*************************************************************
  Loop Check for SS activation
  ****************************************************************/
  
    // if SPI not active, clear current command, else preproc floats and pass to SPI
    if (digitalRead (SS) == HIGH){
      command = 0;
    }
  /*************************************************************
  Debug with serial monitor
  ****************************************************************/
  /*
    Serial.print("Byte 3: ");
    Serial.println(bytes[3],BIN);
    delay(500);
    Serial.print("Byte 2: ");
    Serial.println(bytes[2],BIN);
    delay(500);
    Serial.print("Byte 1: ");
    Serial.println(bytes[1],BIN);
    delay(500);
    Serial.print("Byte 0: ");
    Serial.println(bytes[0],BIN);
    delay(1000);
    Serial.println();*/
  }
  </code></pre>
  
  <p>Master</p>
  
  <pre><code>#include &lt;bcm2835.h&gt;
  #include &lt;stdio.h&gt;
  
  
  void setup()
  {
      bcm2835_spi_begin();
      bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_LSBFIRST);      // The default
      bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);                   // The default
      bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536); // The default
      bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);      // the default
  }
  
  char getByte(const char command){
  
      char read_data = bcm2835_spi_transfer(command);
      delay(100);
      return read_data;
  }
  
  int main(int argc, char **argv)
  {
  //If you call this, it will not actually access the GPIO
  //Use for testing
  //bcm2835_set_debug(1);
  
      if (!bcm2835_init())
          return 1;
      setup();
  
  //Start communication       
      bcm2835_spi_chipSelect(BCM2835_SPI_CS0);// Enable 0
  
      //voltage 1-4  
      char read_data = getByte('a');
      printf("byte is %02d\n", read_data);
  
      read_data = getByte('b');
      printf("byte is %02d\n", read_data);
  
      read_data = getByte('c');
      printf("byte is %02d\n", read_data);
  
      read_data = getByte('d');
      printf("byte is %02d\n", read_data);    
  
     /** voltage = volts.f;   
      printf("%.6f", voltage);
      printf("\n");
      **/
      delay(1000);   
  
      bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, HIGH);
      bcm2835_spi_chipSelect(BCM2835_SPI_CS0);// Disable 0
      bcm2835_spi_end();
      bcm2835_close();
  
      return 0;
  }
  </code></pre>
  
  <p>I'm using a fixed value to debug the code. Sometimes the output from SPI on the Pi is accurate, but otherwise it changes and outputs partially accurate and/or random bytes.</p>
  
  <p>The issue I have been unable to work out is stability on the side of the Pi, so I am looking for help evaluating whether my code is causing inaccuracies or if it's my hardware. </p>