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!

Parents
  • 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!

Reply
  • 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!

Children
No Data
Related