This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Understanding spi_buf_set SPI behavior

Hi,

I am controlling an external device using SPI(M), SYNC, with the nRF52840 DK.

I am using the exact same GPIO configuration using two different test apps using SDK16 and NCS. SDK16 works as expected, the NCS has strange behavior.

With NCS, I have everything about the CS working, defining a special overlay to control CS and the extra GPIO signals from the Arduino type shield that I am using, and it does everything with no errors.

Now, my question is the following: When you have buffer sets that are not the same length the TX and the RX, I followed the code on the spi_nrfx_spi.c driver and it would seem as if it is a loop sending each pair of TX, RX bufs, using transfer_next_chink(), until the last one up to the bigger count in the spi_buf_set would be exhausted, placing ORC chars where needed in each TX-RX bus pair if they have different length.

But what I observed is totally different. All tx bufs are set contagiously, the same as all rx, and it behaves like a concatenation of tx and rx.

So, which is it, doing transfers of each tx-rx pair in the set, using ORC to fill the gaps of the shortest ones, or a concatenation of all the tx, and the rx, and just doing one transfer?

Unfortunately the documentation is not clear about the internal behavior of uneven lengths on the sets.

I am placing some code to exemplify my question.

void read_registers( u16_t address, u8_t *buffer, u16_t size )
{
    u8_t cmd = READ_REGISTER;
    u8_t addr[2] = { ( address & 0xFF00 ) >> 8 , address & 0x00FF };
    u8_t nop = 0;
    u8_t filler[4]; 

    struct spi_buf tx_bufs[] = { { &cmd, 1 }, { addr, 2 }, { &nop, 1 } };
    struct spi_buf_set tx = { tx_bufs, 3 };

    struct spi_buf rx_bufs[] = { { filler, 4 }, { buffer, size } };
    struct spi_buf_set rx = { rx_bufs, 2 };

    int ret = spi_transceive(spi, &spi_cfg, &tx, &rx);
    CHECK_ERR_NO_RET_VAL(ret, "read_registers()");

    if(size == 1) {
        LOG_DBG("RD REG cmd:0x%02X, addr:0x%02X%02X, buffer:0x%02X, size:%i", 
                    cmd, addr[0], addr[1], buffer[0], size);
    } else {
#if CONFIG_LOG_DEFAULT_LEVEL == LOG_LEVEL_DBG
        char buf[40];
        sprintf(buf, "RD REG cmd = 0x%02X, addr:0x%02X%02X", cmd, addr[0], addr[1]);
        LOG_HEXDUMP_DBG(buffer, size, log_strdup(buf));
#endif
    }
}

Thanks!

  • You say that you are using the spi_nrfx_spi.c driver (no EasyDMA) and not the spi_nrfx_spim.c driver (with EasyDMA). You are mentioning the register ORC, but the SPI peripheral does not have it, only the SPIM peripheral and that may be the reason you're not seeing it in the transaction. I don't know in detail how the SPI peripheral/drivers work, and I'm not able to give you a more comprehensive answer at the moment but I hope this information will help you.

    If this answer is not sufficient, please tell me and I will investigate more.

    Best regards,

    Simon

Related