SPI-Messwerte sind verschoben, inkonsistent (nRF-Master, FPGA-Slave)

Ich werde versuchen, mein Projekt so weit wie möglich zu vereinfachen, um dies verständlich zu machen. Ich verdrahte ein nRF52 PCA10040-Board mit einem iCE5LP (Lattice) FPGA.

Ich habe ein Problem mit den Bytes, die in die MCU (MISO-Leitung) gelangen, hier ist die Vorgehensweise:

  1. Der Master sendet den Befehl über SPI
  2. Der Slave führt den Befehl aus und bereitet die Daten für die Übertragung vor
  3. Nachdem er lange genug auf die Verarbeitung des Befehls und die Aufbereitung der Daten gewartet hat, sendet der Master Dummy-Bytes, um das TX-Register vom FPGA zu empfangen.
  4. Die Daten sehen verschoben aus und sind inkonsistent.

Die Daten werden laut Simulation korrekt geladen. Was ich bei jeder zweiten Übertragung erhalte, ist das Byte, das ich erwarte, aber um ein Bit verschoben. Siehe die folgenden Screenshots;

Dies ist die Simulation: SimulationDies ist die Ausgabe des Logikanalysators: LAWas ich erwarte: (es ist eine eMMC-Initialisierungsprozedur)

  • 0xC0FF8080 oder 0x40FF8080 je nach Init-Ergebnis

Was ich zufällig bekomme:

0xE07FC040, was 0xC0FF8080 >> 1 ist, oder 0x007F8040, was 0x00FF0080 >> 1 ist

static uint8_t       m_rx_buf[4];        /**< RX buffer. */
static uint8_t       m_rx_buf_ext[6];    /**< RX buffer. */
static uint8_t       m_tx_buf[] = {0x00, 0xaa, 0xbb, 0xcc};           /**< TX buffer. */


/**
 * @brief SPI user event handler.
 * @param event
 */
void spi_event_handler(nrf_drv_spi_evt_t const * p_event) {
    spi_xfer_done = true;
    NRF_LOG_PRINTF("Received: %x %x %x %x\n", m_rx_buf[0], m_rx_buf[1], m_rx_buf[2], m_rx_buf[3]);
}



/**
 * Function to send a command to a specific module.
 * @param module  : Module to communicate with
 * @param command : Command to send
 */
ret_code_t sendCommand(uint8_t module, uint8_t command, uint8_t mmc_command, uint32_t mmc_arg) {
    ret_code_t err_code;
    uint8_t firstByte = module + command;
    if (command > 31 || module > 7) {
        return APP_ERROR_INVALID_CMD;
    }

    uint8_t msg_a[] = {firstByte, mmc_command, mmc_arg >> 24, mmc_arg >> 16,  mmc_arg >> 8, mmc_arg & 0xFF};
    uint8_t msg_length = sizeof(msg_a);

    memset(m_rx_buf_ext, 0, msg_length);

    spi_xfer_done = false;

    err_code = nrf_drv_spi_transfer(&spi, msg_a, msg_length, m_rx_buf_ext, msg_length);
    while (!spi_xfer_done) {
        __WFE();
    }
    if (err_code != NRF_SUCCESS) {
        NRF_LOG_PRINTF("Error during transfer : %d\n", err_code);
    }
    return err_code;
}


ret_code_t initMMC() {
    ret_code_t err_code;
    bool mmc_initialized = false;

    nrf_delay_us(200);  /**< Wait for more than 74 clock cycles before issuing a command. */
    err_code = sendCommand(MODULE_CMD_SEND, CMD_SEND_CMD_TO_MMC, CMD0, 0);

    while (!mmc_initialized) {
        nrf_delay_us(300);
        err_code = sendCommand(MODULE_CMD_SEND, CMD_SEND_CMD_TO_MMC, CMD1, ARG_BUS_INIT);

        nrf_delay_us(600);

        memset(m_rx_buf, 0, 4);
        spi_xfer_done = false;

        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, 4, m_rx_buf, 4));

        while (!spi_xfer_done)
        {
            __WFE();
        }

        if (m_rx_buf[0] == 0xC0 || m_rx_buf[0] == 0x80 || m_rx_buf[0] == 0xE0) {
            NRF_LOG_PRINTF("eMMC Initialized.\n");
            mmc_initialized = true;
        }
        nrf_delay_ms(1000);
    }
    return err_code;
}

void init_clock() {
    NRF_CLOCK->LFCLKSRC            = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
    NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_LFCLKSTART    = 1;
    while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0); // Wait for clock to start
}


int main(void) {
    APP_ERROR_CHECK(NRF_LOG_INIT());
    init_clock();
    LEDS_CONFIGURE(LEDS_MASK);
    LEDS_OFF(LEDS_MASK);
    APP_TIMER_INIT(APP_TIMER_PRESCALER,APP_TIMER_OP_QUEUE_SIZE,NULL);
    APP_ERROR_CHECK(nrf_drv_gpiote_init());
    buttons_init();
    NRF_LOG_PRINTF(NRF_LOG_COLOR_RED"\nSTARTING.\r\n"NRF_LOG_COLOR_DEFAULT);

    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG(SPI_INSTANCE);
    spi_config.ss_pin = SPI_CS_PIN;
    spi_config.frequency = NRF_SPI_FREQ_4M;
    spi_config.mode = NRF_DRV_SPI_MODE_0;
    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler));

    resetFPGA(RST_PIN);         //Pulls up fpga's reset pin for 5ms then down
    nrf_delay_ms(1000);

    APP_ERROR_CHECK(initMMC());
    while(1) {
        __WFE();
    }
}

Hast du eine Idee, was ich falsch mache? Vielen Dank!

Sind Sie absolut sicher, dass die Uhren synchronisiert sind?
Welche Uhren meinst du? Die Uhr der MCU und die von der MCU generierte SPI-Uhr sind perfekt synchron, ja
Wie sieht es mit dem SPI und dem FPGA aus?
Welche Geschwindigkeiten verwendest du überhaupt?
Der Takt des FPGA beträgt 12 MHz, SPI 4 MHz. eMMC für die Initialisierung wird auf 400 kHz heruntergetaktet (aber das ist irrelevant). Sie sind nicht wirklich synchron, da ich einen FPGA-Taktzyklus benötige, um eine Flankenerkennung auf der Spi-Uhr durchzuführen
Haben Sie versucht, die Taktrate des FPGA zu erhöhen (falls dies möglich ist) oder die Geschwindigkeit des SPI zu verlangsamen? Was sind die Ergebnisse? Obwohl der Unterschied groß genug sein sollte, bin ich nicht ganz überzeugt.
Nein, die Taktrate des FPGA beträgt mit dem internen Oszillator maximal 12 MHz. Ich habe versucht, es auf 2 und 3 MHz zu verlangsamen ... es hat nichts geändert. Ich habe es auf 1 gesetzt und es funktioniert, warum ist das so? Ich dachte, ich brauche mindestens die Hälfte der Geschwindigkeit des Haupttakts, also unter 6 MHz, warum funktioniert es mit 1 und nicht mit 2 MHz?

Antworten (2)

Der Unterschied zwischen Ihrer Erfassungsgeschwindigkeit und der Datengeschwindigkeit reicht nicht aus. Das Erhöhen der Geschwindigkeit des FPGA oder das Verringern der Geschwindigkeit des SPI behebt das Ausrichtungsproblem.

Ihre SPI-Uhr und FPGA-Uhr sind nicht synchronisiert. Das bedeutet, dass Ihr FPGA-Takt mindestens doppelt so schnell laufen muss wie der SPI-Takt. Da SPI jedoch ein externes Signal ist, ist es möglicherweise nicht ganz sauber. Es gibt wahrscheinlich Jitter auf Ihrer Uhr und/oder Ihren Daten. Ein Faktor von 2 als Unterschied ist einfach zu knapp geschnitten.

Sie haben einen Faktor von 3. Wenn Sie Zweifel an der Gültigkeit Ihrer Signale haben, denken Sie daran, dass dies fast das absolute Minimum ist. Erhöhen Sie den Faktor. Wie Sie angedeutet haben, funktioniert Faktor 12. Ihre Schwelle liegt wahrscheinlich bei 8 (12/8 = 1,5 MHz).

Außerdem benötigen Sie höchstwahrscheinlich keine so hohe Geschwindigkeit. Datenintegrität ist wahrscheinlich viel wichtiger. Bauen Sie es zuerst sicher, kümmern Sie sich später um die Geschwindigkeitsoptimierung.

Ihr Diagramm des Logikanalysators hat nicht die erforderliche Auflösung. Aber MISO und MOSI scheinen um einen halben Zyklus phasenverschoben zu sein.

Es gibt normalerweise 4 Modi, in denen SPI-Busse arbeiten . In einem Fall wird erwartet, dass sich die Daten an der fallenden Flanke ändern und an der steigenden Flanke des Takts abgetastet werden. Bei einem anderen ist das Gegenteil der Fall. Wenn Master und Slave nicht gleich eingestellt wurden, ist das Ergebnis unvorhersehbar. Eine Bitverschiebung von 1 ist jedoch ein vernünftiges Ergebnis einer solchen Fehlanpassung.

Vielen Dank für Ihre Antwort, das habe ich auch tatsächlich untersucht. Aber sowohl der Slave als auch der Master sind so konfiguriert, dass sie im 0,0-Modus arbeiten. Das Problem der Phasenverschiebung war meines Erachtens symptomatisch für den in der obigen Antwort hervorgehobenen Fehler. Es findet nicht mehr statt