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

SPI Slave interrupt by the Bluetooth

Hi. I am using nrf52840 with Softdevice 16.0.0 + BLE_uart_peripheral.

The SPI master transmits 2 SPI packets every 10 ms. At the the SPIS event handler, I call ble_nus_data_send() to send the SPI packet out.

However, I found the first couple bytes of the second packet are quite often be zero or lost. But as far as I disconnected the bluetooth to the central, the packets are fine.

I put a GPIO lines before and after the ble_nus_data_send() to tell the master hold the spi transmission but the problem still there.

However, I found if I added 1 ms between the spi cs line low and start the first byte, and also 1 ms after cs line goes high, the chances to get a corrupted spi packet is significantly reduced.

I think it might be the issue similar to this post:

https://devzone.nordicsemi.com/f/nordic-q-a/4034/spi-slave-with-heavy-interrupt-in-btle#post-id-17712

I preferred the GPIO solution mentioned in the post rather than the time delay. 

Could you help to the GPIO in the right position?

  • Nested interrupts are often the issue; try moving ble_nus_data_send() out of the SPIS event handler and into foreground code such as main(). Set a bool flag in the SPIS event handler and when seen as set in the foreground then invoke ble_nus_data_send()

  • I thought ble_nus_data_send() just moves the packet into the bluetooth stack and softdevice handles the actual bluetooth communication at the background. So the conflict is the interrupts from softdevice and spi. 

  • Perhaps I was too vague and quick to answer; this is a typical invocation of ble_nus_data_send():

        do
        {
           uint16_t length = (uint16_t)index;
           err_code = ble_nus_data_send(&m_nus, data_array, &length, m_conn_handle);
           // Also now check BLE_ERROR_GATTS_SYS_ATTR_MISSING or correctly set up due to timer race hazard
           if ((err_code != NRF_ERROR_INVALID_STATE)
            && (err_code != NRF_ERROR_RESOURCES)
            && (err_code != NRF_ERROR_NOT_FOUND)
            && (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING))
           {
              APP_ERROR_CHECK(err_code);
           }
        } while (err_code == NRF_ERROR_RESOURCES);

    This effectively blocks within an interrupt, which is to be discouraged. Blocking in the foreground is fine. The master may be sending the next SPI packet while the previous SPI interrupt is still active;  simple to test, maybe it'll help. Buffering (copying) the received data might also help, hard to say without sight of the SPI handler

  • I understand. But I scoped the gpio line which toggling at the entrance and exit of spi handler. I cant trigger my scope without single stepping, which suggests the time is very very short. Much less than 1 ms.

  • I cant trigger my scope without single stepping

    Try increasing the 'scope io pin drive to H0H1 in case the probes are very capacitive; it would have to be a very slow 'scope not to catch that toggle (must set Trig to Normal). Adding a second pin to the 'scope (also H0H1) which is driven on the packet corrupted condition might provide some useful information.

Related