Hi,
I can use the SPI master functionality within nrf_drv_spi.c/.h just fine (i.e. calls from main) until I connect to my nRF52840 and utilize NUS. If I try to issue a nrf_drv_spi_transfer() call from within my NUS data handler (i.e. when handing incoming data over NUS) to read 2 registers from a SPI connected slave (I am the master), I am not getting the expected SPI event handler with event NRF_DRV_SPI_EVENT_DONE when a SPI transfer completes. In the code below, I am calling bmi160_spiReadRegs() from within my NUS data handler. This function is blocking because m_xfer_done is never set to TRUE as a result of spi_event_handler() being called.
void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
void * p_context)
{
// The only type passed to this handler is "NRF_DRV_SPI_EVENT_DONE"
m_xfer_done = true;
}
void spi_init()
{
ret_code_t err_code;
if(m_initialized) { return; } // Nothing to do.
nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
spi_config.ss_pin = ACC_SPI_CSN; // Driver control.
spi_config.miso_pin = ACC_SPI_MISO;
spi_config.mosi_pin = ACC_SPI_MOSI;
spi_config.sck_pin = ACC_SPI_SCK;
spi_config.mode = NRF_DRV_SPI_MODE_0; // Prev BMI160 exp.
spi_config.frequency = NRF_DRV_SPI_FREQ_8M; // Max Nordic SPI Speed - chip max is 10M
spi_config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST; // From prev egs.
err_code = nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL);
APP_ERROR_CHECK(err_code);
m_initialized = true;
}
///////////////////////////////////////////////////////////////////////////
// BMI160.c slave functions for read/write via SPI. Fcn signature is set.
///////////////////////////////////////////////////////////////////////////
int8_t bmi160_spiReadRegs(uint8_t dev_addr, uint8_t reg_addr, uint8_t *p_data, short unsigned int data_len)
{
ret_code_t err_code;
uint8_t* p_newRxBuf;
// Watch for this to change to true in handler.
m_xfer_done = false;
// Cannot continue if not initialized.
if(!m_initialized) { return 1; }
// Add read bit to register.
reg_addr = reg_addr | SPI_READ_MASK;
// Create a rx buffer that has an extra byte for the response (first byte back is ignored as per egs).
p_newRxBuf = malloc(data_len + 1);
memset(p_newRxBuf, 0, data_len+1);
// Read directly into p_data. nrf_drv_spi_transfer() should hold down cs to ensable values from all regs.
// as specified by data_len.
err_code = nrf_drv_spi_transfer(&spi, ®_addr, 1, p_newRxBuf, data_len+1);
APP_ERROR_CHECK(err_code);
// Wait for a result.
while(!m_xfer_done) { nrf_delay_ms(1); }
// Copy Rx data into p_data
memcpy(p_data, p_newRxBuf+1, data_len);
free(p_newRxBuf);
return 0;
}
If I issue the same SPI read on main using nrf_drv_spi_transfer(), the SPI event handler is called with event NRF_DRV_SPI_EVENT_DONE as expected. But, if I issue the nrf_drv_spi_transfer() from my NUS data handler, my SPI event handler is never called (at all).
I see other references to similar issues on DevZone. For these issues, NUS or SPI priority changes are suggested. I have tried this, but to no avail.
Specifically, I have set NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY to 2 to match NUS, but to no avail. See below.
// <o> NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY - Interrupt priority // <0=> 0 (highest) // <1=> 1 // <2=> 2 // <3=> 3 // <4=> 4 // <5=> 5 // <6=> 6 default // <7=> 7 #ifndef NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY #define NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY 2 #endif
I have also tried changing the priority of NUS to match SPI. I set it to 6 as below.
// <o> BLE_NUS_BLE_OBSERVER_PRIO // <i> Priority with which BLE events are dispatched to the UART Service. // Default 2 #ifndef BLE_NUS_BLE_OBSERVER_PRIO #define BLE_NUS_BLE_OBSERVER_PRIO 6 #endif
Neither of these addressed the issue. If I call nrf_drv_spi_transfer() within my NUS data handler, the SPI event handler is never called with event NRF_DRV_SPI_EVENT_DONE.
This confuses me as the NUS UART example calls UART reads/writes within the NUS data handler and the UART priority is the same as SPI (both 6).
Perhaps this is not priority related?
Help, clues, etc are appreciated.
Thanks,
Mark J