Las lecturas de SPI están cambiadas, son inconsistentes (nRF Master, FPGA Slave)

Intentaré simplificar mi proyecto tanto como sea posible para que esto sea comprensible. Estoy conectando una placa nRF52 PCA10040 a un FPGA iCE5LP (Lattice).

Tengo un problema con los bytes que ingresan a la MCU (línea MISO), este es el curso de acción:

  1. Maestro envía comando a través de SPI
  2. El esclavo ejecuta el comando y prepara los datos para la transferencia
  3. Después de esperar lo suficiente para que se procese el comando y se preparen los datos, el maestro envía bytes ficticios para recibir el registro tx de la FPGA.
  4. Los datos parecen cambiados y son inconsistentes.

Los datos se cargan correctamente, según la simulación. Lo que recibo en todas las demás transferencias es el byte que espero pero que se desplazó un bit. Vea las siguientes capturas de pantalla;

Esta es la simulación: SimulaciónEsta es la salida del analizador lógico: LALo que espero: (es un procedimiento de inicialización de eMMC)

  • 0xC0FF8080 o 0x40FF8080 según el resultado inicial

Lo que obtengo al azar:

0xE07FC040 que es 0xC0FF8080 >> 1 o 0x007F8040 que es 0x00FF0080 >> 1

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

¿Tienes una idea de lo que estoy haciendo mal? ¡Muchas gracias!

¿Estás perfectamente seguro de que los relojes están sincronizados?
¿A qué relojes te refieres? El reloj de la MCU y el reloj SPI, generado por la MCU, están perfectamente sincronizados. sí
¿Qué tal el SPI y el FPGA?
¿Qué velocidades estás usando de todos modos?
El reloj de la FPGA es de 12 MHz, SPI es de 4 MHz. eMMC para la inicialización se reduce a 400 kHz (pero eso es irrelevante) No son realmente sincrónicos ya que necesito un ciclo de reloj de FPGA para realizar la detección de bordes en el reloj spi
¿Ha intentado aumentar la velocidad del reloj de la FPGA (si es posible) o reducir la velocidad de la SPI? ¿Cuáles son los resultados? Si bien la diferencia debería ser lo suficientemente grande, no estoy del todo convencido.
No, la velocidad de reloj de la FPGA es de 12 MHz como máximo con el oscilador interno. Intenté reducir la velocidad a 2 y 3 MHz... no cambió nada. Lo tengo configurado en 1 y está funcionando, ¿por qué? Pensé que necesitaba como mínimo la mitad de la velocidad del reloj principal, por lo que por debajo de 6 MHz, ¿por qué funciona con 1 y no con 2 MHz?

Respuestas (2)

La diferencia entre su velocidad de adquisición y la velocidad de datos no es suficiente. Aumentar la velocidad del FPGA o disminuir la velocidad del SPI soluciona el problema de alineación.

Su reloj SPI y su reloj FPGA no están sincronizados. Esto significa que su reloj FPGA debe funcionar como mínimo dos veces más rápido que el reloj SPI. Sin embargo, dado que SPI es una señal externa, es posible que no esté del todo limpia. Es probable que haya fluctuaciones en su reloj y/o datos. Un factor de 2 como diferencia es simplemente cortarlo demasiado cerca.

Tiene un factor de 3. Cuando tenga dudas sobre la validez de sus señales, tenga en cuenta que esto está cerca del mínimo indispensable. Aumenta el factor. Como indicaste, el factor 12 funciona. Es probable que su umbral esté en 8 (12/8 = 1,5 MHz).

Además, lo más probable es que no necesites una velocidad tan alta. Es probable que la integridad de los datos sea mucho más importante. Constrúyalo de forma segura primero, preocúpese por la optimización de la velocidad después.

La trama de su analizador lógico no tiene la resolución necesaria. Pero el MISO y el MOSI parecen estar desfasados ​​por medio ciclo.

Normalmente hay 4 modos en los que operan los buses SPI . En uno, se espera que los datos cambien en el flanco descendente y se muestreen en el flanco ascendente del reloj. En otro ocurre lo contrario. Si el maestro y el esclavo no se configuraron de la misma manera, el resultado es impredecible. Sin embargo, un cambio de bit de 1 es un resultado razonable de tal desajuste.

Gracias por su respuesta, también exploré eso en realidad. Pero tanto el esclavo como el maestro están configurados para operar en modo 0,0. Creo que el problema 'fuera de fase' fue sintomático del error resaltado en la respuesta anterior. ya no esta pasando