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.

CC1352R1F3 E版本长时间运行ble例程会造成内存耗尽问题?

Other Parts Discussed in Thread: CC1352R

CC1352R1F3   SimpleLink_CC13x2_CC26x2 SDK_4.30.00.54   导入CC1352R LanchPad --->Ble5_Stack --->simple_broadcaster例程  开启广播结束事件GAP_ADV_EVT_MASK_END,大概运行20分钟左右会造成内存耗尽的问题,表现在广播回调函数种消息入队分配不到内存。  请问这是什么原因造成的?

  • 请看一下下面这个贴,是不是类似问题:
    e2echina.ti.com/.../612738
  • 你好 有相关文档指导怎么快速进行内存泄漏问题的查找么?
  • 建议看一下如下文档的memory部分:
    dev.ti.com/.../debugging-index.html
  • 你好 我配置了simple_broadcaster_app.cfg中HEAPNGR_CONFIG = 0x81,查看ROV中HeapMem.Detailed中的信息,广播事件回调第一次少2字节,第2次少8字节,差不多这样循环,直至内存耗尽,请问这版SDKsimpleLink_broadcaster例程是否也存在内存泄露的问题?请帮忙确认下,比较着急!
  • 1、代码是否有改动?
    2、请说明一下测试步骤,是否每次都出现?
  • import例程之后,GapAdv_setEventMask只增加了GAP_ADV_EVT_MASK_END事件,每次都出现,
  • 不好意思 更正一下 每次GAP_EVT_ADV_END事件发生时都会少8个字节
  • GAP_EVT_ADV_END 事件加在哪里?SimpleBroadcaster_processAdvEvent?这部分以及其他修改的代码是否能贴上来?
  • 你好, 修改如下:

    1、 增加事件,simple_broadcaster.c中修改setEventMask函数参数增加GAP_ADV_EVT_MASK_END事件:

    // Set event mask
    status = GapAdv_setEventMask(advHandleLegacy,
                        GAP_ADV_EVT_MASK_START_AFTER_ENABLE | GAP_ADV_EVT_MASK_END |  
                        GAP_ADV_EVT_MASK_END_AFTER_DISABLE |
                         GAP_ADV_EVT_MASK_SET_TERMINATED);

    2、SimpleBroadcaster_processAdvEvent函数修改如下:

    static bool SimpleBroadcaster_processAdvEvent(sbGapAdvEventData_t *pEventData)
    {
            bool safeToDealloc = TRUE;

            static volatile uint8_t test;

           switch (pEventData->event)
           {
                     case GAP_EVT_ADV_START_AFTER_ENABLE:
                                   Display_printf(dispHandle, 2, 0, "Advertising");
                                   break;

                     case GAP_EVT_INSUFFICIENT_MEMORY:
                                  safeToDealloc = FALSE;
                                  break;


                     case GAP_EVT_ADV_END:
                                 test++;
                                 break;


                    default:
                             // Do nothing.
                                break;
           }

           return(safeToDealloc);
    }

    附上完整simple_broadcaster.文件:

    simple_broadcaster.c
    /******************************************************************************
    
     @file  simple_broadcaster.c
    
     @brief This file contains the Simple Broadcaster sample application for
            use with the CC2650 Bluetooth Low Energy Protocol Stack.
    
     Group: WCS, BTS
     Target Device: cc13x2_26x2
    
     ******************************************************************************
     
     Copyright (c) 2011-2020, Texas Instruments Incorporated
     All rights reserved.
    
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
     are met:
    
     *  Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
    
     *  Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
    
     *  Neither the name of Texas Instruments Incorporated nor the names of
        its contributors may be used to endorse or promote products derived
        from this software without specific prior written permission.
    
     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
     ******************************************************************************
     
     
     *****************************************************************************/
    
    /*********************************************************************
     * INCLUDES
     */
    
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Event.h>
    #include <ti/sysbios/knl/Queue.h>
    #include <ti/display/Display.h>
    
    #include "util.h"
    #include <icall.h>
    /* This Header file contains all BLE API and icall structure definition */
    #include <icall_ble_api.h>
    #include <devinfoservice.h>
    
    #ifdef USE_RCOSC
    #include "rcosc_calibration.h"
    #endif //USE_RCOSC
    
    #include <ti_drivers_config.h>
    #include "ti_ble_config.h"
    #include "simple_broadcaster.h"
    
    /*********************************************************************
     * MACROS
     */
    
    /*********************************************************************
     * CONSTANTS
     */
    
    // Task configuration
    #define SB_TASK_PRIORITY                     1
    
    #ifndef SB_TASK_STACK_SIZE
    #define SB_TASK_STACK_SIZE                   1024
    #endif
    
    #define SB_ADV_EVT                           1
    
    // Internal Events for RTOS application
    #define SB_ICALL_EVT                         ICALL_MSG_EVENT_ID // Event_Id_31
    #define SB_QUEUE_EVT                         UTIL_QUEUE_EVENT_ID // Event_Id_30
    
    #define SB_ALL_EVENTS                        (SB_ICALL_EVT | \
                                                   SB_QUEUE_EVT)
    
    // Spin if the expression is not true
    #define SIMPLEBROADCASTER_ASSERT(expr) if (!(expr)) HAL_ASSERT_SPINLOCK;
    /*********************************************************************
     * TYPEDEFS
     */
    
    // App event passed from stack modules. This type is defined by the application
    // since it can queue events to itself however it wants.
    typedef struct
    {
      uint8_t event;                // event type
      void    *pData;               // pointer to message
    } sbEvt_t;
    
    /*********************************************************************
     * GLOBAL VARIABLES
     */
    
    // Display Interface
    Display_Handle dispHandle = NULL;
    
    /*********************************************************************
     * EXTERNAL VARIABLES
     */
    
    /*********************************************************************
     * EXTERNAL FUNCTIONS
     */
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    
    // Entity ID globally used to check for source and/or destination of messages
    static ICall_EntityID selfEntity;
    
    // Event globally used to post local events and pend on system and
    // local events.
    static ICall_SyncHandle syncEvent;
    
    // Queue object used for app messages
    static Queue_Struct appMsgQueue;
    static Queue_Handle appMsgQueueHandle;
    
    // Task configuration
    Task_Struct sbTask;
    #if defined __TI_COMPILER_VERSION__
    #pragma DATA_ALIGN(sbTaskStack, 8)
    #else
    #pragma data_alignment=8
    #endif
    uint8_t sbTaskStack[SB_TASK_STACK_SIZE];
    
    // Container to store advertising event data when passing from advertising
    // callback to app event. See the respective event in GapAdvScan_Event_IDs
    // in gap_advertiser.h for the type that pBuf should be cast to.
    typedef struct
    {
      uint32_t event;
      void *pBuf;
    } sbGapAdvEventData_t;
    
    // Advertising handles
    static uint8 advHandleLegacy;
    
    // Address mode
    static GAP_Addr_Modes_t addrMode = DEFAULT_ADDRESS_MODE;
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    
    static void     SimpleBroadcaster_init(void);
    static void     SimpleBroadcaster_taskFxn(UArg a0, UArg a1);
    
    static void     SimpleBroadcaster_processStackMsg(ICall_Hdr *pMsg);
    static void     SimpleBroadcaster_processGapMessage(gapEventHdr_t *pMsg);
    static void     SimpleBroadcaster_processAppMsg(sbEvt_t *pMsg);
    static void     SimpleBroadcaster_advCallback(uint32_t event, void *pBuf, uintptr_t arg);
    static bool     SimpleBroadcaster_processAdvEvent(sbGapAdvEventData_t *pEventData);
    static status_t SimpleBroadcaster_enqueueMsg(uint8_t event, void *pData);
    
    /*********************************************************************
     * PROFILE CALLBACKS
     */
    
    // GAP Role Callbacks
    /*
    static gapRolesCBs_t simpleBroadcaster_BroadcasterCBs =
    {
      SimpleBroadcaster_stateChangeCB   // Profile State Change Callbacks
    };
    */
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    
    /*********************************************************************
     * @fn      SimpleBroadcaster_createTask
     *
     * @brief   Task creation function for the Simple Broadcaster.
     *
     * @param   none
     *
     * @return  none
     */
    void SimpleBroadcaster_createTask(void)
    {
      Task_Params taskParams;
    
      // Configure task
      Task_Params_init(&taskParams);
      taskParams.stack = sbTaskStack;
      taskParams.stackSize = SB_TASK_STACK_SIZE;
      taskParams.priority = SB_TASK_PRIORITY;
    
      Task_construct(&sbTask, SimpleBroadcaster_taskFxn, &taskParams, NULL);
    }
    
    /*********************************************************************
     * @fn      SimpleBroadcaster_init
     *
     * @brief   Initialization function for the Simple Broadcaster App
     *          Task. This is called during initialization and should contain
     *          any application specific initialization (ie. hardware
     *          initialization/setup, table initialization, power up
     *          notification ...).
     *
     * @param   none
     *
     * @return  none
     */
    static void SimpleBroadcaster_init(void)
    {
    	// ******************************************************************
      // N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp
      // ******************************************************************
      // Register the current thread as an ICall dispatcher application
      // so that the application can send and receive messages.
      ICall_registerApp(&selfEntity, &syncEvent);
    
    #ifdef USE_RCOSC
      // Set device's Sleep Clock Accuracy
    #if ( HOST_CONFIG & ( CENTRAL_CFG | PERIPHERAL_CFG ) )
      HCI_EXT_SetSCACmd(500);
    #endif // (CENTRAL_CFG | PERIPHERAL_CFG)
      RCOSC_enableCalibration();
    #endif // USE_RCOSC
    
      // Create an RTOS queue for message from profile to be sent to app.
      appMsgQueueHandle = Util_constructQueue(&appMsgQueue);
    
      // Open LCD
      dispHandle = Display_open(Display_Type_ANY, NULL);
    
      // Register with GAP for HCI/Host messages. This is needed to receive HCI
      // events. For more information, see the HCI section in the User's Guide:
      // http://software-dl.ti.com/lprf/ble5stack-latest/
      GAP_RegisterForMsgs(selfEntity);
    
      //Initialize GAP layer for Peripheral role and register to receive GAP events
      GAP_DeviceInit(GAP_PROFILE_BROADCASTER, selfEntity, addrMode, &pRandomAddress);
    
      Display_printf(dispHandle, 0, 0, "BLE Broadcaster");
    }
    
    /*********************************************************************
     * @fn      SimpleBroadcaster_processEvent
     *
     * @brief   Application task entry point for the Simple Broadcaster.
     *
     * @param   none
     *
     * @return  none
     */
    static void SimpleBroadcaster_taskFxn(UArg a0, UArg a1)
    {
      // Initialize application
      SimpleBroadcaster_init();
    
      // Application main loop
      for (;;)
      {
        // Get the ticks since startup
        uint32_t tickStart = Clock_getTicks();
    
        uint32_t events;
    
        events = Event_pend(syncEvent, Event_Id_NONE, SB_ALL_EVENTS,
                            ICALL_TIMEOUT_FOREVER);
    
        if (events)
        {
          ICall_EntityID dest;
          ICall_ServiceEnum src;
          ICall_HciExtEvt *pMsg = NULL;
    
          if (ICall_fetchServiceMsg(&src, &dest,
                                    (void **)&pMsg) == ICALL_ERRNO_SUCCESS)
          {
            if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity))
            {
              // Process inter-task message
              SimpleBroadcaster_processStackMsg((ICall_Hdr *)pMsg);
            }
    
            if (pMsg)
            {
              ICall_freeMsg(pMsg);
            }
          }
    
          // If RTOS queue is not empty, process app message.
          if (events & SB_QUEUE_EVT)
          {
            while (!Queue_empty(appMsgQueueHandle))
            {
              sbEvt_t *pMsg = (sbEvt_t *)Util_dequeueMsg(appMsgQueueHandle);
              if (pMsg)
              {
                // Process message.
                SimpleBroadcaster_processAppMsg(pMsg);
    
                // Free the space from the message.
                ICall_free(pMsg);
              }
            }
          }
        }
      }
    }
    
    /*********************************************************************
     * @fn      SimpleBroadcaster_processStackMsg
     *
     * @brief   Process an incoming stack message.
     *
     * @param   pMsg - message to process
     *
     * @return  none
     */
    static void SimpleBroadcaster_processStackMsg(ICall_Hdr *pMsg)
    {
      switch (pMsg->event)
      {
        case GAP_MSG_EVENT:
          SimpleBroadcaster_processGapMessage((gapEventHdr_t*) pMsg);
          break;
    
        default:
          // do nothing
          break;
      }
    }
    
    /*********************************************************************
     * @fn      SimpleBroadcaster_processGapMessage
     *
     * @brief   Process an incoming GAP event.
     *
     * @param   pMsg - message to process
     */
    static void SimpleBroadcaster_processGapMessage(gapEventHdr_t *pMsg)
    {
      switch(pMsg->opcode)
      {
        case GAP_DEVICE_INIT_DONE_EVENT:
        {
          bStatus_t status = FAILURE;
    
          gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg;
    
          if(pPkt->hdr.status == SUCCESS)
          {
            // Store the system ID
            uint8_t systemId[DEVINFO_SYSTEM_ID_LEN];
    
            // use 6 bytes of device address for 8 bytes of system ID value
            systemId[0] = pPkt->devAddr[0];
            systemId[1] = pPkt->devAddr[1];
            systemId[2] = pPkt->devAddr[2];
    
            // set middle bytes to zero
            systemId[4] = 0x00;
            systemId[3] = 0x00;
    
            // shift three bytes up
            systemId[7] = pPkt->devAddr[5];
            systemId[6] = pPkt->devAddr[4];
            systemId[5] = pPkt->devAddr[3];
    
            // Set Device Info Service Parameter
            DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId);
    
            // Display device address
            Display_printf(dispHandle, 1, 0, "%s Addr: %s",
                           (addrMode <= ADDRMODE_RANDOM) ? "Dev" : "ID",
                           Util_convertBdAddr2Str(pPkt->devAddr));
            Display_printf(dispHandle, 2, 0, "Initialized");
    
            if (addrMode > ADDRMODE_RANDOM)
            {
              // Display the RPA.
              Display_printf(dispHandle, 3, 0, "RP Addr: %s",
                             Util_convertBdAddr2Str(GAP_GetDevAddress(FALSE)));
            }
    
            // Setup and start Advertising
            // For more information, see the GAP section in the User's Guide:
            // http://software-dl.ti.com/lprf/ble5stack-latest/
    
            #ifndef BEACON_FEATURE
              advParams1.eventProps = GAP_ADV_PROP_SCANNABLE | GAP_ADV_PROP_LEGACY;
            #else
              advParams1.eventProps = GAP_ADV_PROP_LEGACY;
            #endif // !BEACON_FEATURE
    
            // Create Advertisement set
            status = GapAdv_create(&SimpleBroadcaster_advCallback, &advParams1,
                                   &advHandleLegacy);
            SIMPLEBROADCASTER_ASSERT(status == SUCCESS);
    
            // Load advertising data
            status = GapAdv_loadByHandle(advHandleLegacy, GAP_ADV_DATA_TYPE_ADV,
                                         sizeof(advData1), advData1);
            SIMPLEBROADCASTER_ASSERT(status == SUCCESS);
    
            // Load scan response data
            status = GapAdv_loadByHandle(advHandleLegacy, GAP_ADV_DATA_TYPE_SCAN_RSP,
                                         sizeof(scanResData1), scanResData1);
            SIMPLEBROADCASTER_ASSERT(status == SUCCESS);
    
            // Set event mask
            status = GapAdv_setEventMask(advHandleLegacy,
                                         GAP_ADV_EVT_MASK_START_AFTER_ENABLE | GAP_ADV_EVT_MASK_END|
                                         GAP_ADV_EVT_MASK_END_AFTER_DISABLE |
                                         GAP_ADV_EVT_MASK_SET_TERMINATED);
            SIMPLEBROADCASTER_ASSERT(status == SUCCESS);
    
            // Enable legacy advertising
            status = GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
            SIMPLEBROADCASTER_ASSERT(status == SUCCESS);
          }
    
          break;
        }
    
        default:
          Display_clearLine(dispHandle, 2);
          break;
      }
    }
    
    /*********************************************************************
     * @fn      SimpleBroadcaster_enqueueMsg
     *
     * @brief   Creates a message and puts the message in RTOS queue.
     *
     * @param   event - message event.
     * @param   state - message state.
     */
    static status_t SimpleBroadcaster_enqueueMsg(uint8_t event, void *pData)
    {
      uint8_t success;
      sbEvt_t *pMsg = ICall_malloc(sizeof(sbEvt_t));
    
      // Create dynamic pointer to message.
      if(pMsg)
      {
        pMsg->event = event;
        pMsg->pData = pData;
    
        // Enqueue the message.
        success = Util_enqueueMsg(appMsgQueueHandle, syncEvent, (uint8_t *)pMsg);
        return (success) ? SUCCESS : FAILURE;
      }
    
      return(bleMemAllocError);
    }
    
    /*********************************************************************
     * @fn      SimpleBroadcaster_advCallback
     *
     * @brief   GapAdv module callback
     *
     * @param   pMsg - message to process
     */
    static void SimpleBroadcaster_advCallback(uint32_t event, void *pBuf, uintptr_t arg)
    {
      sbGapAdvEventData_t *pData = ICall_malloc(sizeof(sbGapAdvEventData_t));
    
      if (pData)
      {
        pData->event = event;
        pData->pBuf = pBuf;
    
        if(SimpleBroadcaster_enqueueMsg(SB_ADV_EVT, pData) != SUCCESS)
        {
          ICall_free(pData);
        }
      }
    }
    
    /*********************************************************************
     * @fn      SimpleBroadcaster_processAppMsg
     *
     * @brief   Process an incoming callback from a profile.
     *
     * @param   pMsg - message to process
     *
     * @return  None.
     */
    static void SimpleBroadcaster_processAppMsg(sbEvt_t *pMsg)
    {
      bool safeToDealloc = TRUE;
    
      switch (pMsg->event)
      {
        case SB_ADV_EVT:
          safeToDealloc = SimpleBroadcaster_processAdvEvent((sbGapAdvEventData_t*)(pMsg->pData));
          break;
    
        default:
          // Do nothing.
          break;
      }
    
      if (safeToDealloc)
      {
        // Free message data
        if (pMsg->pData)
        {
          ICall_free(pMsg->pData);
        }
      }
    }
    
    /*********************************************************************
     * @fn      SimpleBroadcaster_processAdvEvent
     *
     * @brief   Process advertising event in app context
     *
     * @param   pEventData
     */
    static bool SimpleBroadcaster_processAdvEvent(sbGapAdvEventData_t *pEventData)
    {
      bool safeToDealloc = TRUE;
    
      static volatile uint8_t test;
    
      switch (pEventData->event)
      {
        case GAP_EVT_ADV_START_AFTER_ENABLE:
          Display_printf(dispHandle, 2, 0, "Advertising");
          break;
    
        case GAP_EVT_INSUFFICIENT_MEMORY:
          safeToDealloc = FALSE;
          break;
        case GAP_EVT_ADV_END:
          test++;
          break;
        default:
          // Do nothing.
          break;
      }
    
      return(safeToDealloc);
    }
    
    /*********************************************************************
    *********************************************************************/
    

  • 我这边测试到了跟你一样的现象,感谢你提供的详细信息。我需要跟美国那边的开发team沟通一下,有消息会来回复
  • 好的 ,如果有结果请尽快告知一下,项目比较着急,非常感谢!
  • 已经定位到问题,这是由于pEventData的内存没有释放导致的,请按照如下代码修改:

    static bool SimpleBroadcaster_processAdvEvent(sbGapAdvEventData_t *pEventData)
    {
            bool safeToDealloc = TRUE;
    
            static volatile uint8_t test;
    
           switch (pEventData->event)
           {
                     case GAP_EVT_ADV_START_AFTER_ENABLE:
                                   Display_printf(dispHandle, 2, 0, "Advertising");
                                   break;
    
                     case GAP_EVT_INSUFFICIENT_MEMORY:
                                  safeToDealloc = FALSE;
                                  break;
    
    
                     case GAP_EVT_ADV_END:
                                 test++;
                                 ICall_free(pEventData->pBuf); // fixed memory leak
                                 break;
    
    
                    default:
                             // Do nothing.
                                break;
           }
    
           return(safeToDealloc);
    }

  • 我这边测试发现,使用有限广播方式,一次广播开启6次广播事件,即GapAdv_enable(advHandleLegacy,  GAP_ADV_ENABLE_OPTIONS_USE_MAX_EVENTS , 6),保留原始回调事件设置,即

    GapAdv_setEventMask(advHandleLegacy,
                      GAP_ADV_EVT_MASK_START_AFTER_ENABLE | 
                      GAP_ADV_EVT_MASK_END_AFTER_DISABLE |
                      GAP_ADV_EVT_MASK_SET_TERMINATED);

    也同样的会有内存泄漏的问题,每次回调少8个字节,请问是否也采用同样的方法来处理?

  • 是的,释放相应的内存即可
  • 请问GAP_EVT_INSUFFICIENT_MEMORY事件回调也同样需要释放一次内存吗
  • 你好 我这边测试发现 ,对于有限关播发送,对于 GapAdv_setEventMask开启的回调事件都需要进行一次内存释放,无限广播方式因为只是需要开启一次广播,固该问题没有显现。目前的问题是我这边测试不到GAP_EVT_INSUFFICIENT_MEMORY事件发生,想确认下是否该事件是否也需要释放一次内存?
  • GAP_EVT_INSUFFICIENT_MEMORY发生时,内存并未成功分配,因此不需要再释放