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

BTLE_CONNECTION_TIMEOUT while connection interval is small

Hi experts,

I need nrf51822 to send thousands of packets (notification) to Master Control Panel (PC), and expect for high data rate. So, I turned the connection interval from 100 ms to 20 ms in Master Control Panel. Unfortunately, the connection is broken after about 5 seconds. Everything is ok if the connection interval is 100ms.

my device configuration is like #define MIN_CONN_INTERVAL MSEC_TO_UNITS(10, UNIT_1_25_MS) #define MAX_CONN_INTERVAL MSEC_TO_UNITS(200, UNIT_1_25_MS) #define SLAVE_LATENCY 10
#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(5000, UNIT_10_MS)

It seems the reason of timeout is I can't send packets as soon as possible. While the connection interval is 20 ms, the actual data rate is about 30 packets per seconds. The low data rate should be because I need read data from SPI Flash for sending.

I'm very confused why it happened. If I didn't send any notification, the connection was always on; but it timeout if I sent notification not fast enough.

Wondering for your help!

  • Difficult to say what is causing this. You mention that you are using SPI, does it work if you exclude that from you project? Could you edit your question and share some code, maybe even upload your complete project so I could test it here? If it is secret, you can also upload it privately through your MyPage at nordicsemi.com

  • Thanks, Petter. Yes, it ran ok if I didn't read from SPI. In my project, I repeatedly read 19 bytes from SPI Flash and send it in notification packet, when the Master write a command. If I comment the read_spi function, it works fine. I did another experiment, in which, I didn't send the packets and tried to read out all the data (about one thousand of records, each is 19 bytes). I found the link will timeout also before all the data had been read out. The code seems be cancelled, because it can't reach the breakpoint below the read lines. I stop the simulator, and found cpu is running sd_app_evt_wait() in power_manage(). here is my code:

    when Master write the command, I will call send_one_package to send the records to Master:

    static INLINE uint32_t send_one_package() {
    data_frame_t frame;
    uint32_t err_code;
    frame.header = FRAME_HEADER;
    frame.type = FRAME_TYPE_HIST;
    for (; pack_report.current_rec < pack_report.current_pack_len; pack_report.current_rec++) {
    if (1 == fetch_a_record((uint8_t *)&(frame.record), pack_report.current_pack, pack_report.current_rec)) {
    frame.record.csum += FRAME_PRE_CSUM_HIST;
    err_code = ble_send((uint8_t *)&frame, DATA_FRAME_SIZE);     
    if (err_code == BLE_ERROR_NO_TX_BUFFERS) {
        ble_tx_complete_handler_set(send_one_package);
        break;
      } else if ( err_code == NRF_ERROR_INVALID_STATE || 
                  err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING) {
        ble_tx_complete_handler_set(send_one_package);      
        break;
      } else if (err_code != NRF_SUCCESS) {
        APP_ERROR_HANDLER(err_code);
      }
    }
    }
    return err_code;
    }
    

    where the fetch_a_record is the function to read SPI Flash. If I comment this, everything is ok.

    int8_t fetch_a_record(record_array_t rec_arr, package_no_t package, record_no_t rec) {
      record_t *record = (record_t *)rec_arr;
      address_t addr;
      addr = cal_record_address(package, rec);
      SPI_FLASH_BufferRead(rec_arr, addr, RECORD_LEN);
      return 1;
    }
    

    The flash read function is :

    void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead) {
      SPI_FLASH_CS_LOW();
      SPI_FLASH_SendByte(Read_Data);
      SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
      SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
      SPI_FLASH_SendByte(ReadAddr & 0xFF);
      while(NumByteToRead--) {
        *pBuffer = SPI_FLASH_ReceiveByte();
        pBuffer++;
      }
      SPI_FLASH_CS_HIGH();
    }
    
    uint8_t SPI_FLASH_ReceiveByte(void) {
      return (SPI_FLASH_SendByte(Dummy_Byte));
    }
    

    ble_tx_complete_handler_set() will set the handler, which will be called in BLE_EVT_TX_COMPLETE event. So, I can send all the records repeatedly.

    I failed to upload the entire project for the weak network. Please have a look if the above code can help. I will try it later.

    BTW, I saw in ble_flash.c, there is

    static void flash_word_write(uint32_t * p_address, uint32_t value) {
        // If radio is active, wait for it to become inactive.
        while (m_radio_active)     {
            // Do nothing (just wait for radio to become inactive).
            (void) sd_app_evt_wait();
        }
    ...
    }
    

    Should I also wait for the radio to be inactive when I access the flash?

    Thanks a lot!

  • My project is based on sdk9.0, but the spi master driver I used is copied from previous SDK. In this driver, spi_master_tx_rx() is called to send and receive data. spi_master_tx_rx() is a sync calling, which will wait for spi_base->EVENTS_READY before it returns. Is it the reason of timeout? Will the CPU be too busy for SPI and be timeout for BLE?

  • Ok. When the central writes to the peripheral SPI fetches some data from an external flash and send it to the central with notifications. It seems you are not using interrupts, so the the SoftDevice should be able to interrupt any operation, including SPI, to maintain the connection. Could it be that an error is sent to app_error_handler() somewhere? And this resets the chip? Try putting a breakpoint in app_error_handler(). ble_flash.c is for accessing the internal flash of the nRF5, but you have an external flash if I have understood you correctly. With regards to your other experiment, maybe you fill are filling up the complete RAM space?

  • Thanks Petter. I have solved this problem, by rewriting the spi flash access functions using the new spi_master driver, which enables spi interrupt. So, I think the problem may be due to the polling method. Too much cpu cycles are wasted to waiting for spi completion. BTW, I found sd_ble_gatts_hvx will return NRF_ERROR_INVALID_STATE if it is called in interrupt. I used scheduler to solve it.

    Thanks again!

Related