2016-08-31 3 views
0

Ich arbeite an einem Projekt, das Daten von einem Arduino Pro Mini sammelt und es mit SPI zu einem Raspberry Pi für die Speicherung sendet.Unzuverlässige SPI-Byte-Array-Übertragung von Arduino zu Raspberry Pi

Der Pro Mini liest den analogen Eingang und berechnet die Spannung (sobald ich fertig bin) und übergibt Werte an den Pi, wenn er mit einem ISR dazu aufgefordert wird.

Ich verwende C/C++ für beide Plattformen, um es einheitlich zu halten. Der Slave-Code wird mithilfe der Arduino-IDE zusammengeschnitten und der Master-Code basiert auf einem BCM2835-SPI-Bibliotheksbeispiel für das Pi.

Arduino-Code soll einen float Wert berechnen und den Float-Wert in ein Array von 4 Bytes/Zeichen vorverarbeiten (Ich bin für binäre Dreharbeiten, weil ich denke, es ist der beste Weg zu gehen). Sobald vom Pi aufgefordert, wird jedes Byte gesendet und in einem Float neu kompiliert.

Hier ist, was ich habe jetzt:

Slave

/************************************************************* 
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();*/ 
} 

Meister

#include <bcm2835.h> 
#include <stdio.h> 


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; 
} 

ich einen festen Wert mit dem Code zu debuggen. Manchmal ist die Ausgabe von SPI auf dem Pi genau, aber ansonsten ändert sie sich und gibt teilweise genaue und/oder zufällige Bytes aus.

Das Problem, das ich nicht ausarbeiten konnte, ist Stabilität auf der Seite des Pi, also suche ich nach Hilfe, ob mein Code Ungenauigkeiten verursacht oder ob es meine Hardware ist.

Antwort

0

Bei einer Schätzung würde ich sagen, dass dies ein Timing-Problem zwischen dem Sender und Empfänger ist. Versuchen Sie, die Bits der Daten zu betrachten, die Sie empfangen, und sehen Sie, ob sie vorwärts oder rückwärts verschoben sind. Dies wird möglicherweise anzeigen, dass der pi zu lange auf den Empfang wartet oder nicht lange genug auf alle Daten wartet. Ich denke, die Probleme sind wahrscheinlich um die Verzögerungen:

delay(500); //for errors 

auf dem Arduino und

delay(1000); 

am Empfänger. Warum benutzt du diese? 500ms ist eine lange Zeit, um den Pi auf eine Antwort auf die SPI-Daten warten zu lassen.

Nur eine Anmerkung, es gibt jetzt auch einen SPI-Kernel-Treiber (spidev) für die Pi - das ist ein viel mehr Industriestandard-Ansatz und ist möglicherweise eine robustere Methode.

Es ist ein gutes Beispiel dafür auf der Raspberry Pi Github site: https://github.com/raspberrypi/linux/blob/rpi-4.4.y/Documentation/spi/spidev_test.c

+0

Dank für Ihre Antwort js441. Ich wechselte zu python mit spiDev, weil es viel einfacher ist. Lassen Sie mich Sie fragen, glauben Sie, dass Python über C in Bezug auf den Industriestandard gleichermaßen akzeptabel ist? – giri

+0

@giri Das ist eine schwierige Frage zu beantworten. Beide werden in der Industrie verwendet, es geht eher darum, was für Sie funktioniert. Wenn Sie eine gültige Arbeitslösung in einer Sprache einfacher als die andere machen können, dann ist das die Sprache für Sie. – js441