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

SPI manager queue limitations

Hi all,

Having a bit of an issue with the SPI manager scheduler. When sending small packets (<4 bytes), I seem to be able to queue as many requests as I want.

However, sending a larger packet - even without any other requests in the queue (in this case 15 bytes), the transfer completes successfully but hardfaults the nRF52840 before calling the .end_callback from the transaction. This behaviour occurs even when .end_callback is set to NULL.

Update: So keeping the code as-is with the same 15 byte arrays. Doing two transfers: one with the length at 8-9 bytes / 15 possible: no hard fault, 10 bytes: finish callback isn't run (hits breakpoint but the pins it manipulates don't change state) but no error, 11 bytes+ HardFault

image description

The code I am using is this:

void send_data_async(uint8_t * data, size_t len, uint8_t * handler) {

// Packet definition
nrf_spi_mngr_transfer_t packet = 
{
   .p_tx_data = (uint8_t const *) data,
   .tx_length = (uint8_t)        len, 
	.p_rx_data = (uint8_t *)      NULL,
   .rx_length = (uint8_t)        0, 
   };
	
	
// Transaction	
nrf_spi_mngr_transaction_t command_trans = {
    .begin_callback      = start_data_callback,
        .end_callback        = finish_data_callback,
        .p_user_data         = NULL,
        .p_transfers         = &packet,
        .number_of_transfers = 1,
        .p_required_spi_cfg  = NULL
};

// Queue
APP_ERROR_CHECK(nrf_spi_mngr_schedule(&m_nrf_spi_mngr, &command_trans));
}

From the call:

 NRF_SPI_MNGR_DEF(m_nrf_spi_mngr, 16, 0);

 static ret_code_t init_spi0_master(void)
 {
 // SPI0 (with transaction manager) initialization.
 nrf_drv_spi_config_t const m_master0_config =
 {
    .sck_pin        = SPI_CLK,
    .mosi_pin       = SPI_DATA,
    .miso_pin       = NRF_DRV_SPI_PIN_NOT_USED,
    .ss_pin         = NRF_DRV_SPI_PIN_NOT_USED,
    .irq_priority   = APP_IRQ_PRIORITY_LOWEST,
    .orc            = 0xFF,
    .frequency      = NRF_DRV_SPI_FREQ_8M,
    .mode           = NRF_DRV_SPI_MODE_0,
    .bit_order      = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST
 };
 return nrf_spi_mngr_init(&m_nrf_spi_mngr, &m_master0_config);
 }

 uint8_t w_lut_29_22[15] = {0x84,0x01,0x02, 0x44,0x84,0x02, 0x44,0x84,0x02, 0x44,0x01,0x02, 0x00,0x00,0x00};
 send_data_async(w_lut_29_22, 15, NULL);

Interestingly, if I change the command to nrf_spi_mngr_perform instead, using the same nrf_spi_mngr_transfer_t object, it works perfectly.

This leads me to think that there may be some kind of maximum buffer size for individual requests being passed into the scheduler queue which I haven't configured and the defaults are too low. Alternatively, it may be something to do with it holding the system for too long and annoying the Softdevice?

If there aren't any special parameters which I'm missing, if there are any good guides for diagnosing a hard fault. I've looked at several from these forums (eg: using the HardFault_Handler function, taking the SP register, getting the memory address it points to, adding +18 etc. but the end address doesn't point to any address in my code. It always seems to be from either the SoftDevice or bootloader (hence my suspicion I may be annoying them))

Related