1
\$\begingroup\$

I'm trying to write a communication protocol between an FPGA and a Microcontroller through an SPI, the µC being the Master here.

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

Here's the code I'm using for the FPGA part, simulation works nicely within Active HDL with process simulating the Master behavior. Here's how the transaction is supposed to look like (as explained in the link above):

  1. There is data available in tx_load_data registry --> trdy is high
  2. Master send command "0000 0000" instructing the slave to load the subsequent MOSI data into the receive register, while simultaneously outputting the transmit register to MISO (Master receives tx_load_data)
  3. trrdy goes low when the last bit is sent
  4. Likewise, rrdy goes high to assess that new data sent by the master has been received.

This works in simulation, I've managed to get the same as Figure 4 (see link above).

Trying to reproduce the same behavior with the µC attached, data is loaded, trrdy goes high, I send a command like "0x0A", it gets transmitted and there's something going on the MISO link, but I can't read it properly. From what I understood with SPI communications, I'm supposed to receive the response while I'm presenting data through MOSI. Is that right?

The following are samples of my C code, I'm pretty sure I'm doing something wrong but I lack experience. When debugging, the registers of the receive buffer are often filled with "111111" (words of 6 or 8 bits, it's inconsistent). The sendByte function is called within a button handler, and the rx buffer is printed out in the spi event handler, called at every transfer.

 /*
 * 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);
    }
}
\$\endgroup\$
6
  • \$\begingroup\$ Its unclear whether you realise that your SPI slave doesn't know in advance what the master is going to send it - so it can only tailor its response after it has received something. It can't go back in time to change what it has already sent. So, the master sends a command to the slave (while simultaneously the slave returns either "nothing" or some default data) and then the master sends some dummy data to the slave in order to be able to read the slave's response to the previous command. \$\endgroup\$
    – brhans
    Jun 14, 2016 at 14:53
  • \$\begingroup\$ Ok, thank you for making this clearer. So I've been trying to do as you state, meaning that my first message is the command : 0x0, my trrdy bit goes high on the scope, so data is ready to be transmitted. (I bound those steps to buttons to ease up debug) Then I send uint8_t data[] = "A\0"; or sth like that, and I still don't fill my receive buffer... \$\endgroup\$
    – Fluffy
    Jun 14, 2016 at 15:06
  • \$\begingroup\$ Your master is in command of the SPI clock, and bits are only shifted in/out of SPI ports along with the SPI clock. So you have to send a byte in order to receive a byte. If you want to fill your receive buffer (20 bytes?) then your master has to send that many bytes to the slave. \$\endgroup\$
    – brhans
    Jun 14, 2016 at 15:16
  • \$\begingroup\$ Alright, that helped me a lot, thank you very much! The size were wrong indeed. I have a response in my buffer now (not yet at the right place? I'll look this up) I think I'm very close to figure this out, do you have an idea on how I should write the bit of code that assure me 0b00000000 command is being sent? data[] = {0}; makes the transfer hang (I'm using it in blocking mode for now) \$\endgroup\$
    – Fluffy
    Jun 14, 2016 at 15:48
  • \$\begingroup\$ data[] = "0A" kind of works to do the whole thing in one request, but I get the response in rx_buf[1], while rx_buf[0]='\0' this is why I couldn't see it before. But most importantly, it doesn't clear out the trdy bit, meaning that the Slave doesn't acknowledge the end of the transfer :( \$\endgroup\$
    – Fluffy
    Jun 14, 2016 at 16:09

1 Answer 1

1
\$\begingroup\$

The thing I didn't have in mind, is that SPI communications suggests that you should send as much data as you want to receive, not more, not less. So my buffer was noisy because of that. By setting m_length to 1 : err_code = nrf_drv_spi_transfer(&spi, m_tx, m_length, m_rx_buf, m_length); I am successfully transmitting one byte, while receiving exactly one byte in my receive buffer m_rx_buf

For the first transfer (command) I'm receiving dummy data that I don't process, for the actual transfer I'm buffering it and processing it.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.