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.

CC2340R5: How to manage the Data PDU length?

Part Number: CC2340R5

Tool/software:

Hi TI,

I am using two CC2340R5 board and connect to each other, And set the Max Size of PDU for both devices to 240 in syscfg like the image below,

Later, I used a sniffer to check the content of the LL_LENGTH_REQ sent from the Central and found that the TX Max is only 27 bytes (the minimum PDU length as specified by SIG). Are there any other settings that need to be modified?

LL_LENGTH_REQ from Central


another LL_LENGTH_REQ from Peripheral

the SDK I use is simplelink_lowpower_f3_sdk_8_10_01_02

  • Hi,

    The MAX PDU length is simply the maximum length the PDU can be set to. This is not what it will be set to. You will need to configure the data length in the application code as well.

    Best Regards,

    Jan

  • Hi Jan,

    Thank you for your explanation. After that, I used 'ATT_EXCHANGE_MTU_REQ' between the two devices to handle this issue.

    Following that, I tried to send an 'ATT_WRITE_REQ,' and the code is shown below:

    // Exchange and set Max MTU
    attExchangeMTUReq_t req;
    uint8_t MTUVals = 251;
    req.clientRxMTU = MTUVals - L2CAP_HDR_SIZE;
    GATT_ExchangeMTU(gapEstMsg->connectionHandle, &req, BLEAppUtil_getSelfEntity());
    
    // Use ATT_WRITE_REQ to send local OOB data
    Req.handle = 37;
    uint8_t charVals[16];
    for (int i = 0; i < KEYLEN; i++)
    {
        charVals[i] = localOobData.rand[i];
    }
    Req.pValue = GATT_bm_alloc(gapEstMsg->connectionHandle, ATT_WRITE_REQ, sizeof(charVals), NULL);
    Req.len = sizeof(charVals);
    for (int i = 0; i < sizeof(charVals); i++)
    {
        Req.pValue[i] = charVals[i];
    }
    Req.sig = 0;
    Req.cmd = 0;
    
    bStatus_t status = GATT_WriteCharValue(gapEstMsg->connectionHandle, &Req, BLEAppUtil_getSelfEntity());
    if ( status != SUCCESS )
    {
        GATT_bm_free((gattMsg_t *)&Req, ATT_WRITE_REQ);
    }
    // Print the status of the gatt_WriteCharValue call
    MenuModule_printf(APP_MENU_GENERAL_STATUS_LINE, 0, "Call Status: GATTWrite = "
                      MENU_MODULE_COLOR_BOLD MENU_MODULE_COLOR_RED "%d" MENU_MODULE_COLOR_RESET,
                      status);

    However, the request could not be sent, and the error message printed via UART is shown in the image below:


    After multiple attempts, it seems the issue is with the first parameter, handle, in GATT_WriteCharValue(), but I'm not sure how to resolve it. Do you have any suggestions on how to address this problem?

  • Hi,

    Thank you for sharing your latest debug results. This is very helpful! Can you clarify why you suspect the first parameter of the function is the issue? Can you try printing the value you are passing to confirm it is indeed the connection handle we expect it to be?

    Best Regards,

    Jan

  • Hi,

    Because error code 22 converts to hexadecimal as 0x16, I looked it up in TI's library and found that it indicates a parameter error. I started troubleshooting with the handle parameter and discovered that entering 0 results in the 0x16 error message, while entering 1 returns 0x02. The other parameters, like pReq and taskId, are written according to the example code provided by TI on GitHub, so I believe the issue may lie with the handle.

    I add debug message to print the gapEstMsg->connectionHandle,the code is update below:

    // Exchange and set Max MTU
    attExchangeMTUReq_t req;
    uint8_t MTUVals = 251;
    req.clientRxMTU = MTUVals - L2CAP_HDR_SIZE;
    GATT_ExchangeMTU(gapEstMsg->connectionHandle, &req, BLEAppUtil_getSelfEntity());
    
    MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE2, 0, "my handle = "
                      MENU_MODULE_COLOR_BOLD MENU_MODULE_COLOR_RED "%d" MENU_MODULE_COLOR_RESET,
                      gapEstMsg->connectionHandle);
    
    // Use ATT_WRITE_REQ to send local OOB data
    Req.handle = 37;
    uint8_t charVals[16];
    for (int i = 0; i < KEYLEN; i++)
    {
        charVals[i] = localOobData.rand[i];
    }
    Req.pValue = GATT_bm_alloc(0, ATT_WRITE_REQ, sizeof(charVals), NULL);
    Req.len = sizeof(charVals);
    for (int i = 0; i < sizeof(charVals); i++)
    {
        Req.pValue[i] = charVals[i];
    }
    Req.sig = 0;
    Req.cmd = 0;
    
    bStatus_t status = GATT_WriteCharValue(0, &Req, BLEAppUtil_getSelfEntity());
    if ( status != SUCCESS )
    {
        GATT_bm_free((gattMsg_t *)&Req, ATT_WRITE_REQ);
    }
    // Print the status of the gatt_WriteCharValue call
    MenuModule_printf(APP_MENU_GENERAL_STATUS_LINE, 0, "Call Status: GATTWrite = "
                      MENU_MODULE_COLOR_BOLD MENU_MODULE_COLOR_RED "%d" MENU_MODULE_COLOR_RESET,
                      status);

    and the UART is shown the message below:


    the current handle is 0, so I also fill 0 into the GATT_WriteCharValue(), but it still print Error status = 22.

    However, when I removed the code that sends GATT_Exchange_MTU_REQ, and directly sent ATT_WRITE_REQ, it was successfully transmitted. The result is shown in the image below:


    So I suspect that after sending GATT_Exchange_MTU_REQ, the handle might have changed to something related to GATT or ATT. However, when I sent GATT_WriteCharValue(), I still passed the value of connectionHandle as the handle, which might be why the transmission failed. Of course, this is just my assumption. If I’m wrong, please correct me. Thank you.

    Best regards,

    Aki

  • Hi Aki,

    I believe you are right. I don't think you can call the GATT write API before the GATT Exchange API has posted its completion event. I also don't expect you to need to change the MTU size one every right, so I would suggest setting it to your desired value at the start of the connection and not everytime you need to perform a write.

    Best Regards,

    Jan

  • Hi,

    All the above code is written in the Connection_ConnEventHandler function's switch case for BLEAPPUTIL_LINK_ESTABLISHED_EVENT in app_connection.c. If I want to actively perform ATT_MTUExchange at the start of the connection, where would you suggest I write it?

    Best regards,

    Aki

  • Hi Aki,

    Got it. Thank you for clarifying. Can you remove the GATT procedures that are after the MTU Exchange? Try only doing the MTU exchange in the link established event and the writes in a separate event after some time. I would like to see if adding some time delay has an impact on this behavior.

    Best Regards,

    Jan

  • Hi Jan,

    In app_connection.c, I add some new event define for MTU exchange and ATT write,

    #define MTU_EXCHANGE_EVENT (uint32_t)BV(14)
    #define ATT_WRITE_OOB_DATA_CONFIRM_EVENT (uint32_t)BV(15)
    #define ATT_WRITE_OOB_DATA_RAND_EVENT (uint32_t)BV(16)
    #define OOB_PAIRING_EVENT (uint32_t)BV(17)
    #define SET_REMOTE_OOB_DATA_EVENT (uint32_t)BV(18)
    
    // Events handlers struct, contains the handlers and event masks
    // of the application central role module
    BLEAppUtil_EventHandler_t connectionConnHandler =
    {
        .handlerType    = BLEAPPUTIL_GAP_CONN_TYPE,
        .pEventHandler  = Connection_ConnEventHandler,
        .eventMask      = BLEAPPUTIL_LINK_ESTABLISHED_EVENT |
                          BLEAPPUTIL_LINK_TERMINATED_EVENT |
                          BLEAPPUTIL_LINK_PARAM_UPDATE_EVENT |
                          BLEAPPUTIL_LINK_PARAM_UPDATE_REQ_EVENT |
                          MTU_EXCHANGE_EVENT |
                          ATT_WRITE_OOB_DATA_CONFIRM_EVENT |
                          ATT_WRITE_OOB_DATA_RAND_EVENT |
                          OOB_PAIRING_EVENT |
                          SET_REMOTE_OOB_DATA_EVENT
    };

    Then, in Connection_ConnEventHandler(), I add the new cases to implement those new event,

    void Connection_ConnEventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
    {
        switch(event)
        {
            case BLEAPPUTIL_LINK_ESTABLISHED_EVENT:
            {
                gapEstLinkReqEvent_t *gapEstMsg = (gapEstLinkReqEvent_t *)pMsgData;
    
                // Add the connection to the connected device list
                Connection_addConnInfo(gapEstMsg->connectionHandle, gapEstMsg->devAddr);
    
                /*! Print the peer address and connection handle number */
                MenuModule_printf(APP_MENU_CONN_EVENT, 0, "Conn status: Established - "
                                  "Connected to " MENU_MODULE_COLOR_YELLOW "%s " MENU_MODULE_COLOR_RESET
                                  "connectionHandle = " MENU_MODULE_COLOR_YELLOW "%d" MENU_MODULE_COLOR_RESET,
                                  BLEAppUtil_convertBdAddr2Str(gapEstMsg->devAddr), gapEstMsg->connectionHandle);
    
                /*! Print the number of current connections */
                MenuModule_printf(APP_MENU_NUM_CONNS, 0, "Connections number: "
                                  MENU_MODULE_COLOR_YELLOW "%d " MENU_MODULE_COLOR_RESET,
                                  linkDB_NumActive());
    
                event = MTU_EXCHANGE_EVENT;
                Connection_ConnEventHandler(event, pMsgData);
    
                break;
            }
    
            case MTU_EXCHANGE_EVENT:
            {
                doAttMtuExchange();
    
                event = ATT_WRITE_OOB_DATA_CONFIRM_EVENT;
                Connection_ConnEventHandler(event, pMsgData);
                break;
            }
    
            case ATT_WRITE_OOB_DATA_CONFIRM_EVENT:
            {
                doAttWriteNoRspConfirm();
    
                event = ATT_WRITE_OOB_DATA_RAND_EVENT;
                Connection_ConnEventHandler(event, pMsgData);
                break;
            }
    
            case ATT_WRITE_OOB_DATA_RAND_EVENT:
            {
                doAttWriteNoRspRand();
    
                event = SET_REMOTE_OOB_DATA_EVENT;
                Connection_ConnEventHandler(event, pMsgData);
                break;
            }

    And I tried sending 16 bytes of data, which was successfully transmitted. The packet transmission sequence observed using a sniffer is shown in the image below:

    You can see that even after modifying the code to use events, the ATT_WRITE_CMD packet is transmitted faster than the BLE stack changes the MTU size. To prove that the MTU size has not been changed at the moment of transmitting the ATT_WRITE_CMD, I sent 32 bytes of data, and the result was a failure to transmit.

    If there are any logical errors in my code, please help me correct them. Thank you.



    Best regards,

    Aki

  • Hi,

    I have found the following sections of the user's guide which mentions how to configure for larger MTU sizes. Can you confirm that the steps outlined have been followed?

    https://dev.ti.com/tirex/content/simplelink_lowpower_f3_sdk_8_10_01_02/docs/ble5stack/ble_user_guide/html/ble-stack-5.x/gatt-cc23xx.html#configuring-for-larger-mtu-values

    The following section may also be helpful as it shows how to use the data length extension feature to send large amounts of data:

    https://dev.ti.com/tirex/content/simplelink_lowpower_f3_sdk_8_10_01_02/docs/ble5stack/ble_user_guide/html/ble-stack-common/link-layer-cc23xx.html?#utilizing-dle-in-the-application

    Best Regards,

    Jan

  • Hi,

    Based on the two links you provided, I called HCI_EXT_SetMaxDataLenCmd(251, 2120, 251, 2120) in App_StackInitDoneHandler and observed the values in the LL_LENGTH_REQ packet using a sniffer. However, the maximum PDU length that can be transmitted is still 27 bytes.

    So, is the only way to change the maximum packet length after connection still through GATT_ExchangeMTU()?

    Best regards,

    Aki

  • Hi Aki,

    Got it. Thank you for testing. After this latest change, can you share what the sniffer reports if you then call the ExchangeMTU function?

    Best Regards,

    Jan

  • Hi Jan,

    After call the ATT_ExchangeMTU, The sniffer reports are shown as below:

    and the ATT_READ_RSP can transmit more than 27 bytes data.

  • Hi,

    If I am not mistaken, what is happening is that code changes provided in the user's guide section i shared sets the hard max that the PDU may be and the exchange MTU change can be used to change the length to any length up to that max. So you are now able to implement the data length changes you were looking for?

    Best Regards,

    Jan

  • Hi,

    Yeah, the issue with the data PDU settings has now been resolved, really thanks for your help!