SPIM transmission corrupted when k_sleep() is called.

Hi,

I'm new to the nRF Connect SDK but I'm developing a project with the NRF54L15. Currently I'm testing the SPI peripherals and I'm having trouble with the SPIM peripheral glitching out. Here is a simple program that has the problem:

#include <nrfx_spim.h>
#include <zephyr/kernel.h>

#define SPIM_INST_IDX 21

static uint8_t m_tx_buffer[] = "Hello World!";
static uint8_t m_rx_buffer[sizeof(m_tx_buffer)];

static volatile bool spim_done = false;

static void spim_handler(nrfx_spim_evt_t const* p_event, void* p_context) {
    if (p_event->type == NRFX_SPIM_EVENT_DONE) {
        spim_done = true;
    }
}

int main(void) {
    nrfx_err_t status;

    IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_SPIM_INST_GET(SPIM_INST_IDX)),
                IRQ_PRIO_LOWEST, NRFX_SPIM_INST_HANDLER_GET(SPIM_INST_IDX), 0,
                0);

    nrfx_spim_t spim_inst = NRFX_SPIM_INSTANCE(SPIM_INST_IDX);

    nrfx_spim_config_t spim_config = NRFX_SPIM_DEFAULT_CONFIG(
        NRF_PIN_PORT_TO_PIN_NUMBER(6, 2), NRF_PIN_PORT_TO_PIN_NUMBER(8, 2),
        NRF_PIN_PORT_TO_PIN_NUMBER(9, 2), NRF_PIN_PORT_TO_PIN_NUMBER(10, 2));

    void* p_context = "Test context";
    status = nrfx_spim_init(&spim_inst, &spim_config, spim_handler, p_context);
    NRFX_ASSERT(status == NRFX_SUCCESS);

    while (1) {
        spim_done = false;
        nrfx_spim_xfer_desc_t spim_xfer_desc = NRFX_SPIM_XFER_TRX(
            m_tx_buffer, sizeof(m_tx_buffer), m_rx_buffer, sizeof(m_rx_buffer));

        status = nrfx_spim_xfer(&spim_inst, &spim_xfer_desc, 0);
        NRFX_ASSERT(status == NRFX_SUCCESS);
        
        while (!spim_done) {
            k_sleep(K_MSEC(1));
        }
        k_sleep(K_MSEC(1000));
    }

    return 0;
}

Here is an image of the output when it doesn't work. The first transmission after reset will be ok and the rest will be corrupted:

If I replace k_sleep(K_MSEC(1)); with k_yield(); it starts working. If I just have an empty while loop it also works. Here is an image of the signal when it works:

Completely removing the while loop and just calling the long sleep directly also makes it not work, so it seems that the problem is calling k_sleep() while the transfer is still happening. Is this something that is expected? If yes, where could I read up more about why this is the case, and learn some more about the inner workings?

Best regards,
Sašo Domadenik

Related