This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Increasing bluetooth speed without blocking other peripherals

Hi,

I'm putting together some firmware that takes packets received over SPI and then streams them over BLE. I'm trying to run the BLE at close to 1Mb/s (which is still within spec from my understanding) but I'm getting some inconsistent packet dropping. After some debugging, I have come to some roadblocks.

1) Is there a way to confirm that I'm properly queueing BLE packets? I've instantiated the queued write module and enabled the length extension with the following code:

NRF_BLE_QWR_DEF(m_qwr);   

...
...

err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);

...
...

bool conn_evt_len_ext_enabled;
ble_opt_t  opt;

conn_evt_len_ext_enabled = true;

memset(&opt, 0x00, sizeof(opt));
opt.common_opt.conn_evt_ext.enable = conn_evt_len_ext_enabled ? 1 : 0;

err_code = sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &opt);
APP_ERROR_CHECK(err_code);


and when I want to send bluetooth packets I just use: 

ble_nus_data_send(&m_nus, ble_tx_buf, &ble_packet_length, m_conn_handle);


My understanding is that with my current setup, I can keep running 'ble_nus_data_send' and the microcontroller will just queue whatever I want to send to be sent later. Is that correct? Do I have to wait to receive NRF_SUCCESS?

2) I was reading this blog post: https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/throughput-and-long-range-demo and went through the demo code and it seems like I can increase BLE transfer speeds by boosting my tx power. Is it recommended to change the tx power and link budget or should I not touch those? During run-time I set my PHY to 2M - does that automatically alter my tx power and link budget?

I should note that I'm building my peripheral FW off of the ble_app_uart example and my central FW off a ble_app_uart_c example - but I've added USB functionality. I'm more than happy to provide any/all code if there are any questions.

Thank you so much!

Ryan

  • Hi Ryan

    1. Have you been able to track down where exactly the packets are dropped? Does it occur from the SPI to the transmitting device, or is the data lost over the air? I think you should wait for the ble_nus_data_send() to be completed before you call it again.

    2. It only helps to increase the TX power if you're having trouble with the connection in terms of range, higher TX power won't help much if the devices are right next to each other. The 2MBPS PHY does not alter the TX power. 

    Best regards,

    Simon

  • Hi Simon!

    1) Right now it looks like it's happening on the Bluetooth side. I probed the spi pins and the data looks good and is being transmitted at the right rate. As far as waiting for the "success" response I ran into a weird issue.

    I figured things would run fastest if I put everything in the interrupt handlers so I have a timer_interrupt trigger a SPI transaction and then a SPI_interrupt handler that triggers a bluetooth transaction. My original code (where I wait for NRF_SUCCESS) is below:

    void spim_event_handler(nrfx_spim_evt_t const * p_event,
                           void *                  p_context)
    {
        spi_xfer_done = true;
        // Bring CS high
        nrf_gpio_pin_set(NRFX_SPIM_SS_PIN);
        
        // send 3 packets at once to take advantage of the large payload size
        if (spi_trx_counter == 3)
        {
            //NRF_LOG_INFO("READ 3 SPI PACKETS, SEND to BLE");
            spi_trx_counter = 0;
            while(ble_nus_data_send(&m_nus, ble_tx_buf, &ble_packet_length, m_conn_handle) != NRF_SUCCESS);
        }
    }
     

    This became problematic because waiting with "while(ble_nus_data_send(&m_nus, ble_tx_buf, &ble_packet_length, m_conn_handle) != NRF_SUCCESS);" in the interrupt handler prevented the SPI from operating 'while' the bluetooth was running. I confirmed this by probing my SPI pins with an oscilloscope - I'd get 3 SPI packets (all spaced <1ms apart) and then there would be a 6-7ms gap (what I assume is the connection interval) while the code hit the bluetooth transfer. In other words, the BLE was blocking the SPI  

    Removing the "while"  fixed this blocking problem. SPI transactions are happening at the proper rate now - but I worry I'm not queueing packets properly (which is why I'm getting some dropped packets). Do you know if how the queueing is handled in the backend? Or is this something I have to implement myself? If so, does that mean I 'have' to move the BLE transfers to my main loop?

    Edit: I took another look at my sdk_config and I saw the following block:

    // <e> NRF_BLE_QWR_ENABLED - nrf_ble_qwr - Queued writes support module (prepare/execute write)
    //==========================================================
    #ifndef NRF_BLE_QWR_ENABLED
    #define NRF_BLE_QWR_ENABLED 1
    #endif
    // <o> NRF_BLE_QWR_MAX_ATTR - Maximum number of attribute handles that can be registered. This number must be adjusted according to the number of attributes for which Queued Writes will be enabled. If it is zero, the module will reject all Queued Write requests. 
    #ifndef NRF_BLE_QWR_MAX_ATTR
    #define NRF_BLE_QWR_MAX_ATTR 0
    #endif

    I probably need to make NRF_BLE_QWR_MAX_ATTR at least 1 for the NUS notifications. Don't I? I also don't see anything in my sdk config for length extension. Do you know if I have to enable this in my SDK_config?

    2) Ahh that makes alot of sense. So playing with tx power and link budget won't really help me with this blocking problem that I'm dealing with. At least that's cleared up!

    Thanks so much for your help, Simon. I really appreciate it!

    Kindest regards,

    Ryan

  • Hi

    The Queued Writes application in the SDK should give a good example on how to use the queued writes module. You will indeed have to set the NRF_BLE_QWR_MAX_ATTR define to 1 or more, depending on how many attribute handles you want to be able to register. As stated, if this is zero, all queued write requests will be rejected by the Queued Write module.

    Best regards,

    Simon

  • Hi Simon,

    Thank you for the pointer! A previous post had pointed me to the ble_app_uart example but it seems like it might not actually use the queued writes module. 

    Unfortunately, I may be barking up the wrong tree here - I was reading this post and they mention:

    that queued writes only make sense if you want to synchronize 
    writes to multiple characteristics, so that the change take 
    effect simultaneously.


    That's not actually what I want to do. I really just want to send a large amount of data at a fast rate without breaking my SPI. Furthermore, from looking through everything it seems that the central device is the one that actually uses the "queued writes" and peripheral devices just receive them (or am I wrong there?).

    Looking back I should have stated this in the original post: my problem is that my peripheral device needs to perform SPI transactions every 500us and I need to send all this SPI data over BLE without halting the SPI operationsI know for a fact people have done this sort of thing before, but it seems I'm terrible at googling it because I only ever get my forum posts hahaha.

    Is there a way to run the BLE in parallel with SPI? If so, does it involve using the SPI interrupt and CPU bound BLE_transfers? 

    Do you know what would happen if I gave the (ble_nus_data_send) a packet that was larger than 256 bytes? Does the bluetooth peripheral automatically break it into the correct number of packets?

    Thank you so much, Simon! I can't tell you how much I appreciate all of your help and this sort of support from Nordic.

    Kindest regards,

    Ryan

  • Hi

    It seems like you're on the right track. You're using the SPI example for SPI communication I presume, and the ble_app_uart example to see how we get data from a serial device and send that data over BLE? If you're struggling with the buffer being taken by the radio peripheral, hindering the SPI from transmitting data, you can do double buffering. Good discussion on that here.

    Trying to transmit more than 251 bytes in one BLE packet would result in an error as that would be outide of the BLE specification. This is very well explained in this Novelbits blog post. It also explains how BLE packets are built up.

    Best regards,

    Simon

Related