SPI-Transaktion zwischen FPGA und Mikrocontroller

Ich versuche, ein Kommunikationsprotokoll zwischen einem FPGA und einem Mikrocontroller über ein SPI zu schreiben, wobei der µC hier der Master ist.

  • FPGA: Lattice iCE40 Ultra Breakout Board Rev.A (iCE5LP4K)
  • µC: Nordic nRF52 (PCA10040)

Hier ist der Code, den ich für den FPGA-Teil verwende . Die Simulation funktioniert gut innerhalb von Active HDL, wobei der Prozess das Master-Verhalten simuliert. So soll die Transaktion aussehen (wie im obigen Link erklärt):

  1. Es sind Daten in der Registrierung tx_load_data verfügbar --> trdy ist hoch
  2. Sendebefehl „0000 0000“ des Masters, der den Slave anweist, die nachfolgenden MOSI-Daten in das Empfangsregister zu laden, während gleichzeitig das Senderegister an MISO ausgegeben wird (Master empfängt tx_load_data)
  3. trrdy wird niedrig, wenn das letzte Bit gesendet wird
  4. Ebenso geht rrdy hoch, um zu beurteilen, dass neue vom Master gesendete Daten empfangen wurden.

Dies funktioniert in der Simulation, ich habe es geschafft, dasselbe wie in Abbildung 4 zu erhalten (siehe Link oben).

Beim Versuch, das gleiche Verhalten mit dem angeschlossenen µC zu reproduzieren, werden Daten geladen, trrdy geht hoch, ich sende einen Befehl wie "0x0A", es wird übertragen und auf dem MISO-Link ist etwas los, aber ich kann es nicht richtig lesen. Soweit ich die SPI-Kommunikation verstanden habe, soll ich die Antwort erhalten, während ich Daten über MOSI präsentiere. Ist das richtig?

Das Folgende sind Beispiele meines C-Codes. Ich bin mir ziemlich sicher, dass ich etwas falsch mache, aber mir fehlt die Erfahrung. Beim Debuggen werden die Register des Empfangspuffers oft mit "111111" gefüllt (Wörter mit 6 oder 8 Bit, das ist inkonsistent). Die sendByte-Funktion wird innerhalb eines Button-Handlers aufgerufen, und der rx-Puffer wird im spi-Event-Handler ausgegeben, der bei jeder Übertragung aufgerufen wird.

 /*
 * This function is supposed to ouput 00000000 01000001 to MOSI
 * Data received is buffered in m_rx_buf[20] array, declared in the header
 */
 void sendByteTest() {
    ret_code_t err_code;

    uint8_t m_tx[2];
    m_tx[0] = 0x0;
    m_tx[1] = 'A';

    m_length = sizeof(m_tx);        /**< Transfer length. */
    err_code = nrf_drv_spi_transfer(&spi, m_tx, m_length, m_rx_buf, m_length);
    if (err_code != NRF_SUCCESS)
        NRF_LOG_PRINTF(" Error during transfer.\r\n");

    memset(m_rx_buf, 0, m_length);
}

int main(void) {
    /** CLOCK, BUTTONS, GPIOTE initialization omitted **/

    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG(SPI_INSTANCE);
    spi_config.ss_pin = SPI_CS_PIN;
    spi_config.mode = NRF_DRV_SPI_MODE_2;   // ss_n is active low, set accordingly
    spi_config.frequency = NRF_DRV_SPI_FREQ_125K;
    spi_config.bit_order = NRF_SPI_BIT_ORDER_MSB_FIRST;
    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler));
    int i = 0;

    while(1) {
    nrf_gpio_pin_toggle(LED_1);
    nrf_delay_ms(200);
    }
}
Es ist unklar, ob Sie erkennen, dass Ihr SPI-Slave nicht im Voraus weiß, was der Master ihm senden wird - daher kann er seine Antwort erst anpassen, nachdem er etwas empfangen hat. Es kann nicht in der Zeit zurückgehen, um zu ändern, was es bereits gesendet hat. Der Master sendet also einen Befehl an den Slave (während der Slave gleichzeitig entweder "nichts" oder einige Standarddaten zurückgibt) und dann sendet der Master einige Dummy-Daten an den Slave, um die Antwort des Slaves auf den vorherigen Befehl lesen zu können .
Ok, danke, dass du das klarer gemacht hast. Also habe ich versucht, das zu tun, was Sie sagen, was bedeutet, dass meine erste Nachricht der Befehl ist: 0x0, mein Trrdy-Bit geht im Oszilloskop hoch, sodass Daten zur Übertragung bereit sind. (Ich habe diese Schritte an Schaltflächen gebunden, um das Debuggen zu erleichtern.) Dann sende ich uint8_t data[] = "A\0"; oder so etwas, und ich fülle meinen Empfangspuffer immer noch nicht ...
Ihr Master hat das Kommando über die SPI-Uhr, und Bits werden nur zusammen mit der SPI-Uhr in/aus SPI-Ports verschoben. Sie müssen also ein Byte senden, um ein Byte zu empfangen. Wenn Sie Ihren Empfangspuffer füllen möchten (20 Bytes?), muss Ihr Master so viele Bytes an den Slave senden.
Alles klar, das hat mir sehr geholfen, vielen Dank! Die Größe war tatsächlich falsch. Ich habe jetzt eine Antwort in meinem Puffer (noch nicht an der richtigen Stelle? Ich werde das nachschlagen). Versichern Sie mir, dass der Befehl 0b00000000 gesendet wird? Daten[] = {0}; macht die Übertragung hängen (ich benutze es vorerst im Blockiermodus)
data[] = "0A"funktioniert irgendwie, um das Ganze in einer Anfrage zu erledigen, aber ich bekomme die Antwort in rx_buf[1], während rx_buf[0]='\0'ich es deshalb vorher nicht sehen konnte. Aber am wichtigsten ist, dass es das trdy-Bit nicht löscht, was bedeutet, dass der Slave das Ende der Übertragung nicht bestätigt :(
@Fluffy data[] = {0} ist keine korrekte Syntax. Sie fordern es auf, ein Array unbekannter Länge auf 0 zu setzen. Sie könnten beispielsweise data[256] = {0} ausführen, um bei der Initialisierung alles auf 0 zu setzen. Oder Sie können memset(data, 0, sizeof(data)) verwenden;

Antworten (1)

Was ich nicht im Sinn hatte, ist, dass SPI-Kommunikation vorschlägt, dass Sie so viele Daten senden sollten, wie Sie empfangen möchten, nicht mehr und nicht weniger. Deshalb war mein Puffer laut. Durch Setzen m_lengthauf 1 : err_code = nrf_drv_spi_transfer(&spi, m_tx, m_length, m_rx_buf, m_length);Ich sende erfolgreich ein Byte, während ich genau ein Byte in meinem Empfangspuffer empfangem_rx_buf

Für die erste Übertragung (Befehl) erhalte ich Dummy-Daten, die ich nicht verarbeite, für die eigentliche Übertragung puffere ich sie und verarbeite sie.