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.

CC2652RB: Issue getting Simple_Peripheral notifications working on Charactertistic 5 with increased size (64 bytes)

Part Number: CC2652RB

I am working with the CC2652 using the simple_peripheral example and I have modified it to allow the characteristic 5 to have notifications and also increased the size of the payload to 64 bytes. This all seems to work, I can call readCharacteristic5 on my phone app size and see data, but I cannot read it fast enough so I subscribed to characteristic5, get a true, but once my CC2652 tries to send out data it crashes and quits broadcasting ble altogether (no longer see it in the ble devices available list on my phone app).

I did try the newer simple_peripheral_gatt_builder_preview but it had an issue where it only allows len == sizeof(uint8)) when I call SimpleProfile_SetParameter(). So I made all the changes I wanted in this project then made sure my original simple_peripheral project has the same changes and still didn't fix my issue.

I'm gathering data from a UART in emstat_pico.c and once I detect a linefeed I sent the message to UpdateBleBuffer(uartBuffer) which calls SimpleProfile_SetParameter().

  • // UART Code from emStat_Pico.c
    void uart_rx_handler(UART_Handle u, void *buf, size_t count) {
        GPIO_toggle(R_LED);
        char temp = (((char*)buf)[0]);
        if(uartRXLocation < BUFFERSIZE) {
            uartBuffer[uartRXLocation++] = temp;
        }
        else {
            uartRXLocation = 0;
        }
    
        if(temp == 0x0A) {
            UpdateBleBuffer(uartBuffer);
            memset(uartBuffer, 0x00, BUFFERSIZE);
            uart_control.rx_done = 1;
            uartRXLocation = 0;
        }
        UART_read(u,buf,1);
    }
    //*******************************************************************
    
    
    // function in simple_peripheral.c to pass data between UART and BLE
    bool UpdateBleBuffer(void *data)
    {
        SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR5, SIMPLEPROFILE_CHAR5_LEN, data);
    
        return true;
    }
    //*******************************************************************
    
    
    // Code from simple_gatt_profile.c
    // Simple Profile Characteristic 5 Properties
    static uint8 simpleProfileChar5Props = GATT_PROP_NOTIFY|GATT_PROP_READ;
    
    // Characteristic 5 Value
    static uint8 simpleProfileChar5[SIMPLEPROFILE_CHAR5_LEN] = {0};
    
    // Simple Profile Characteristic 5 User Description
    static uint8 simpleProfileChar5UserDesp[17] = "Characteristic 5";
    // Characteristic "Char5" CCCD
    static gattCharCfg_t *simpleProfileChar5Config;
    
    // Characteristic 5 Declaration
        {
          { ATT_BT_UUID_SIZE, characterUUID },
          GATT_PERMIT_READ,
          0,
          &simpleProfileChar5Props
        },
    
          // Characteristic Value 5
          {
            { ATT_BT_UUID_SIZE, simpleProfilechar5UUID },
            GATT_PERMIT_READ,
            0,
            simpleProfileChar5
          },
    
          // Characteristic 5 User Description
          {
            { ATT_BT_UUID_SIZE, charUserDescUUID },
            GATT_PERMIT_READ,
            0,
            simpleProfileChar5UserDesp
          },
    
          // Char5 configuration
          {
            { ATT_BT_UUID_SIZE, clientCharCfgUUID },
            GATT_PERMIT_READ | GATT_PERMIT_WRITE,
            0,
            (uint8 *)&simpleProfileChar5Config
          },
          
    // Allocate Client Characteristic Configuration table
      simpleProfileChar5Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *
                                                                MAX_NUM_BLE_CONNS );
    
      if ( simpleProfileChar5Config == NULL )
      {
        return ( bleMemAllocError );
      }
    
      // Initialize Client Characteristic Configuration attributes
      GATTServApp_InitCharCfg( LINKDB_CONNHANDLE_INVALID, simpleProfileChar5Config );
    
      if ( services & SIMPLEPROFILE_SERVICE )
      {
        // Register GATT attribute list and CBs with GATT Server App
        status = GATTServApp_RegisterService( simpleProfileAttrTbl,
                                              GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                              GATT_MAX_ENCRYPT_KEY_SIZE,
                                              &simpleProfileCBs );
      }
    
    bStatus_t SimpleProfile_SetParameter( uint8 param, uint8 len, void *value )
    {
      bStatus_t ret = SUCCESS;
      switch ( param )
      {
        case SIMPLEPROFILE_CHAR1:
          if ( len == sizeof ( uint8 ) )
          {
            simpleProfileChar1 = *((uint8*)value);
          }
          else
          {
            ret = bleInvalidRange;
          }
          break;
    
        case SIMPLEPROFILE_CHAR2:
          if ( len == sizeof ( uint8 ) )
          {
            simpleProfileChar2 = *((uint8*)value);
          }
          else
          {
            ret = bleInvalidRange;
          }
          break;
    
        case SIMPLEPROFILE_CHAR3:
          if ( len == sizeof ( uint8 ) )
          {
            simpleProfileChar3 = *((uint8*)value);
          }
          else
          {
            ret = bleInvalidRange;
          }
          break;
    
        case SIMPLEPROFILE_CHAR4:
          if ( len == sizeof ( uint8 ) )
          {
            simpleProfileChar4 = *((uint8*)value);
    
            // See if Notification has been enabled
            GATTServApp_ProcessCharCfg( simpleProfileChar4Config, &simpleProfileChar4, FALSE,
                                        simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                        INVALID_TASK_ID, simpleProfile_ReadAttrCB );
          }
          else
          {
            ret = bleInvalidRange;
          }
          break;
    
        case SIMPLEPROFILE_CHAR5:
          if ( len == SIMPLEPROFILE_CHAR5_LEN )
          {
            VOID memcpy( simpleProfileChar5, value, SIMPLEPROFILE_CHAR5_LEN );
    
            // Try to send notification.
            GATTServApp_ProcessCharCfg( simpleProfileChar5Config, simpleProfileChar5, FALSE,
                                    simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                    INVALID_TASK_ID, simpleProfile_ReadAttrCB);
          }
          else
          {
            ret = bleInvalidRange;
          }
          break;
    
        default:
          ret = INVALIDPARAMETER;
          break;
      }
    
      return ( ret );
    }

  • Adding some more observation, I put my device in debug mode, connected my app and set notifications to true on Characteristic 5 and requested data (sent a command then causes my UART to sent data out) and it crashed (app disconnected and device no longer shows up on BLE list). On CCS I paused and found I was stuck here:

    Call_Errno
    ICall_abort(void)
    {
    #ifdef HALNODEBUG
    #elif  defined(EXT_HAL_ASSERT)
      HAL_ASSERT(HAL_ASSERT_CAUSE_ICALL_ABORT);
    #else
      {
        volatile uint8_t j=1;
        while(j);
      }
    #endif /* EXT_HAL_ASSERT */
      ICALL_HOOK_ABORT_FUNC();
      return(ICALL_ERRNO_SUCCESS);
    }

  • Hi Matthew,

    I would suggest you to identify the function throwing out the error. Using some breakpoints, you should manage to do this :)

    Best regards,

  • I've tracked it down to where I'm calling UpdateBleBuffer(uartBuffer); which then calls SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR5, SIMPLEPROFILE_CHAR5_LEN, data);

    The code works if all I'm doing is trying to readCharacteristics from my phone, but doesn't work when I set notifications. It seems to be a similar issue as this post, but I'm new to the RTOS CC2652 so not exactly sure how to fix it.

    e2e.ti.com/.../cc2640-abort-icall-encountered

  • So stepping through the code SimpleProfile_setParameter() gets to SIMPLEPROFILE_CHAR5 which I've setup notifications so it calls GATTServApp_ProcessCharCfg() which then finds it way to gattServApp_sendNotiInd() which makes it to status = GATT_Notifcation which finally makes it here and calls ICall_abort() due to threadtype == BIOS_ThreadType_Hwi:

    uint32_t icall_directAPI( uint8_t service , icall_lite_id_t id, ... )
    {
      va_list argp;
      uint32_t res;
      icallLiteMsg_t liteMsg;
      // The following will push all parameter in the runtime stack.
      // This need to be call before any other local declaration of variable....
      va_start(argp, id);
      // Test that the API is not called in a Hwi or Swi context
      {
        BIOS_ThreadType threadtype = BIOS_getThreadType();
        if (threadtype == BIOS_ThreadType_Hwi ||
            threadtype == BIOS_ThreadType_Swi)
        {
    #ifdef HALNODEBUG
    #else /* ! HALNODEBUG */
          ICall_abort();
    #endif /* HALNODEBUG */
        }
      }

    My question is this because of the way I'm calling SimpleProfile_setParameter() from inside a UART_RX interrupt handler? If so what is the proper way to do this? I've been trying to figure out how to setup ICall from within my UART Task which I did set that up, but not sure how to do this at this time.

  • Hi,

    You may want to review our debugging guide.

    Generally speaking this is not good practice to execute a lot of code in an HWI context. I would rather suggest to post an event in the HWI contect and then call SimpleProfile_setParameter() in a task context.

    In addition to that, make sure all the tasks accessing ICall are ICall enabled.

    Regards,

  • Okay, so I added  ICall_registerApp(&selfEntity, &syncEvent); to my UART task and I call  Event_post(syncEvent, selfEntity); within my uart_rx_handler after I receive a full message, and then the events = Event_pend(syncEvent, Event_Id_NONE, SP_ALL_EVENTS, ICALL_TIMEOUT_FOREVER); inside my main application loop. But now I have few problems. I'm trying to follow the documentation to update Max Number of ICall Enabled Tasks in syscfg to 4 (default was 3) and then update OSAL_MAX_NUM_PROXY_TASKS in osal.c inside ble5stack, but it was already at 4 and changing it to 5 causing iCall to abort upon program execution. To be honest the documentation is not very clear and scattered when I'm trying to learn TIRTOS and BLE at the same time. So should OSAL_MAX_NUM_PROXY_TASK be the same as what is in syscfg because they didn't match to begin with? Do I have to build ble5stack after changing the value or is it built when I build simple_peripheral project? Should I even be calling an Event_pend within my UART code or try to send a Event_pend on the BLE task?

  • Faceplam, it would help if I had the right syscfg open...too many projects. Though it does seem like what I change in syscfg doens't reflect ICAL_MAX_NUM_TASKS in icall.c.

  • Okay, I managed to get it working, and by working I can now send 64 byte packets out over Characteristic 5 with notifications set in my phone App and it updates automatically. Sure enough ICALL_Abort was getting called because I was calling SimplePeripheral_SetParameters inside a HWI. That wasn't my final plan as I did want to get semaphores or icall working, but I'm trying to learn too many things at once. I did end up changing syscfg "Max Number of ICalll Enables Tasks" to 4 in BLE, then I also changed ICALL_MAX_NUM_TASKS to 4 in icall.c and finally OSAL_MAX_NUM_PROXY_TASKS to 4 (which I think it was by default anyway before I messed with it). Then my issue was when I called Event_post() I didn't realized I needed to send "SP_ALL_EVENTS" as the eventMask. Once I did that everything started working. Wow....what a ride. I'm tired now.

  • Hi Matthew,

    Well done... you probably deserve (at least) one coffee now Coffee I am sure this exercise was a good investment for you.

    Best regards,