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

Connection timeout at central

Hi,

I'm using the example "ble_central/ble_app_uart_c" of nRF5_SDK_17.0.2. Connection to peripheral workes fine.

If the central re-starts while a connection is established, the peripheral get a "disconnect" event and wait for a new connection.

If the peripheral re-starts while a connection is established, the central get no "disconnect" event and runs into fatal error.

So, how to set up central, to handle a "disconnect" by timeout?

Thanks for helping!

Parents
  • Hello,

    I'm using the example "ble_central/ble_app_uart_c" of nRF5_SDK_17.0.2.

    Have you made any changes to the central example? If so, what changes have you made?

    the central get no "disconnect" event and runs into fatal error.

    That sounds strange - the central should resume scanning for a peripheral device when a link is broken.
    Could you make sure to have DEBUG defined in your preprocessor defines, like shown in the included image?

    This will make a detailed error message be outputted to your logger whenever a non-NRF_SUCCESS error code is passed to an APP_ERROR_CHECK. Please do this, and let me know what this error message says when the device resets.

    Looking forward to resolving this issue together!

    Best regards,
    Karl

  • Hello Karl,

    thank you for your soon response. First the error message:

    <info> app_timer: RTC: initialized.
    <info> app: BLE UART central example started.
    <info> app: Connecting to target 340D3750ACE0
    <info> app: ATT MTU exchange completed.
    <info> app: Ble NUS max data length set to 0xF4(244)
    <info> app: Discovery complete.
    <info> app: Connected to device with Nordic UART Service.
    <error> nrf_ble_gq: SD GATT procedure (1) failed on connection handle 0 with error: 0x00000013.
    <error> app: ERROR 19 [NRF_ERROR_RESOURCES] at C:\Projekte\MyCompany\0288_TT_BLE_Modul\nRF5_SDK_17.0.2_d674dde\examples\ble_central\ble_app_uart_c\main.c:123
    PC at: 0x0002F57D
    <error> app: End of error report

    I have made some "small" changes in main.c:

    • set ECHOBACK_BLE_UART_DATA to 0
    • in void uart_event_handle(app_uart_evt_t * p_event):
      Check connection state befor sending data
          if (m_ble_nus_c.conn_handle != BLE_CONN_HANDLE_INVALID)
          {
              switch (p_event->evt_type)
              {
                  case APP_UART_DATA_READY:
                      ...
              }
          }

    Here is some background information:

    The BLE module is connected to our µC (STM32) via UART. This STM32 sends a heartbeat every 250ms via uart -> BLE to the peripheral - indipending of a BLE connection state. If there is no connection established, the central runs into a fatal error. Therefore we have checked the connection handle before sending the data via BLE.

  • Hi Karl,

    we tried something to find out the interacting of

    • heartbeat cycle
    • disconnection time and
    • queue size.
    We found the place where the dosconnection time can be set. If we reduce this time (from 4000ms to 1000ms), a disconnection will be recognized before the queue overflows.
    Unfortunately we have not found the place where to adjust the size of the queue. Can this also be found in the sdk_config?
  • Hello again,

    the other issue with the APP_UART_COMMUNICATION_ERROR while initialization seems also to be fixed (by a workaround): We have changed the order of the initialization sequence and have moved uart_init() behind the ble_stack_init().

    While doing so, we have no APP_UART_COMMUNICATION_ERROR  anymore.

    While initialization the uart interrupts are already enabled, although the BLE stack has not yet been initialized. This obviously leads to this error.

    What better solution here than just changing the initialization order?

  • Hello again Andi,

    Thank you for your patience.

    Andi_Frueh said:
    We found the place where the dosconnection time can be set. If we reduce this time (from 4000ms to 1000ms), a disconnection will be recognized before the queue overflows.

    Yes, the connection timeout can be adjusted to fit the specific application. 
    You should also consider the environment that the device will be working in when configuring this, because packet loss or corruption happens more frequently in a 2.4 GHz noisy environment, or in an environment in which the peripheral and central moves behind obstacles and further away from each other. What connection interval are you using currently?
    The connection interval is what determines how often there is scheduled communication between the two devices, so for example if you need your central to stop a machine as fast as possible if a heartbeat is not received you can likely set the connection timeout even lower if you are using a low connection interval, such as 7.5 ms.

    Andi_Frueh said:
    Unfortunately we have not found the place where to adjust the size of the queue. Can this also be found in the sdk_config?

    The size of the queue, are you here talking about the UARTE RX buffer, or the hvn_tx_queue_size?

    Andi_Frueh said:
    What better solution here than just changing the initialization order?

    Is it a possibility for you to use flow control?
    This should negate this issue all together.
    Alternatively, perhaps your STM could wait until it receives some kind of go-ahead signal before it starts sending the heartbeats. This could for example be a start command sent over UART, or similar.

    Best regards,
    Karl

  • Good Morning Karl,

    What connection interval are you using currently?

    If I'm right, the connection intervall is defined in sdk_config.h with 7.5...30 ms. So we can decrease the disconnection timeout, as you suggested.

    #define NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL   7.5
    #define NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL    30
    #define NRF_BLE_SCAN_SUPERVISION_TIMEOUT      4000

    The size of the queue, are you here talking about the UARTE RX buffer, or the hvn_tx_queue_size?

    In main.c the uart buffer size is defined by 256 Byte. Increasing or decreasing this size has no effect to the disconnection detection. If the connection is broken, it takes around 4 seconds and the central runs into the error handle, before to detect disconnection.

    Is it a possibility for you to use flow control?

    Using flow control is not desired. Is there a way to disable / enable uart interrupts by application, without changing SDK code? If so, we could disable the uart irq while initialization phase.

    You could implement specific error handling for specific errors.

    What would be an adequate error handling for

    1. APP_UART_COMMUNICATION_ERROR while initialization
    2. NRF_ERROR_RESOURCES while sending cyclic data with a broken connection

    Regards,
    Andi

  • Hello Andi,

    Andi_Frueh said:
    If I'm right, the connection intervall is defined in sdk_config.h with 7.5...30 ms. So we can decrease the disconnection timeout, as you suggested.

    Great! Yes, you could also set the two values to be equal, this will make the only possible connection interval whatever you define them too be. So long as this is fine with the peer (the central always decides, but the peripheral may be configured to disconnect if it does not support it), then this will always be the used connection interval. This also gives you a better predictability for how often the messages will be coming in.
    It also seems to me that you are here still using the 4000 ms connection supervision timeout, is this intentional or will you be lowering it later on?

    Andi_Frueh said:
    In main.c the uart buffer size is defined by 256 Byte. Increasing or decreasing this size has no effect to the disconnection detection. If the connection is broken, it takes around 4 seconds and the central runs into the error handle, before to detect disconnection.

    Does this means that it takes around 4 seconds for the UART buffer to overflow?
    Because if it is the 4 s connection timeout event will not cause it to enter the error handler, because a disconnection (for whatever reason) is not an application layer error. It is expected that a link may be broken at whatever time.
    If you decrease the connection supervision timeout to something much smaller, say 200 ms (with 7.5 ms connection interval this still gives you ~26 connection event tries to get your packets through before disconnecting), this would let you get the disconnected event much sooner. 

    Andi_Frueh said:

    What would be an adequate error handling for

    1. APP_UART_COMMUNICATION_ERROR while initialization

    This depends a little, but you could likely just ignore it during initialization unless this means that you are missing out on some critical / unique information. For example, you could ignore it until the UART peripheral is ready, clear the RX buffer, and then begin normal operation.

    Does your heartbeats contain any information, such as a timestamp or status?
    If they do not, you could for example just discard the information that is received during startup and wait for the next one.

    Andi_Frueh said:
    NRF_ERROR_RESOURCES while sending cyclic data with a broken connection

    This could also just be ignored in the case that you do not have any additional information contained in the heartbeat signal.
    For example if your hvn tx queue size is 1, there can only be queued a single heartbeat for sending at any one time. If the heartbeats come in every 250 ms, and you have a supervision timeout of < 250 ms, you will keep trying to send the same heartbeat notification up until either it goes through (and you then are ready for the next heartbeat) or until the connection is declared broken once the supervision timeout runs out.

    The important part for the error handling in both of these cases is that you do not use the default error handling, since this is to reset the device, which here would terminate the link and do no good.

    Best regards,
    Karl

Reply
  • Hello Andi,

    Andi_Frueh said:
    If I'm right, the connection intervall is defined in sdk_config.h with 7.5...30 ms. So we can decrease the disconnection timeout, as you suggested.

    Great! Yes, you could also set the two values to be equal, this will make the only possible connection interval whatever you define them too be. So long as this is fine with the peer (the central always decides, but the peripheral may be configured to disconnect if it does not support it), then this will always be the used connection interval. This also gives you a better predictability for how often the messages will be coming in.
    It also seems to me that you are here still using the 4000 ms connection supervision timeout, is this intentional or will you be lowering it later on?

    Andi_Frueh said:
    In main.c the uart buffer size is defined by 256 Byte. Increasing or decreasing this size has no effect to the disconnection detection. If the connection is broken, it takes around 4 seconds and the central runs into the error handle, before to detect disconnection.

    Does this means that it takes around 4 seconds for the UART buffer to overflow?
    Because if it is the 4 s connection timeout event will not cause it to enter the error handler, because a disconnection (for whatever reason) is not an application layer error. It is expected that a link may be broken at whatever time.
    If you decrease the connection supervision timeout to something much smaller, say 200 ms (with 7.5 ms connection interval this still gives you ~26 connection event tries to get your packets through before disconnecting), this would let you get the disconnected event much sooner. 

    Andi_Frueh said:

    What would be an adequate error handling for

    1. APP_UART_COMMUNICATION_ERROR while initialization

    This depends a little, but you could likely just ignore it during initialization unless this means that you are missing out on some critical / unique information. For example, you could ignore it until the UART peripheral is ready, clear the RX buffer, and then begin normal operation.

    Does your heartbeats contain any information, such as a timestamp or status?
    If they do not, you could for example just discard the information that is received during startup and wait for the next one.

    Andi_Frueh said:
    NRF_ERROR_RESOURCES while sending cyclic data with a broken connection

    This could also just be ignored in the case that you do not have any additional information contained in the heartbeat signal.
    For example if your hvn tx queue size is 1, there can only be queued a single heartbeat for sending at any one time. If the heartbeats come in every 250 ms, and you have a supervision timeout of < 250 ms, you will keep trying to send the same heartbeat notification up until either it goes through (and you then are ready for the next heartbeat) or until the connection is declared broken once the supervision timeout runs out.

    The important part for the error handling in both of these cases is that you do not use the default error handling, since this is to reset the device, which here would terminate the link and do no good.

    Best regards,
    Karl

Children
No Data
Related