nrf5340 SPI/nrf-spim: 11 us delay between each buffer in a spi_buf_set

There seems to be a weird delay of around 11 us between each buffer in a spi_buf_set as shown in the red regions in the image below:

The test involves a transfer of 100 buffers of 128 bytes each using spi_transceive_signal on a nrf5340-DK using spi4 @8Mhz.

Is there a way to avoid this delay ? 

SPI delay between buffers

#include <zephyr/kernel.h>
#include <zephyr/drivers/spi.h>
#include <nrfx_clock.h>

struct spi_dt_spec master_spispec = SPI_DT_SPEC_GET(DT_NODELABEL(spidev), SPI_WORD_SET(8) | SPI_TRANSFER_MSB, 0);

static struct k_poll_signal spi_done_sig = K_POLL_SIGNAL_INITIALIZER(spi_done_sig);

static uint8_t tx_buffer[100 * 128]{};
static uint8_t rx_buffer[100 * 128]{};

int main(void)
{
    int err = nrfx_clock_divider_set(NRF_CLOCK_DOMAIN_HFCLK, NRF_CLOCK_HFCLK_DIV_1);
    if (err != NRFX_SUCCESS)
    {
        printk("Failed to set 128 MHz: %d\n", err);
    }

    printk("CPU clock: %u MHz\n", SystemCoreClock / MHZ(1));

    err = spi_is_ready_dt(&master_spispec);
    if (!err)
    {
        printk("Error: SPI device is not ready, err: %d\n", err);
    }

    for (int i = 0; i < 100 * 128; ++i)
    {
        tx_buffer[i] = i % 255;
        rx_buffer[i] = 0;
    }

    struct spi_buf tx_spi_buf[100];
    struct spi_buf rx_spi_buf[100];

    for (int i = 0; i < 100; ++i)
    {
        tx_spi_buf[i].buf = &tx_buffer[i * 128];
        tx_spi_buf[i].len = 128;
        rx_spi_buf[i].buf = &rx_buffer[i * 128];
        rx_spi_buf[i].len = 128;
    }

    struct spi_buf_set tx_spi_buf_set = {.buffers = tx_spi_buf, .count = 100};
    struct spi_buf_set rx_spi_buf_set = {.buffers = rx_spi_buf, .count = 100};

    k_poll_signal_reset(&spi_done_sig);

    err = spi_transceive_signal(master_spispec.bus, &master_spispec.config, &tx_spi_buf_set, &rx_spi_buf_set, &spi_done_sig);
    if (err < 0)
    {
        printk("spi_transceive_dt() failed, err: %d\n", err);
    }

    unsigned int spi_signaled;
    int spi_result = 0;
    do
    {
        k_poll_signal_check(&spi_done_sig, &spi_signaled, &spi_result);
    } while (spi_signaled == 0);

    printk("SPI Transfer finished\n");

    printk("SPI result: %i  RX: 0x%.2x, 0x%.2x\n", spi_result, rx_buffer[0], rx_buffer[1]);

    return 0;
}

Parents
  • Yes, but you have to talk to the hardware directly (or write your own driver). The idea is that you can re-feed the EasyDMA registers in the "started" event with the data for the new/next buffers.

    The original drivers use the "end" event to feed the SPIM peripherial - that introduces an interrupt delay.

    In your example I'd try using bigger buffers though. The SPIM peripherial in the NRF5340 allows up to 64KB (65535 byte) in a single transfer.

Reply
  • Yes, but you have to talk to the hardware directly (or write your own driver). The idea is that you can re-feed the EasyDMA registers in the "started" event with the data for the new/next buffers.

    The original drivers use the "end" event to feed the SPIM peripherial - that introduces an interrupt delay.

    In your example I'd try using bigger buffers though. The SPIM peripherial in the NRF5340 allows up to 64KB (65535 byte) in a single transfer.

Children
Related