How to read a large file (About 240MB) from SD card

Hello all, I hope you are doing well. 

I Have a project on NRF52840 in which I have multiple sensors connected to the NRF52 and the sensor data are storing in the SD card in the form of a CSV file of size 240 MB. I want to read this large file from the SD card and then send it to the mobile app using ble_periperhial. I have used This example and modified it, but the problem is that I can only read 220000 bytes from the SD card in the buffer at once and when I am trying to increase 

   #define FILE_SIZE_MAX (Maximum size in bytes of the file to be read from SDCARDgreater than 220000, while the following;

                                            static uint8_t file_buffer[FILE_SIZE_MAX]; 

                                           ff_result = f_read(&file, file_buffer, FILE_SIZE_MAX, (UINT *) &bytes_read);

 Then it gives the following error:

                                      .bss is too large to fit in RAM1 memory segment
                                     .heap is too large to fit in RAM1 memory segment
                                      section .heap overlaps absolute placed section .stack
                                      section .stack VMA [000000002003e000,000000002003ffff] overlaps section .bss VMA [0000000020002c64,0000000020224b08]   

                                               

I don't know about this error and how to solve it. Simply I want to read the whole file (234MB) from the SD card at once and then send it in chunks to the mobile app, Is this possible or do I have to read in chunks from the SD card too? 

Any help regarding this will be highly appreciated.

Parents
  • Hi 

    Unfortunately you only have 256kB of RAM available in the nRF52840 device, and parts of this RAM will be needed by the rest of your application, which is probably why the code won't build if you make your buffer larger than 220000 bytes. 

    In other words you will have to split up the transaction into smaller chunks, yes. 

    The most efficient solution would be to match the reads from your external memory to the size of your Bluetooth packets, and make sure that you buffer multiple BLE packets at once to make sure the BLE communication doesn't have to wait for the reads from external memory. 

    Best regards
    Torbjørn

  • Hi Torbjørn, thanks for the quick help. 

    Unfortunately you only have 256kB of RAM available in the nRF52840 device, and parts of this RAM will be needed by the rest of your application, which is probably why the code won't build if you make your buffer larger than 220000 bytes. 

    Okay, I understand, and thanks for the thorough explanation. 

    The most efficient solution would be to match the reads from your external memory to the size of your Bluetooth packets, and make sure that you buffer multiple BLE packets at once to make sure the BLE communication doesn't have to wait for the reads from external memory. 

    Can you please refer me to a ticket/blog etc where they have read from the SD card in chunks(my Bluetooth packet is 244 bytes)? I have tried different approaches but I am unable to read from an SD card in chunks. I don't know how to change the pointer to the next byte/line of the SD card data. When I read the first 220000 bytes( #define FILE_SIZE_MAX    220000) of data from a file on the SD card then I am unable to change the pointer to the next index( 220000+1th  byte). Can you please help me with that? 

    Thanks & kind Regards,

    Sami

  • Hi Sami

    Samiulhaq said:
    I am able to send 2284066 bytes in about 30 seconds.

    Again, this is not bad. If my math is correct this is more than 600kbps, which is very close to the maximum limit when running at 1M phy (the maximum limit is somewhere around 760kbps). 

    Samiulhaq said:
    How can I check the connection parameter? using nRF_Sniffer ?

    Yes, you can find the connection interval in the sniffer trace by looking for the LL_CONNECTION_UPDATE_IND packets. There are several of these in the trace, but it is the last one that is the important one. If you look at packets 874 and 877 in the trace you will see that the slave requests a connection interval of 50ms in packet 874, and the central accepts this request in packet 877. 

    This implies that your project is configured to ask for a 50ms connection interval, which is not optimal for throughput. If you change this to 15ms you might be able to get even closer to the theoretical maximum. 

    Samiulhaq said:
    How can I check for a larger MTU? MTU size in the sdk_config.h is as follows:

    Looking at the trace, and your throughput numbers, it is clear that the MTU is correctly configured. 

    Samiulhaq said:
    Where can I use these lines in my code? in the case BLE_GAP_EVT_CONNECTED:?

    Correct. 

    Samiulhaq said:
    Can you please test the project on your side?

    At the moment I don't think this is necessary. I believe you should be able to achieve better throughput by changing the connection interval and phy, I doubt there is much else you can do. 

    By the way, did you confirm which phone you are using for the testing? 

    As I mentioned earlier many phones will be slower than what you see with this phone, so it is important to not have too high expectations. BLE was never really designed for high throughput after all.

    Best regards
    Torbjørn

  • Hello Torbjørn, thanks for the reply.

    Again, this is not bad. If my math is correct this is more than 600kbps, which is very close to the maximum limit when running at 1M phy (the maximum limit is somewhere around 760kbps). 

    How can I check whether the communication is using 1M PHY or 2M? I want to use 2M PHY, how can I enable it, or maybe I have enabled it already but my phone is not supporting 2M PHY, how to check that? 

     

    This implies that your project is configured to ask for a 50ms connection interval, which is not optimal for throughput. If you change this to 15ms you might be able to get even closer to the theoretical maximum. 

    When I am trying to reduce the connection interval then I am facing a lot of empty packets which reduce the throughput, what will be a problem in your opinion? 

    By the way, did you confirm which phone you are using for the testing? 

    I have tested on 03 phones, Vivo, Samsung, and Poco. My personal phone Vivo Y51s (Android version 12) does not support 2M PHY I guess. The sniffer trace I have shared with you is from the Vivo phone. The Samsung I guess is supporting 2M PHY but the throughput is very low compared to the Vivo phone. And the POCO one is very fast, I have tested it on my own project( the one with serial operations of reading from SD card and sending to BLE) and I have achieved a decent throughput of about2284066 bytes in 23-25 seconds. But now it is not giving a good throughput (even worse than the Vivo with 1M PHY). I don't know the reason.  That's why I want you to test it on your side and do the necessary modifications ( like connection interval, 2M PHY, etc). 

    Thanks & Best Regards,

    Sami

  • Hi Sami

    Samiulhaq said:
    How can I check whether the communication is using 1M PHY or 2M? I want to use 2M PHY, how can I enable it, or maybe I have enabled it already but my phone is not supporting 2M PHY, how to check that? 

    To try and enable 2M phy you can run the following code after the connection is established:

    ble_gap_phys_t gap_phys_settings; 
    gap_phys_settings.tx_phys = BLE_GAP_PHY_2MBPS;  
    gap_phys_settings.rx_phys = BLE_GAP_PHY_2MBPS;         
    sd_ble_gap_phy_update(m_conn_handle, &gap_phys_settings);

    In order to see which phy you actually get you have to wait for the BLE_GAP_EVT_PHY_UPDATE event to be forwarded to the application. If the phone supports this event will tell you. 

    Just to show which phy was enabled you can log the status of this event like this:

    case BLE_GAP_EVT_PHY_UPDATE:
        NRF_LOG_INFO("Phy update: TX Phy %i, RX Phy %i", \
              (int)p_ble_evt->evt.gap_evt.params.phy_update.tx_phy, \
              (int)p_ble_evt->evt.gap_evt.params.phy_update.rx_phy);
        break;

    What the phy values mean can be found in ble_gap.h:

    /**@defgroup BLE_GAP_PHYS GAP PHYs
     * @{ */
    #define BLE_GAP_PHY_AUTO                         0x00    /**< Automatic PHY selection. Refer @ref sd_ble_gap_phy_update for more information.*/
    #define BLE_GAP_PHY_1MBPS                        0x01    /**< 1 Mbps PHY. */
    #define BLE_GAP_PHY_2MBPS                        0x02    /**< 2 Mbps PHY. */
    #define BLE_GAP_PHY_CODED                        0x04    /**< Coded PHY. */
    #define BLE_GAP_PHY_NOT_SET                      0xFF    /**< PHY is not configured. */

    Another way to check if your phone supports 2M phy is to install the nRF Connect app, and open the Device Information tab. There you will get an overview of which optional BLE features are supported or not. 

    Samiulhaq said:
    When I am trying to reduce the connection interval then I am facing a lot of empty packets which reduce the throughput, what will be a problem in your opinion? 

    This sounds very odd. Does this happen on all the phones, or only on some of them? 
    How small is the connection interval in this case?

    Samiulhaq said:
    That's why I want you to test it on your side and do the necessary modifications ( like connection interval, 2M PHY, etc). 

    I can do some testing later in the week, but I will be limited by the phones I have available. I can test it with one of the high end Samsung phones and ensure that there is no bottle neck on the nRF side at least, and make sure that 2M is enabled, but optimizing across many different phones I will have to leave with you ;)

    Best regards
    Torbjørn

  • Hey Torbjørn, thanks for the thorough explanation. 

    To try and enable 2M phy you can run the following code after the connection is established:

    Yes, I can enable 2M PHY in the case BLE_GAP_EVT_CONNECTED: of the ble_evt_handler() with the help of the following lines:

                ble_gap_phys_t const phys =
                {
                     .rx_phys = BLE_GAP_PHY_2MBPS,
                     .tx_phys = BLE_GAP_PHY_2MBPS,
                };
                err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
                APP_ERROR_CHECK(err_code);
    

    I can confirm that I have switched to the 2M PHY from the sniffer trace and the log. Is this the correct way to enable 2M PHY?

    When I am using 1M PHY I can send the 2284066 bytes in about 26-27 seconds which is quite good but the problem is that when I switched to 2M PHY then the rate of data transfer(throughput) decreased a lot although I assumed a high throughput in 2M PHY but it is just the opposite of my expectation. What do you think will be the reason for the small throughput in 2M PHY than 1M? 

    This sounds very odd. Does this happen on all the phones, or only on some of them? 
    How small is the connection interval in this case?

    I have tested on three different phones and almost every phone has this behavior(decreasing conn. interval leads to more empty packets). when the conn. interval is 40-50 then the number of empty packets is the least but when I decrease the conn. interval then I am facing empty packets which leads to small throughput and when I increase the conn. interval then the throughput decreases( I don't know why).

    I can do some testing later in the week, but I will be limited by the phones I have available. I can test it with one of the high end Samsung phones and ensure that there is no bottle neck on the nRF side at least, and make sure that 2M is enabled, but optimizing across many different phones I will have to leave with you ;)

    Yes please, do a test on a high-speed phone on your side and let me know about the throughput. If you want me to send you my project which has the SD card functionality then let me know I will share it with you and you can test it on your side with a good phone. If the throughput is small then kindly do some necessary modifications ( like conn. interval, 2M PHY, MTU size, Event_length, etc) in the projects and sent me back. I will be very thank full to you. 

    Best Regards,

    Sami

  • Hi Torbjørn,

    **UPDATE:

    I have tested on three different phones and almost every phone has this behavior(decreasing conn. interval leads to more empty packets). when the conn. interval is 40-50 then the number of empty packets is the least but when I decrease the conn. interval then I am facing empty packets which leads to small throughput and when I increase the conn. interval then the throughput decreases( I don't know why).

    I have reduced the connection interval and it increases the throughput(in the phone which supports 2M PHY).

    Now I am the problem of "When I am using 1M PHY I can send the 2284066 bytes in about 26-27 seconds which is quite good but the problem is that when I switched to 2M PHY then the rate of data transfer(throughput) decreased a lot although I assumed a high throughput in 2M PHY but it is just the opposite of my expectation. What do you think will be the reason for the small throughput in 2M PHY than 1M"?  This happens only in this project (the one you have provided).

    What do you think about this?

    Best Regards,

    Sami 

Reply
  • Hi Torbjørn,

    **UPDATE:

    I have tested on three different phones and almost every phone has this behavior(decreasing conn. interval leads to more empty packets). when the conn. interval is 40-50 then the number of empty packets is the least but when I decrease the conn. interval then I am facing empty packets which leads to small throughput and when I increase the conn. interval then the throughput decreases( I don't know why).

    I have reduced the connection interval and it increases the throughput(in the phone which supports 2M PHY).

    Now I am the problem of "When I am using 1M PHY I can send the 2284066 bytes in about 26-27 seconds which is quite good but the problem is that when I switched to 2M PHY then the rate of data transfer(throughput) decreased a lot although I assumed a high throughput in 2M PHY but it is just the opposite of my expectation. What do you think will be the reason for the small throughput in 2M PHY than 1M"?  This happens only in this project (the one you have provided).

    What do you think about this?

    Best Regards,

    Sami 

Children
  • Hi Sami

    Are you able to share sniffer traces for the two cases, with the transfer happening in 1M and 2M modes respectively? 

    Also, which phone is showing this behavior?

    I actually have seen similar behavior on the Huawei P20 Pro, where the 2M mode showed significantly lower transfer speed. The reason for this was that when enabling 2M phy the phone was only able to send a single packet in each connection event, while in 1M mode it could send multiple packets. In this case it is clearly a bug on the phone side, where the 2M support is not properly implemented. 

    Best regards
    Torbjørn

  • Hi Torbjørn, thanks for the reply.

    Are you able to share sniffer traces for the two cases, with the transfer happening in 1M and 2M modes respectively? 

    Yes sure,  Actually I am attaching 4 sniffer files:

                 1) 1M PHY conn.interval=50

                 2) 1M PHY conn.interval=10

                 3)  2M PHY conn.interval=50

                 4)  2M PHY conn.interval=10

    The result I have concluded from the 4 traces is that:

    1) Increasing conn. interval in 1M PHY leads to high throughput, that is:

                  Throughput at conn. interval 50 >>  Throughput at conn. interval 10

    2) Increasing conn. interval in 2M PHY leads to decreased(lower) throughput, that is:

                  Throughput at conn. interval 10 >>  Throughput at conn. interval 50

    Your comment about that? I am totally confused about what's going on. 

    Also, which phone is showing this behavior?

    Samsung Galaxy A30, Android version 11.

    I actually have seen similar behavior on the Huawei P20 Pro, where the 2M mode showed significantly lower transfer speed. The reason for this was that when enabling 2M phy the phone was only able to send a single packet in each connection event, while in 1M mode it could send multiple packets. In this case it is clearly a bug on the phone side, where the 2M support is not properly implemented. 

     I don't think so the problem is with the phone because I have tested another project (the same project but Modified by me in which I am reading data from an SD card and sent on ble directly without the involvement of fifo or other temporary storage.), in which case the 2M PHY has achieved a decent throughput (2284066 bytes in about 23-24 seconds) with the same phone. 

    I don't know why this project has a problem with 2M PHY. Have you tested it on your side? 

    If you want more information just let me know and thanks for your through explanation and help.

    Best Regards,

    Sami

    1M_PHY_Sniffer_trace_conn_interval_10.pcapng

    1M_PHY_conn_interval_50_sniffer_trace.pcapng

    2M_PHY_conn_interval_10_sniffer_trace.pcapng

    2M_PHY_conn_interval_50_sniffer_trace.pcapng

  • Hi Sami

    Thanks for sharing all the traces. 

    I only had limited time to work on your case today, so I prioritized fixing my example. 

    You were correct that there were some issues with it. I wasn't sending full length packets in all cases, and also discovered an issue with the code going to sleep even if you had more data to send. 

    I pushed an update to the repo which should fix these issues.

    Are you able to check out the updated example and see if it works better?

    I will have to come back to you on the traces and the 2M phy issues next week. 

    Best regards
    Torbjørn 

  • Hey Torbjørn , thanks.

    Are you able to check out the updated example and see if it works better?

    I am going to test it now and let you know about the outcomes. Thanks for updating the project.

    I will have to come back to you on the traces and the 2M phy issues next week. 

    Okay sir sure, thanks. 

    Best Regards,

    Sami

  • Hey Torbjørn Sir, I hope you will be fine.

    ** UPDATE

    Sir, I have updated the project with the changes you have made, Now I have achieved a decent throughout of ~1063kbps with a very good phone which is capable of achieving a throughput of >1300kbps.

    Now I have some questions, but first, let me explain the different scenarios, and then I will come to my questions. 

    First Scenario: 

    I have another project which is doing the same task (Reading a file from an SD card and sending it to ble) but the logic is different and simple( Reading data from an SD card and send directly to Ble without the use of temporary storage or TX complete event), see the below code snippet.

    #define MIN_CONN_INTERVAL               MSEC_TO_UNITS(20, UNIT_1_25_MS)             /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
    #define MAX_CONN_INTERVAL               MSEC_TO_UNITS(75, UNIT_1_25_MS)             /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */
    
    
    static uint8_t file_found_on_sdcard = false;
    static uint8_t file_buffer[FILE_SIZE_MAX];
    static uint32_t file_actual_read_size = 0;
    static uint8_t file_send_to_peripheral = false;
    
    uint32_t timestamp_test_start, timestamp_test_stop;
        // Enter main loop.
        for (;;)
        {
            if(file_send_to_peripheral)
            {
             timestamp_test_start = app_timer_cnt_get();
                if(size > 0)   // size of file
                {
                uint32_t remaining_bytes = size;  
                uint16_t chunk_length = BLE_NUS_MAX_DATA_LEN;
                ret_code_t err_code;
    
                while(remaining_bytes > 0)
                  {
    
                   ff_result = f_read(&file, file_buffer, sizeof(file_buffer), (UINT *) &bytes_read);
                    do
                     {
                     err_code= ble_nus_data_send(&m_nus, file_buffer, &chunk_length, m_conn_handle);
    
                    if ((err_code != NRF_ERROR_INVALID_STATE) &&
                        (err_code != NRF_ERROR_RESOURCES) &&
                        (err_code != NRF_ERROR_NOT_FOUND))
                      {
                          APP_ERROR_CHECK(err_code);
                          remaining_bytes -= chunk_length;
                           m_total_num_bytes += chunk_length;
                       if(remaining_bytes < chunk_length)
                          {
                          chunk_length = remaining_bytes;
                          }
                        //NRF_LOG_INFO("Remaining bytes to send: %d", remaining_bytes);
    
                      }
                     }while((err_code == NRF_ERROR_RESOURCES));
                  }
                }
    
                file_send_to_peripheral = false;
                timestamp_test_stop = app_timer_cnt_get();
                uint32_t diff = app_timer_cnt_diff_compute(timestamp_test_stop, timestamp_test_start);
                uint32_t kbps = (uint32_t)((float)(size * 8) / ((float)diff / 16384.0f) / 1024.0f);
                NRF_LOG_INFO("Test complete! Time passed: %i, ~%i kbps", diff, kbps);
            }
            //idle_state_handle();
            while(NRF_LOG_PROCESS());
        }
    }
    

     

    The throughput achieved by this project is the following.

    The Sniffer trace is the following: 

    MyProject_Sniffer_trace.pcapng

    Questions Related to this Scenario:

    1) If you see the throughput in the above-attached screenshot you will see that sometime the throughput goes to >1200kbps and even >1300kpbs, but the throughput is not stable means the throughput is varying and sometimes goes very low, and sometimes very high. I don't find the reason for this behavior, Can you please explain this? 

    2) The throughput in this case is increasing when I increase the connection intervals and vice versa. I expect to have a high throughput on small connection intervals but it is just the opposite of my expectation. What do you think about this? 

    2) Second Scenario:

    I have made some necessary changes to the project you have provided, see the below code snippet:

    #define MIN_CONN_INTERVAL               MSEC_TO_UNITS(15, UNIT_1_25_MS)             /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
    #define MAX_CONN_INTERVAL               MSEC_TO_UNITS(15, UNIT_1_25_MS)             /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */
    
    
    // Create a FIFO structure
    app_fifo_t dummy_fifo;
    
    uint32_t dummy_fifo_bytes_used;
    
    // Create a buffer for the FIFO
    #define DUMMY_FIFO_SIZE 512
    uint8_t dummy_buffer[DUMMY_FIFO_SIZE];
    
    static int dummy_buffer_write(uint8_t *data, uint32_t len)
    {
        app_fifo_write(&dummy_fifo, data, &len);
        dummy_fifo_bytes_used += len;
        return len;
    }
    
    static int dummy_buffer_bytes_free(void)
    {
        return DUMMY_FIFO_SIZE - dummy_fifo_bytes_used;
    }
    
    static int dummy_buffer_read(uint8_t *data, uint32_t len)
    {
        app_fifo_read(&dummy_fifo, data, &len);
        dummy_fifo_bytes_used -= len;
        return len;
    }
    
    static int dummy_buffer_bytes_used(void)
    {
        return dummy_fifo_bytes_used;
    }
    
    static void init_dummy_buffer(void)
    {
        // Initialize FIFO structure
        uint32_t err_code = app_fifo_init(&dummy_fifo, dummy_buffer, DUMMY_FIFO_SIZE);
        APP_ERROR_CHECK(err_code);
    
        dummy_fifo_bytes_used = 0;
    }
    
    
    #define TEST_DUMP_SIZE  size                       // Size of the file in the SD card
    #define TEST_READ_SIZE  BLE_NUS_MAX_DATA_LEN       // BLE_NUS_MAX_DATA_LEN  =244
    #define TEST_WRITE_SIZE BLE_NUS_MAX_DATA_LEN       //m_ble_nus_max_data_len
    uint32_t dummy_test_remaining_bytes_read = 0;
    uint32_t dummy_test_remaining_bytes_write = 0;
    
    /**@brief Application main function.
     */
    int main(void)
    {
        bool erase_bonds;
        uint32_t err_code;
    
        // Initialize.
        uart_init();
        log_init();
        timers_init();
        buttons_leds_init(&erase_bonds);
        power_management_init();
         fatfs_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        services_init();
        advertising_init();
        conn_params_init();
    
        init_dummy_buffer();
    
        // Start execution.
        //printf("\r\NRF_ERROR_RESOURCES test started.\r\n");
        NRF_LOG_INFO("Debug logging for UART over RTT started.");
        advertising_start();
         timers_start();
    
        static uint8_t tmp_read_buffer[TEST_READ_SIZE];
        static uint8_t tmp_write_buffer[BLE_NUS_MAX_DATA_LEN];
        uint16_t write_length;
        int bt_written;
    
    
         uint32_t timestamp_test_start, timestamp_test_stop;
        // Enter main loop.
        for (;;)
        {
            // If the run_dummy_test flag is set, start a new data dump test
            if(run_dummy_test) 
            {
                run_dummy_test = false;
                bt_written = 0;
                dummy_test_remaining_bytes_read = TEST_DUMP_SIZE;
                timestamp_test_start = app_timer_cnt_get();
            }
    
            // As long as there are bytes left to read, and there is room in the dummy buffer, read out a single packet
            if(dummy_test_remaining_bytes_read && dummy_buffer_bytes_free() >= TEST_READ_SIZE)
            {
                // Set the read_length to the minimum of the remaining bytes to read and the test read size
                uint32_t read_length = (dummy_test_remaining_bytes_read > TEST_READ_SIZE) ? TEST_READ_SIZE : dummy_test_remaining_bytes_read;
    
                // Read SD card data into a temporary array
                ff_result = f_read(&file, tmp_read_buffer, sizeof(tmp_read_buffer), (UINT *) &bytes_read);
    
                // Move the SD card data from the temporary array into our FIFO buffer
                dummy_buffer_write(tmp_read_buffer, read_length);
    
                // Reduce the remaining number of bytes to read for the test
                dummy_test_remaining_bytes_read -= read_length;
    
                NRF_LOG_DEBUG("Dummy data produced %i, remaining %i", read_length, dummy_test_remaining_bytes_read);
            }
    
            // As long as there is data in the dummy buffer, and the Bluetooth stack has free buffers, upload a packet to the Bluetooth stack
            // If retransmit_previous_buffer is set it means the packet stored in tmp_write_buffer still hasn't been successfully
            // sent (because of NRF_ERROR_RESOURCES). In this case we try to send it again, without reading new data from the FIFO
           if(ble_buffers_available && (dummy_buffer_bytes_used() >= TEST_WRITE_SIZE || retransmit_previous_buffer || \
                                        (dummy_buffer_bytes_used() > 0 && dummy_test_remaining_bytes_read == 0)))
            {
                //bsp_board_led_off(0);
    
                // Read new data from the FIFO unless retransmit_previous_buffer is set, in which case we have to retransmit the last packet
                if(!retransmit_previous_buffer)
                {
                    // Move a new packet from the FIFO to the temporary write buffer
                    write_length = dummy_buffer_read(tmp_write_buffer, TEST_WRITE_SIZE);
    
                    NRF_LOG_DEBUG(" Fifo to tmp %i bytes", write_length);
                } 
    
                // Forward a single packet to the Bluetooth stack
                // NOTE: This code assumes that write_length will not be changed by ble_nus_data_send(..) (this could happen if you try to send a packet
                //       longer than the negotiated MTU size). If this could happen then the code needs to be changed to ensure that the remaining data gets
                //       written afterwards. 
                err_code = ble_nus_data_send(&m_nus, tmp_write_buffer, &write_length, m_conn_handle);
                if(err_code == NRF_SUCCESS)
                {
                    // In case of success, update the bt_written parameter (please note the data will still take some time to reach the Bluetooth client)
                    bt_written += write_length;
                    m_total_num_bytes+= write_length;
                    //NRF_LOG_INFO("   Tmp to BT total: %i (+%i)", bt_written, write_length);
                }
                else if(err_code == NRF_ERROR_RESOURCES) 
                {
                    // In case of NRF_ERROR_RESOURCES, clear the ble_buffers_available flag to avoid trying to send more data until the Bluetooth buffers
                    // clear up. This flag will be set by the BLE_GATTS_EVT_HVN_TX_COMPLETE event in the ble_evt_handler function in main.c
                    ble_buffers_available = false;
    
                    //bsp_board_led_on(0);
    
                    //NRF_LOG_INFO("     ERROR RESOURCES");
                }
                else if(err_code != NRF_ERROR_INVALID_STATE && err_code != NRF_ERROR_NOT_FOUND)
                {
                    APP_ERROR_CHECK(err_code);
                }
                
                // The retransmit_previous_buffer should be cleared for any upload. 
                // If NRF_ERROR_RESOURCES were to happen again it should be set again in the ble_evt_handler
                retransmit_previous_buffer = false;
    
                if(bt_written == size) 
                {
                     timestamp_test_stop = app_timer_cnt_get();
                    uint32_t diff = app_timer_cnt_diff_compute(timestamp_test_stop, timestamp_test_start);
                    uint32_t kbps = (uint32_t)((float)(TEST_DUMP_SIZE * 8) / ((float)diff / 16384.0f) / 1024.0f);
                    // Any other code that should be added upon completion can be added here. 
                    NRF_LOG_INFO("Test complete! Time passed: %i, ~%i kbps", diff, kbps);
                }
            }
            while(NRF_LOG_PROCESS());
            //idle_state_handle();
        }
    }

    The throughput achieved by this project is the following:

     

    The Sniffer trace is the following: 

    Torbjørn_Provided_Project_Sniffer_trace.pcapng

    The throughput is very stable in this case as you can see in the attached screenshot.

    Questions: 

    1)  Why the throughput doesn't go to ~1200kbps or 1300kbps in this case as goes in 1st scenario? I want the throughput to be ~1200kbps or greater, How can this be achieved?

    2) If you see the above sniffer trace, there are a lot of empty packets which I think limit the throughput to ~1000-1060kbps. How to reduce/eliminate these empty packets? 

    3) The throughput, in this case, is Maximum at the connection interval(Min & Max =15) and when I try to increase the connection interval then the throughput decreases, and when decreases the connection interval then it leads to more empty packets which decreases the throughput. Can you please explain this behavior? 

    Best Regards,

    Sami

     

Related