Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

SPI hangs in nrf_spi_event_check() during transaction after I2C communication has been performed.

Our system has SPI and I2C. Each of these communications works in isolation, as implemented in our program, for multiple transactions. When we try to include both we noted that any SPI transactions that occurs after the 1st I2C transaction will hang in the nrf_spi_event_check() function called from spi_xfer() in nrfx_spi.c.

So in isolation our I2C transactions work fine, and our SPI transactions work fine, but as soon as we try to perform an I2C transaction followed by a SPI transaction the program hangs.

Through debugging we cannot see any notable change in behavior of the SPI transaction before or after the I2C transaction other than it hanging. We have no interrupts in our system and we are only sending data over SPI (we pass a dummy rx buffer to the transfer function). I pasted some code snippets below to show our implementation of SPI and I2C. We are seeking any advice in how to get our program to exit the nrf_spi_event_check() loop when it is stuck.

SPI

Init:
...
    instance_(NRFX_SPI_INSTANCE(0)),
    handle_(
        {
            .sck_pin = 14,   
            .mosi_pin = 13,
            .miso_pin = 15,
            .ss_pin = NRFX_SPI_PIN_NOT_USED,    
            .irq_priority = 7,        
            .orc = 0xFF,     
            .frequency = NRF_SPI_FREQ_4M,
            .mode = NRF_SPI_MODE_0,
            .bit_order = NRF_SPI_BIT_ORDER_MSB_FIRST
        }
    ),
...

Init code, NOTE: no handler function, we are polling not using an interrupt:
    nrfx_spi_init(&instance_, &handle_, nullptr, NULL);

SPI transfer function.  Only interested in the write:
...
    nrfx_spi_xfer_desc_t xfer_desc = NRFX_SPI_XFER_TRX(&packet, static_cast<size_t>(i), &dummy_rx_byte, 1);
    nrfx_spi_xfer(&instance_, &xfer_desc, 0);
...

Where it gets stuck after an I2C Write:
...
    else
    {
        do {
            while (!nrf_spi_event_check(p_spi, NRF_SPI_EVENT_READY)) {} //  <-- gets stuck here
            nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
            NRFX_LOG_DEBUG("SPI: Event: NRF_SPI_EVENT_READY.");
        } while (transfer_byte(p_spi, p_cb));
        if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED)
        {
            nrf_gpio_pin_set(p_cb->ss_pin);
        }
    }
...    
nrfx_spi.c, line 332

Relevant I2C code:
Init:
...
    instance_(NRFX_TWI_INSTANCE(0)),
    handle_(
        {
            .scl = scl_pin_number,
            .sda = sda_pin_number,
            .frequency = NRF_TWI_FREQ_100K,
            .interrupt_priority = NRFX_TWI_DEFAULT_CONFIG_IRQ_PRIORITY,                  
            .hold_bus_uninit = NRFX_TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT
        }
    )


    nrfx_twi_init(&instance_, &handle_, nullptr, NULL);
    nrfx_twi_enable(&instance_);

Write:
...
    nrfx_twi_xfer_desc_t tx_transfer = {
            .type = NRFX_TWI_XFER_TX,
            .address = device_address,
            .primary_length = size,
            .secondary_length = 0,  
            .p_primary_buf  = buffer,
            .p_secondary_buf = NULL
        };
    auto error = nrfx_twi_xfer(&instance_, &tx_transfer, 0);
...

Parents
  • Hello,

    You have same instance for SPI and TWI. 

    instance_(NRFX_SPI_INSTANCE(0))

     instance_(NRFX_TWI_INSTANCE(0))

    ''SPI shares registers and other resources with other peripherals that have the same ID as the SPI. Therefore, the user must disable all peripherals that have the same ID as the SPI before the SPI can be configured and used''

    So, you need to use separate instance for SPI and TWI or uninit one peripheral before initing the next and use PRS (peripheral resource sharing module)

Reply
  • Hello,

    You have same instance for SPI and TWI. 

    instance_(NRFX_SPI_INSTANCE(0))

     instance_(NRFX_TWI_INSTANCE(0))

    ''SPI shares registers and other resources with other peripherals that have the same ID as the SPI. Therefore, the user must disable all peripherals that have the same ID as the SPI before the SPI can be configured and used''

    So, you need to use separate instance for SPI and TWI or uninit one peripheral before initing the next and use PRS (peripheral resource sharing module)

Children
No Data
Related