This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2541 Connection Event getting triggered wrongly by the BLE Stack even though the Central Device sends new Connection Interval Max Value after Connection Parameter Update Request

Other Parts Discussed in Thread: CC2541

Hi,

We are using the CC2541 as a Peripheral Device.

Our Connection Interval Params are as below:

Conn Interval Min = 7.5 ms

Conn Interval Max = 12.5 ms

Slave Latency = 0

Supervision Timeout = 10 seconds

We have set the "enable automatic parameter update request when a connection is formed" to TRUE.

The issue that we are seeing is when we connect to Central Device, the Central Device sends Connection Parameter Update Request to 11.25 ms i.e. value is set as 9 (9 * 1.25ms = 11.25ms). But we get the Connection Events from the BLE Stack at every 50ms.

Our BLE Stack version is 1.4.0 (BLE-CC254x-1.4.0).


To confirm the above we did the below mentioned code changes:

We referred the SensorTag Sample Project and we have added code to detect:

Connection Events from the Stack

Connection Parameter Request Updates from the Stack

How we have measured the Connection Events from the BLE Stack is by the below code :

HCI_EXT_ConnEventNoticeCmd(AppTaskID, CONN_EVENT_COMPLETE_EVT);

Also we have registered the Connection Parameter Update Request callback in our Application Task Init function:

VOID GAPRole_RegisterAppCBs( &paramUpdateCB );

 

So when we get the Connection Event, we process the CONN_EVENT_COMPLETE_EVT and we take the difference between two consecutive connection events, so that we know what exactly is the Connection Event followed by our BLE Controller.

Also when we get the Connection Parameter Update Request from Central Device, we are logging the new Connection Interval Max sent by the Central Device.

What we observed is that, the Central Device sends the Connection Parameter Update Request with value of 9 (9 * 1.25ms = 11.25ms), but the difference between the two consecutive Connection Events from the stack is 50ms.

So is there a bug in the Stack that the new Connection Interval is not honored or are we missing anything.

Thanks,
Sunny

  • Hello Sunny,

    Can you provide a sniffer trace showing the connection setup & update? Also, can you instrument your code with a GPIO pin toggle when you process the CONN_EVENT_COMPLETE_EVT?

    In addition, which sample project are you using, and what changes were made beyond what is stated above?

    Best wishes
  • Hi JXS,


    Thanks for your the reply.

    Actually we took the air capture and observed the following:

    Our setup is like below:

    We are peripheral device. Ours is a custom application based on SimpleBLEPeripheral Code.

    We are connecting with Central Device.

    What we observed in this problematic case is that the Central Device sends the Connection Interval as 0x27 = 39 * 1.25ms = 48.75ms.

    We have configured "enable automatic parameter update request when a connection is formed" to TRUE.

    But our BLE Stack never triggers the "Connection Parameter Update Request" once the connection is established.

    So we have the following questions:

    1. Once the connection is created, is there a way to know the Connection Interval configured, since we want to trigger the "Connection Parameter Update Request" procedure if the current Connection Interval decided by the Central Device is too big ?

    2. Even though we have configured the "enable automatic parameter update request when a connection is formed" to TRUE, does the Peripheral device, not trigger the "Connection Parameter Update Request" procedure if the Central device's Connection Interval does not match with our Peripheral device's configured Connection Interval and Slave Latency.

    The idea is, currently we come to know the Connection Interval configured by enabling the Connection_Events triggered by the Stack, and taking the difference between two consecutive Connection_Events. But this increases our processing overhead. So we want to avoid this and retrieve the already configured Connection Interval set by the Central Device.

    Thanks,
    Sunny

  • HI Sunny,

    What are the values for the following in your system:
    DEFAULT_CONN_PAUSE_PERIPHERAL
    ?

    The value of this (in secs) is the delay before the param update is sent.
    Also, attaching the full sniffer file will help :)

    Best wishes
  • Hello Sunny.

    1. Yes, upon a connection establishment, the connection event is passed to the GAPRole (peripheral.c) as part of the gapEstLinkReqEvent_t structure in the GAP_LINK_ESTABLISHED_EVENT:

    typedef struct
    {
    osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status
    uint8 opcode; //!< GAP_LINK_ESTABLISHED_EVENT
    uint8 devAddrType; //!< Device address type: @ref GAP_ADDR_TYPE_DEFINES
    uint8 devAddr[B_ADDR_LEN]; //!< Device address of link
    uint16 connectionHandle; //!< Connection Handle from controller used to ref the device
    uint16 connInterval; //!< Connection Interval
    uint16 connLatency; //!< Conenction Latency
    uint16 connTimeout; //!< Connection Timeout
    uint8 clockAccuracy; //!< Clock Accuracy
    } gapEstLinkReqEvent_t;

    The GAPRole stores this in the gapRole_ConnInterval which can be accessed using GAPRole_GetParameter(GAPROLE_CONN_INTERVAL,...). You can get this parameter in your application in the GAPRole callback function (i.e. peripheralStateNotificationCB for the simpleBLEPeripheral project) at the GAPROLE_CONNECTED state.

    You can also register with the GAPRole to be notified of a parameter update via the GAPRole_RegisterAppCBs(). See the function definition in peripheral.c.

    To summarize...you can always check the current connection parameter using the get parameter function as mentioned above and you can be notified of connection parameter changes by registering a pGapRoles_ParamUpdateCB callback function with the GAPRole.


    2. The update request will occur independent of what the Central device configures the initial connection parameters as. However, the central device does not have to accept the parameter update sent by the peripheral. IT is possible that it denies the request.
  • Hi JXS & Tim,


    Thank you for the reply.

    We are using the below for DEFAULT_CONN_PAUSE_PERIPHERAL:

    // Connection Pause Peripheral time value (in seconds)
    #define DEFAULT_CONN_PAUSE_PERIPHERAL    6


    I will not be able to share the full logs on E2E Forum since it is a public forum.
    But I can email you the logs. I would request you to please accept my friend request of E2E Profile so that I can share the logs with you.

    I have two more question however for sending the Connection Parameter Update Request.

    1. So based on the above DEFAULT_CONN_PAUSE_PERIPHERAL, the Connection Parameter Update Request will be sent by the peripheral device right?

    If the above is correct, then we never saw the Connection Parameter Update Request getting triggered from the peripheral device automatically.

    2. If the Connection Parameter Update Request is triggered from the peripheral device, then will the application (peripheral) get the pGapRoles_ParamUpdateCB callback?

    Because, at the moment, we are doing extra processing by enabling the CONNECTION_EVENT which get triggered from the BLE Stack and measuring the time difference between the two consecutive CONNECTION_EVENT every time. So we just want to remove this extra processing.

    Otherwise, as Tim suggested, we need to use the GAPRole_GetParameter(GAPROLE_CONN_INTERVAL,...) frequently throughout the connection. This will also be a overhead, but less when compared to the CONNECTION_EVENT measurement that we are doing currently.

    Thanks for your reply.

    Awaiting your reply.

    Thanks,

    Sunny

  • Hi JXS and Tim,

    As Tim suggested we added the below code at GAPROLE_CONNECTED state in peripheralStateNotificationCB():

    GAPRole_GetParameter(GAPROLE_MAX_CONN_INTERVAL, &connIntMax);

    if(connIntMax > 30)
    {

    // Update connection parameters
    GAPRole_SendUpdateParam( 6, 20, 0, 1000, GAPROLE_NO_ACTION);

    }

    We have also put the above same check in ProcessEvent() function in one of our Events which gets triggered every 2 seconds, so that we can trigger the Connection Parameter Update Procedure if Central Device exceeds the Connection Interval of 30 (i.e. 30 * 1.25ms).

    We are also logging the gapRole_MaxConnInterval, by sending it in the 3rd byte of our Data Service having the Attribute Handle  0x4C as shown in the below snapshot:

    As you can see from the above snapshot, although we have put code to trigger the Connection Parameter Update Procedure in our Data Event handled in the ProcessEvent() function, but the stack still does not trigger it.

    Also, it is observed that the gapRole_MaxConnInterval variable in peripheral.c file read by GAPRole_GetParameter(GAPROLE_MAX_CONN_INTERVAL, &connIntMax) is still showing 0x14 which is what is being set by Init() function, and when we call the GAPRole_SendUpdateParam().

    So we believe that somehow the stack is not triggering the Connection Parameter Update Request event though the application (Peripheral Device) is calling the GAPRole_SendUpdateParam() every 2 seconds and also the gapRole_MaxConnInterval variable is not getting updated of the current Connection Interval that is negotiated to 48.75ms.

    Can you please update regarding the same.

    I have the full air sniffer logs, but I will not be able to share them to this public forum.

    Awaiting your reply.

    Thanks,

    Sunny

  • Hi Sunny,

    How does the 3rd byte (highlighted) in the Notification packet correspond to the Connection Interval? Can you show a sniffer snapshot with the Connection parameter request and update sequence?

    Best wishes
  • Hi JXS,

    Please see the snapshot of the negotiated Connection Interval below:

    We have enabled the CONNECTION_EVENT from the BLE Stack via the below command:

    HCI_EXT_ConnEventNoticeCmd(TaskID, CONN_EVENT_COMPLETE_EVT);

    So on every Connection Interval we get the CONN_EVENT_COMPLETE_EVT event which we handle.
    In this CONNECTION_EVENT handling, we measure the time between two consecutive CONNECTION_EVENT.

    This measured time between two consecutive CONNECTION_EVENT should be the negotiated Connection Interval right ?

    The above time difference is being sent in the third byte of the notification packet.

    So in order to know the negotiated Connection Interval, we are logging the above mentioned time difference in the notification packet.

    Please do let me know if you require any other information regarding the same.

  • Hi,

    All of your screen shots shows an initial conn interval of 0x27 (48.75ms), and you further indicated that the time delta between to consecutive CONN_EVENT_COMPLETE_EVT events is ~ 50ms. So far, this indicates correct operation as the conn interval is 48.75ms.

    What I think is the issue is you are querying the GAPROLE_MAX_CONN_INTERVAL but considering this value to be the actual conn interval; this is incorrect and only returns what you are requesting. If you want to check the current interval, query GAPROLE_CONN_INTERVAL parameter.

    Also, to cross-check, you should see GAPRole_SendUpdateParam() getting triggered on your debugger.

    Best wishes
  • Hi JXS,

    Thanks for the information.

    We tried and it worked. We have not done extensive testing.

    But upon our basic code change @ peripheralStateNotificationCB() function during GAPROLE_CONNECTED state, we observed that we got the correct Connection Interval.

    Still one more question is there.

    In a scenario when the Bluetooth Low Energy Connection is created, and after lets say 2 minutes, the Peripheral Device sends Connection Parameter Update Request, then how does the Peripheral Application Code know that such request has been triggered by the BLE Stack (since we have set the Connection Update Request to TRUE).

    Thanks,

    Sunny

  • Hello Sunny. You can register to receive parameter update notifications from the GAPRole with the GAPRole_RegisterAppCBs() function. Please see my previous post for more information.

  • Hi Tim,


    Thanks a lot for your reply.

    On a leaving note, for the sake of clarity, as per the below diagram from the Bluetooth Core Specification v4.2:

    When the "LE Connection Update Complete" Event is sent from the Controller to the Host, the BLE Stack will call the GAPRole_RegisterAppCBs() function right ?

    And thus, the scenario of Connection Parameter Update Request sent from either Peripheral (we are Peripheral Device) or Central Device is handled by the GAPRole_RegisterAppCBs() function.

    Thanks again.

    Sunny

  • Hello Sunny. The GAPRole_RegisterAppCBs() function allows you to register an application callback function with with the GAPRole. Therefore, the function that you register is the function that will be called when the parameter update occurs. Note that this function must be of type:

    typedef void (*gapRolesParamUpdateCB_t)( uint16 connInterval,
                                             uint16 connSlaveLatency,
                                             uint16 connTimeout );
    

    There is an example of this in the sensor tag project in SensorTag.c.

  • Hi Tim,

    Thanks a lot for the reply.

    I will close this thread.

    That helped a lot.


    Thanks,
    Sunny

  • Just a note to anyone reading this thread that one has to be careful about using GAPRole_SendUpdateParam right after the change to the GAPROLE_CONNECTED state if you are setting a longer connection interval (even just 160 which is 200 ms) because some applications will do queries (e.g. for device information) right after connecting and may time out or respond very slowly if the connection interval is set longer.  I found this to be true with the Apple iOS and applications like LightBlue.  Though not documented, it seems that the setting of a delayed connection parameter update request using a delay set by the GAP parameter TGAP_CONN_PAUSE_PERIPHERAL is intentional and designed to have a connection be stabilized first (i.e. get all the fast communication stuff out of the way).  Note that the Apple iOS initial default connection parameter appears to be 30 ms and that they ignore the settings specified in the GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE (at least when it's part of scan response data though I suspect it will be ignored as part of advertising data as well).  They will honor a subsequent connection update request.