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: BLE stack malloc

Part Number: CC2340R5

Tool/software:

Hi we are developing an application where CC2340r5 (as Central) connects to device and writes data in every 30s using

GATT_WriteNoRsp

and receives notification in 

ATT_HANDLE_VALUE_NOTI
Problem: Heap memory full.
Behaviour: On observation it has found that Allocations > Frees in RTOS Object View (screenshot attached). More importantly, for every complete notification we are receiving, after every complete notification i can see that Allocations is incrementing by 20 but Frees are incrementing by 16 only
NOTE: it includes . 
GATT_bm_alloc for  ATT_WRITE_REQ and len=8bytes
  • Hi,

    Can you share your code for how you are handling the writes and notification reception? It is possible that a free statement may be missing.

    Best Regards,

    Jan

  • For sending data, i am using the following function.
    NOTE: I am aware that on error i have to free memory. But be assured return code is always success in our case.
    xBSW_FsmBleSendDataTk
    (IVEC_BswFsmBLEHandle_s* pxBLEFsmHandle, uint8_t* pu8Data,
        uint8_t u8Len)
    {
        IVEC_BSW_FUNC_ENTRY(LOG_STRING);
        if (pxBLEFsmHandle == NULL)
        {
            return commonBSW_INVALID_PARAM;
        }
        attWriteReq_t l_xRq = { .handle =
                                   pxBLEFsmHandle->xMyBleConn.u16CharValueHandle,
                               .len = u8Len,
                               .cmd = 1,
                               .sig = 0 };
        l_xRq.pValue = GATT_bm_alloc(pxBLEFsmHandle->xMyBleConn.u16Conn,
            ATT_WRITE_REQ, u8Len, NULL);
        memcpy(l_xRq.pValue, pu8Data, u8Len);
        bStatus_t status =
            GATT_WriteNoRsp(pxBLEFsmHandle->xMyBleConn.u16Conn, &l_xRq);
        IVEC_BSW_LOG(LOG_STRING, "Sending data: %d %d 0x%x %d\n", pxBLEFsmHandle->xMyBleConn.u16Conn,
            l_xRq.len, l_xRq.handle, status);
        IVEC_BswCommonErr_e l_xError = commonBSW_WRITE_FAIL;
        if (status == SUCCESS)
        {
            l_xError = commonBSW_SUCCESS;
            pxBLEFsmHandle->xMyMetrics.u32LastTxBLE = 0;//TODO: add value
        }
         
        IVEC_BSW_FUNC_EXIT(LOG_STRING, l_xError);
        return l_xError;
    }
    NOTE: I am using BLEAppUtil from TI for events processing
    BLEAppUtil_EventHandler_t dataGATTHandler = {.handlerType =
                                                     BLEAPPUTIL_GATT_TYPE,
                                                 .pEventHandler = GATT_EventHandler,
                                                 .eventMask = 0xffffffff};

    bStatus_t Data_start(void)
    {
        bStatus_t status = SUCCESS;

        // Register the handlers
        status = BLEAppUtil_registerEventHandler(&dataGATTHandler);

        // Return status value
        return (status);
    }

    For receiving notification, i am using the following code
    static void GATT_EventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
    {
        gattMsgEvent_t *gattMsg = (gattMsgEvent_t *)pMsgData;
        switch (gattMsg->method){
    case ATT_HANDLE_VALUE_NOTI:
        {
            IVEC_BswFsmBLEHandle_s *l_pxTempBleHandle = IVEC_BswFsmBleGetHandle(gattMsg->connHandle);
            if (l_pxTempBleHandle && l_pxTempBleHandle->fpv_FsmBleDataCb)
            {
                l_pxTempBleHandle->xMyMetrics.u32LastRcvdBLE=0;//TODO: add value
                l_pxTempBleHandle->fpv_FsmBleDataCb(l_pxTempBleHandle, gattMsg->msg.handleValueNoti.pValue, gattMsg->msg.handleValueNoti.len);
            }
            Display_printf(__gprv_DisplayUart, 0, 0, "ATT_HANDLE_VALUE_NOTI %d %d ",
                           gattMsg->msg.handleValueNoti.len,
                           gattMsg->msg.handleValueNoti.handle);
            if (gattMsg->msg.handleValueNoti.len > 0)
            {
                for (uint8 i = 0; i < gattMsg->msg.handleValueNoti.len; i++)
                {
                    Display_printf(__gprv_DisplayUart, 0, 0, "0x%x ",
                                   gattMsg->msg.handleValueNoti.pValue[i]);
                }
                // ICall_freeMsg(gattMsg->msg);
            }
            Display_printf(__gprv_DisplayUart, 0, 0, "\n");
        }
        break;
    }
    }
    NOTE: i am not using malloc and free in code written by me.
  • Hi,

    After receiving a notification, I believe that you need to use       GATT_bm_free() to free the received notification data.

    Best Regards,

    Jan

  • Hi,
    As i can check in the file bleapputil_task.c provided by TI, memory is being freed by TI. On investigation this task is freeing memory as frees counter is incrementing. But we are still unable to discover 4 allocations that are not being freed.

    void *BLEAppUtil_Task(void *arg)
    {
        // Register to the stack and create queue and event
        BLEAppUtil_stackRegister();

        // Init the ble stack
        BLEAppUtil_stackInit();

        // Application main loop
        for (;;)
        {
            BLEAppUtil_appEvt_t pAppEvt;

            // wait until receive queue message
            if (mq_receive(BLEAppUtil_theardEntity.queueHandle, (char*)&pAppEvt, sizeof(pAppEvt), NULL) > 0)
            {
                BLEAppUtil_msgHdr_t *pMsgData = (BLEAppUtil_msgHdr_t *)pAppEvt.pData;
                bool freeMsg = FALSE;

                switch (pAppEvt.event)
                {
                  case BLEAPPUTIL_EVT_STACK_CALLBACK:
                  {
                      // Set the flag to true to indicate that BLEAppUtil_freeMsg
                      // should be used to free the msg
                      freeMsg = TRUE;

                      switch (pMsgData->event)
                      {
                          case GAP_MSG_EVENT:
                              BLEAppUtil_processGAPEvents(pMsgData);
                              break;

                          case GATT_MSG_EVENT:
                              BLEAppUtil_processGATTEvents(pMsgData);
                              break;

                          case L2CAP_DATA_EVENT:
                              BLEAppUtil_processL2CAPDataMsg(pMsgData);
                              break;

                          case L2CAP_SIGNAL_EVENT:
                              BLEAppUtil_processL2CAPSignalEvents(pMsgData);
                              break;

                          case HCI_GAP_EVENT_EVENT:
                              BLEAppUtil_processHCIGAPEvents(pMsgData);
                              break;

                          case HCI_DATA_EVENT:
                              BLEAppUtil_processHCIDataEvents(pMsgData);
                              break;

                          case HCI_SMP_EVENT_EVENT:
                              BLEAppUtil_processHCISMPEvents(pMsgData);
                              break;

                          case HCI_SMP_META_EVENT_EVENT:
                              BLEAppUtil_processHCISMPMetaEvents(pMsgData);
                              break;

                        case HCI_CTRL_TO_HOST_EVENT:
                        {
                            BLEAppUtil_processHCICTRLToHostEvents(pMsgData);
                            hciPacket_t *pBuf = (hciPacket_t *)pMsgData;
                            switch (pBuf->pData[0])
                            {
                              case HCI_ACL_DATA_PACKET:
                              case HCI_SCO_DATA_PACKET:
                                BM_free(pBuf->pData);
                              default:
                                break;
                            }
                            break;
                        }


                        default:
                            break;
                    }
                    break;
                }
                  case BLEAPPUTIL_EVT_ADV_CB_EVENT:
                  {
                      BLEAppUtil_processAdvEventMsg(pMsgData);
                      if (((BLEAppUtil_AdvEventData_t *)pMsgData)->event != BLEAPPUTIL_ADV_INSUFFICIENT_MEMORY &&
                          ((BLEAppUtil_AdvEventData_t *)pMsgData)->pBuf)
                      {
                          BLEAppUtil_free(((BLEAppUtil_AdvEventData_t *)pMsgData)->pBuf);
                      }
                      break;
                  }

                  case BLEAPPUTIL_EVT_SCAN_CB_EVENT:
                  {
                      BLEAppUtil_processScanEventMsg(pMsgData);
                      if (((BLEAppUtil_ScanEventData_t *)pMsgData)->event == BLEAPPUTIL_ADV_REPORT &&
                          ((BLEAppUtil_ScanEventData_t *)pMsgData)->pBuf->pAdvReport.pData)
                      {
                          BLEAppUtil_free(((BLEAppUtil_ScanEventData_t *)pMsgData)->pBuf->pAdvReport.pData);
                      }
                      if (((BLEAppUtil_ScanEventData_t *)pMsgData)->event != BLEAPPUTIL_SCAN_INSUFFICIENT_MEMORY &&
                          ((BLEAppUtil_ScanEventData_t *)pMsgData)->pBuf)
                      {
                          BLEAppUtil_free(((BLEAppUtil_ScanEventData_t *)pMsgData)->pBuf);
                      }
                      break;
                  }

                  case BLEAPPUTIL_EVT_PAIRING_STATE_CB:
                      BLEAppUtil_processPairStateMsg(pMsgData);
                      break;

                  case BLEAPPUTIL_EVT_PASSCODE_NEEDED_CB:
                      BLEAppUtil_processPasscodeMsg(pMsgData);
                      break;

                  case BLEAPPUTIL_EVT_CONN_EVENT_CB:
                      BLEAppUtil_processConnEventMsg(pMsgData);
                      break;

                  case BLEAPPUTIL_EVT_CALL_IN_BLEAPPUTIL_CONTEXT:
                  {
                      ((BLEAppUtil_CallbackToInvoke_t *)pMsgData)->callback(((BLEAppUtil_CallbackToInvoke_t *)pMsgData)->data);

                      // Verify that the data is not NULL before freeing it
                      if(((BLEAppUtil_CallbackToInvoke_t *)pMsgData)->data != NULL)
                      {
                          BLEAppUtil_free(((BLEAppUtil_CallbackToInvoke_t *)pMsgData)->data);
                      }
                      break;
                  }

                  default:
                      break;
                }

                // Free the data
                if (pMsgData && freeMsg)
                {
                    // Use freeMsg
                    BLEAppUtil_freeMsg(pMsgData);
                }
                else if (pMsgData)
                {
                    // Use free
                    BLEAppUtil_free(pMsgData);
                }
                else
                {
                    /* this else clause is required, even if the
                    programmer expects this will never be reached
                    Fix Misra-C Required: MISRA.IF.NO_ELSE */
                }
            }
        }
    }
  • Hi,

    Got it. At a glance, that looks okay to me. I think we will need to narrow in on the problematic allocations to figure out what we may be missing. I would suggest adding breakpoints around known allocation points to see if we can find the one that increases the heap permanently.

    Best Regards,

    Jan

  • Hi
    The issue is reproducible in example basic ble.
    Since the example does not have code for writing data to peripheral device i had to copy app_menu.c from the following source https://github.com/TexasInstruments/ble_examples/tree/simplelink_low_power_f3_sdk-7.40.01/examples/rtos/LP_EM_CC2340R5/ble5stack/basic_ble_GATT_client/app

    I have altered the code of the following function to receive data from my device

    void Menu_doGattWriteCB(uint8 index)
    {
        bStatus_t status;

        uint8_t charVals[8] =  {0xea, 0xd1, 0x01, 0x04, 0xff, 0x04, 0xff, 0xf5};;
        attWriteReq_t req;
        req.pValue = GATT_bm_alloc(menuCurrentConnHandle, ATT_WRITE_REQ, 8, NULL);
        req.len = 8;
        req.handle=0xd;
        // charVal = charVals[index];
        memcpy(req.pValue ,charVals,8);
        req.sig = 0;
        req.cmd = 1;

        status =GATT_WriteNoRsp(menuCurrentConnHandle, &req);
        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);


        if ( status != SUCCESS )
            {
                GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
            }
        // Go back to the last menu
        MenuModule_goBack();
    }

    Just before sending the data request i noted the readings of refreshed allocations and frees as 9094, 9007
    After receiving data, i noted the readings of refreshed allocations and frees as 9116, 9025
    As we can clearly see that 4 frees are missing, as found in my earlier posts.
    I have tried to find allocations but not sure where to look since that code belongs to simplink sdk.
    Also, i am using sdk version: 8.10.1.02
  • Hi,

    Thank you for the further testing! To ensure I am understanding correctly, the basic_ble example is able to exhibit this behavior when the app_menu.c file from the link you shared is used? Otherwise, the behavior does not occur, correct (because the original does not operate as a GATT client)?

    Best Regards,

    Jan

  • Hi

    the basic_ble example is able to exhibit this behavior when the app_menu.c file from the link you shared is used?

    If you are understanding that code in app_menu.c, has to do something with my issue, then as per my observation it is incorrect.

    Otherwise, the behavior does not occur, correct (because the original does not operate as a GATT client)?

    I haven't checked about other scenarios yet as my focus is primarily on notifications. I only used the example to show that while receiving notifications, 4 frees are missing possibly due to Ble stack  or bleapp utils memory mishandling. .


    NOTE: My single notification is divided into 4 events of Ti ble stack. I have also verified that following code is freeing the memory when GATT event handler returns:

    if (pMsgData && freeMsg)
                {
                    // Use freeMsg
                    BLEAppUtil_freeMsg(pMsgData);
                }

  • Hi,

    I am guessing that we are missing something in the application code. Possibly in the app_menu.c. My thought is that theres a case or callback that requires that we use BLEAppUtil_freeMsg() to free a received block, but we are not doing so. In your code, are you verifying that the GATT operations return SUCCESS and if not, then freeing the allocated payload?

    Best Regards,

    Jan

  • For sending data, i am using the following function.
    NOTE: I am aware that on error i have to free memory. But be assured return code is always success in our case

    Yes, we are doing that.
    I don't think we are supposed to free the block in user code as the api  BLEAppUtil_freeMsg() is defined in bleapputil_internal.h.

    I believe free is missing from  BLEAppUtil.
    Do you have information about allocations being done to receive notifications. So that we can track if that particular block is being freed or not.

  • Hi

     We have found by experimentation that we needed to use 

     GATT_bm_free(&gattMsg->msg,gattMsg->method)  in 
     case ATT_HANDLE_VALUE_NOTI:

    Now, we are good with notifications receiving.
    I think there should be a proper example or guide for such things which i have not found yet.
    Please share if you have reference for development resources.
    Thanks.