Transacción SPI entre FPGA y Microcontrolador

Estoy tratando de escribir un protocolo de comunicación entre un FPGA y un Microcontrolador a través de un SPI, siendo el µC el Maestro aquí.

  • FPGA: Lattice iCE40 Ultra Breakout Board Rev.A (iCE5LP4K)
  • µC: NRF52 nórdico (PCA10040)

Aquí está el código que estoy usando para la parte de FPGA , la simulación funciona muy bien dentro de Active HDL con un proceso que simula el comportamiento del Maestro. Así es como se supone que debe verse la transacción (como se explica en el enlace anterior):

  1. Hay datos disponibles en el registro tx_load_data --> trdy es alto
  2. El maestro envía el comando "0000 0000" que le indica al esclavo que cargue los datos MOSI posteriores en el registro de recepción, mientras envía simultáneamente el registro de transmisión a MISO (el maestro recibe tx_load_data)
  3. trrdy baja cuando se envía el último bit
  4. Asimismo, rrdy se eleva para evaluar que se han recibido nuevos datos enviados por el maestro.

Esto funciona en simulación, logré obtener lo mismo que la Figura 4 (ver enlace arriba).

Al tratar de reproducir el mismo comportamiento con el µC adjunto, los datos se cargan, trrdy aumenta, envío un comando como "0x0A", se transmite y algo sucede en el enlace MISO, pero no puedo leerlo correctamente. Por lo que entendí con las comunicaciones SPI, se supone que debo recibir la respuesta mientras presento datos a través de MOSI. ¿Está bien?

Los siguientes son ejemplos de mi código C, estoy bastante seguro de que estoy haciendo algo mal, pero me falta experiencia. Al depurar, los registros del búfer de recepción a menudo se llenan con "111111" (palabras de 6 u 8 bits, es inconsistente). La función sendByte se llama dentro de un controlador de botón, y el búfer rx se imprime en el controlador de eventos spi, llamado en cada transferencia.

 /*
 * 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);
    }
}
No está claro si se da cuenta de que su esclavo SPI no sabe de antemano qué le enviará el maestro, por lo que solo puede adaptar su respuesta después de haber recibido algo. No puede retroceder en el tiempo para cambiar lo que ya ha enviado. Entonces, el maestro envía un comando al esclavo (mientras que simultáneamente el esclavo devuelve "nada" o algunos datos predeterminados) y luego el maestro envía algunos datos ficticios al esclavo para poder leer la respuesta del esclavo al comando anterior. .
Ok, gracias por aclarar esto. Así que he estado tratando de hacer lo que dices, lo que significa que mi primer mensaje es el comando: 0x0, mi bit trrdy se eleva en el alcance, por lo que los datos están listos para ser transmitidos. (Asocié esos pasos a los botones para facilitar la depuración) Luego envío uint8_t data[] = "A\0"; o algo así, y todavía no lleno mi búfer de recepción...
Su maestro está al mando del reloj SPI, y los bits solo se desplazan dentro/fuera de los puertos SPI junto con el reloj SPI. Entonces, debe enviar un byte para recibir un byte. Si desea llenar su búfer de recepción (¿20 bytes?), entonces su maestro debe enviar esa cantidad de bytes al esclavo.
Muy bien, eso me ayudó mucho, ¡muchas gracias! El tamaño estaba mal de hecho. Ahora tengo una respuesta en mi búfer (¿todavía no está en el lugar correcto? Buscaré esto) Creo que estoy muy cerca de resolver esto, ¿tiene alguna idea de cómo debo escribir el fragmento de código que asegurarme de que se está enviando el comando 0b00000000? datos[] = {0}; hace que la transferencia se cuelgue (lo estoy usando en modo de bloqueo por ahora)
data[] = "0A"funciona para hacer todo en una sola solicitud, pero recibo la respuesta en rx_buf[1], aunque rx_buf[0]='\0'es por eso que no pude verlo antes. Pero lo más importante, no borra el bit trdy, lo que significa que el Esclavo no reconoce el final de la transferencia :(
@Fluffy data[] = {0} no es la sintaxis correcta. Le está pidiendo que establezca una matriz de longitud desconocida en 0. Podría hacer data[256] = {0} para establecerlo todo en 0 en la inicialización, por ejemplo. O puede usar memset (datos, 0, tamaño de (datos));

Respuestas (1)

Lo que no tenía en mente es que las comunicaciones de SPI sugieren que debe enviar tantos datos como desee recibir, ni más ni menos. Así que mi búfer era ruidoso por eso. Al configurarlo m_lengthen 1: err_code = nrf_drv_spi_transfer(&spi, m_tx, m_length, m_rx_buf, m_length);estoy transmitiendo con éxito un byte, mientras recibo exactamente un byte en mi búfer de recepciónm_rx_buf

Para la primera transferencia (comando) recibo datos ficticios que no proceso, para la transferencia real los estoy almacenando en búfer y procesándolos.