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

SPI from BLE event

Hi, I am using SDK14.1 with nrf52832 and want to write to eeprom memory over SPI from BLE characteristic call.

My spi module works and everything was working fine until i tried to write something to eeprom over BLE.

This is my SPI function

_xfer_done = false;
APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, extendedTxBuffer, totalLength, NULL, 0));
while (!_xfer_done);

When this function is called from BLE _xfer_done state never changes. So i guess i never get a handler call.

What should i do in this situation?

  • I have put the #define SPI_DEFAULT_CONFIG_IRQ_PRIORITY 3 and now it works. It this safe?

  • Good question. I personally do all as scheduled actions through scheduler later outside event call-backs (because these are typically done inside some interrupt handler and time to execute APP FW code is limited).

  • It could it be caused by interrupt nesting, as @endnode suggests, or some interrupt priority issue.

    You start an SPI transfer from within an interrupt context (the BLE event) and then wait for a transfer complete interrupt with while (!_xfer_done). However, what probably happens is that since the SPI interrupt has lower priority than the BLE event, the SPI interrupt will not be executed before your BLE event code is completed because it is queued behind the BLE event. Hence the flag _xfer_done is never set, and you effectively end up waiting forever in the while (!_xfer_done) loop.

    Solutions are:

    1. Raise the SPI priority to a level above the BLE event level (level 4), as you have already done by setting the level to 3. Then the SPI interrupt will not be queued behind the BLE event, but executed right away. Then the _xfer_done flag will be set letting your code move on from the while loop. This is relatively safe, but it is not good practice to have a while() loop inside an interrupt, so I would rather recommend one of the solutions below.
    2. Set a flag in the BLE event handler and use that flag to trigger an SPI transfer from the main context.
    3. Or use a scheduler and schedule an SPI transfer in the BLE event handler.
  • If i understand corectly solution nr. 2 would include a bool and a buffer[20]. When the write to the characteristic is finished i would check in main context if my bool is true and then write to the spi. I don't understand the implementation of the 3. solution.

  • Q2. Something like this:

    volatile bool start_spi_tx_flag = false; // Make sure to declare flag as 'volatile'
    
    // In BLE event handler
    void some_ble_event_handler(...)
    {
    	// [....]
    	start_spi_tx_flag = true;
    }
    
    // In main 
    int main(void)
    {
    	// [....]
    	
    	while(1) // Main while forever loop
    	{
    		// [....]	
    		if(start_spi_tx_flag)
    		{
    			// Do SPI transfer and set start_spi_tx_flag = false when you are ready
    		}		
    	}
    }
    

    Q3. Please have a look at the scheduler library in the SDK.

Related