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.

RTOS/CC2650EM-5XD-RD: ADC conversions impacts Ble connection and visibility of device

Part Number: CC2650EM-5XD-RD
Other Parts Discussed in Thread: CC2650

Tool/software: TI-RTOS

Hi all,

When I use ADC Continuous Conversion by some reason my Phone lose connection with board.

Below the sample of the code how I use ADC Continuous Conversion:

  // Initialize ADC Converter
  ADCBuf_Params adcBufParams;
  ADCBuf_Params_init(&adcBufParams);
  adcBufParams.callbackFxn = App_ADCBufCallback;
  adcBufParams.recurrenceMode = ADCBuf_RECURRENCE_MODE_CONTINUOUS;
  adcBufParams.returnMode = ADCBuf_RETURN_MODE_CALLBACK;
  adcBufParams.samplingFrequency = 10;
  sockCurrAdcBufHandle = ADCBuf_open(Board_ADCBuf0, &adcBufParams);
  if (!sockCurrAdcBufHandle) {
      Log_error0("Error initializing board ADC pins !!");
      Task_exit();
  }

  ADCBuf_Conversion continuousConversion;
  continuousConversion.arg = NULL;
  continuousConversion.adcChannel = Board_ADCBufChannel0;
  continuousConversion.sampleBuffer = sampleBufferOne;
  continuousConversion.sampleBufferTwo = sampleBufferTwo;
  continuousConversion.samplesRequestedCount = ADCBUFFERSIZE;
  if (ADCBuf_convert(sockCurrAdcBufHandle, &continuousConversion, 1) != ADCBuf_STATUS_SUCCESS) {
      Log_error0("Did not start conversion process correctly !!");
      Task_exit();
  }


  void App_ADCBufCallback(ADCBuf_Handle handle,
                          ADCBuf_Conversion *conversion,
                          void *completedADCBuffer,
                          uint32_t completedChannel) {
  if (conversion == NULL) {
    return;
  }
  if (completedADCBuffer == NULL) {
    return;
  }
  /* Adjust raw adc values and convert them to microvolts */
  ADCBuf_adjustRawValues(handle,
                         completedADCBuffer,
                         ADCBUFFERSIZE,
                         completedChannel);
  ADCBuf_convertAdjustedToMicroVolts(handle,
                                     completedChannel,
                                     completedADCBuffer,
                                     microVoltBuffer,
                                     ADCBUFFERSIZE);
}

And if I use continuous mode Ble Device disappear, but it steal works, it does not crash

Maybe I need to handle ADC Conversion with Ble Stack in some special way ?

  • Hi Denis,
    Where do you run this code? (In SDK/sample app context)
  • Hi Denis,

    Are you using the EM + SmartRF06 board, or a custom board? If custom board, please see the HW Bringup and Design Considerations, found on the FAQ (last link) e2e.ti.com/.../770223

    It sounds like you either have an issue with the power supply / decoupling that could degrade the RF performance, or perhaps your interrupt handling/reading out of the ADC measurements takes too much time, so that the BLE task isn't able to run in time.

    I think ideally you'd want to run ADC conversion when the BLE stack is not using the radio. I'm just a software guy myself, but it sounds probable that the current draw during an RF event could also influence the ADC measurements.

    I can't see that you mention which SDK or project you are using, but simple_peripheral has some example code showing how to get notified when a connection event is done. At this point you should have some milliseconds to do a conversion before the next connection event happens.

    Best regards,
    Aslak
  • Hi J Lindh,

    All this code I run in application context

  • Thanks Aslak N. ,

    I am using custom board and this issue with visibility is observed only when I use ADC conversion.
    Seems like you are right regarding the time taken by conversion, it took too long ...
    I have not found simple_peripheral with some example code showing how to get notified when a connection event is done ?
    Can you share a link or snippet of code ?
  • Sometimes when in debug mode I stop the debugging it stopped at:

    /*!
     *  @brief  HWI ISR of the ADC triggered when the DMA transaction is complete
     *
     *  @param  arg         An ADCBufCC26XX_Handle
     *
     */
    static void ADCBufCC26XX_hwiFxn (UArg arg) {
        ADCBufCC26XX_Object            *object;
        ADCBufCC26XX_HWAttrs const     *hwAttrs;
        uint32_t                        intStatus;
    
        /* Get the pointer to the object and hwAttrs */
        object = ((ADCBuf_Handle)arg)->object;
        hwAttrs = ((ADCBuf_Handle)arg)->hwAttrs;
    
        if (object->recurrenceMode == ADCBuf_RECURRENCE_MODE_ONE_SHOT) {
            /* Disable the ADC */
            AUXADCDisable();
            /* Disable ADC DMA if we are only doing one conversion and clear DMA done interrupt. */
            HWREG(AUX_EVCTL_BASE + AUX_EVCTL_O_DMACTL) = AUX_EVCTL_DMACTL_REQ_MODE_SINGLE | AUX_EVCTL_DMACTL_SEL_FIFO_NOT_EMPTY ;
        }
        UDMACC26XX_clearInterrupt(object->udmaHandle, (1 << UDMA_CHAN_AUX_ADC) | (hwAttrs->gptDMAChannelMask));
    
        /* Get the status of the ADC_IRQ line and ADC_DONE */
        intStatus = HWREG(AUX_EVCTL_BASE + AUX_EVCTL_O_EVTOMCUFLAGS) & (AUX_EVCTL_EVTOMCUFLAGS_ADC_IRQ | AUX_EVCTL_EVTOMCUFLAGS_ADC_DONE);
        /* Clear the ADC_IRQ flag if it triggered the ISR */
        HWREG(AUX_EVCTL_BASE + AUX_EVCTL_O_EVTOMCUFLAGSCLR) = intStatus;
    
        /* Post SWI to handle remaining clean up and invocation of callback */
        Swi_post(Swi_handle(&(object->swi)));
    }

    Seems like chip is not hang up, but it is not visible ...

  • Hi,

    Sorry, I missed your question. Simple_peripheral should have an event called SBP_CONN_EVT_END_EVT, which is enabled via the command HCI_EXT_ConnEventNoticeCmd(connHandle, selfEntity, SBP_CONN_EVT_END_EVT); and it will generate an event from the stack to your task every time a connection event is finished. This is used by the 'resend' mechanism, but you can enable it when connecting if you wish, and comment out the part where it's disabled.

    Best regards,
    Aslak
  • Thanks,

    It is very helpful, but how can I check when connection started ?

    Okay, I can check if connection event finished, but how to check if it is started ? connection started ?

    I want to implement something like the following:

    // Make ADC conversion

    // Connection is started

    // Block ADC conversion

    ...

    // Connection is finished

    // Unblock ADC conversion

    // Make ADC conversion

    I have the following events in peripheral application:

    #define PRZ_STATE_CHANGE_EVT                  0x0001
    #define PRZ_CHAR_CHANGE_EVT 0x0002
    #define PRZ_PERIODIC_EVT 0x0004
    #define PRZ_CONN_EVT_END_EVT 0x0008

    But SBP_CONN_EVT_END_EVT helpful only when connection finished, but I do not know when it started ?!
  • Hi,

    Sorry for the delay due to holidays.

    On the CC2650 there is no API/callback that tells you when it's started. For CC2640R2 the SDK has an extended event complete callback that gives you the time to next event start.

    In your case however you can depend on connection event end happening with some delay after it's actually done, and assume that the next connection starts at connection-interval minus a couple of miliseconds (or more - this includes the conn-end jitter and also the time that was spent on-air) from the time you get the event.

    Best regards,
    Aslak
  • Thanks you for response

    Okay, even if I cannot check when event started, but I do not receive PRZ_CONN_EVT_END_EVT ...
    And there is paradox: I cannot receive PRZ_CONN_EVT_END_EVT, because I have not subscribed to it and I have not subscribed to it, because I do not have gattMsgEvent_t -> I do not have gattMsgEvent_t, because I have not received any messages from ICall ... seems like I am in loop ))

    Can you suggest how to use properly PRZ_CONN_EVT_END_EVT I initialization function of my task ?
  • Hi Denis,

    That's not a nice loop to be in. I'm not sure what you mean however, surely you must receive _some_ messages to the application task from the stack (via icall) otherwise how are you even in a connection? Please help me understand what you are doing and trying and I'll see how I can help you.

    Best regards,
    Aslak
  • @Aslak N.

    Hi Aslak,

    I have the following code:

    static void Staff_taskFxn(UArg a0, UArg a1)
    {
      // Initialize application
      Staff_init();
    
      // Application main loop
      for (;;)
      {
        // Waits for a signal to the semaphore associated with the calling thread.
        // Note that the semaphore associated with a thread is signaled when a
        // message is queued to the message receive queue of the thread or when
        // ICall_signal() function is called onto the semaphore.
        ICall_Errno errno = ICall_wait(ICALL_TIMEOUT_FOREVER);
    
        if (errno == ICALL_ERRNO_SUCCESS)
        {
          ICall_EntityID dest;
          ICall_ServiceEnum src;
          ICall_HciExtEvt *pMsg = NULL;
    
          // Check if we got a signal because of a stack message
          if (ICall_fetchServiceMsg(&src, &dest,
                                    (void **)&pMsg) == ICALL_ERRNO_SUCCESS)
          {
            uint8 safeToDealloc = TRUE;
    
            if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity))
            {
              ICall_Stack_Event *pEvt = (ICall_Stack_Event *)pMsg;
    
              // Check for event flags received (event signature 0xffff)
              if (pEvt->signature == 0xffff)
              {
                // Event received when a connection event is completed
                if (pEvt->event_flag & PRZ_CONN_EVT_END_EVT)
                {
                  // Try to retransmit pending ATT Response (if any)
                  Staff_sendAttRsp();
                }
              }
              else // It's a message from the stack and not an event.
              {
                // Process inter-task message
                safeToDealloc = Staff_processStackMsg((ICall_Hdr *)pMsg);
              }
            }
    
            if (pMsg && safeToDealloc)
            {
              ICall_freeMsg(pMsg);
            }
          }
    
          // Process messages sent from another task or another context.
          while (!Queue_empty(hApplicationMsgQ))
          {
            app_msg_t *pMsg = Queue_dequeue(hApplicationMsgQ);
    
            // Process application-layer message probably sent from ourselves.
            User_processApplicationMessage(pMsg);
    
            // Free the received message.
            ICall_free(pMsg);
          }
        }
      }
    }

    Which I reworked from ProjectZero. And I've never received PRZ_CONN_EVT_END_EVT from the stack ...

    And I cannot figure out how to detect this event ... For subscribing for PRZ_CONN_EVT_END_EVT I need to use HCI_EXT_ConnEventNoticeCmd with connHandle

    Which handles in Staff_processGATTMsg:

    static uint8_t Staff_processGATTMsg(gattMsgEvent_t *pMsg)
    {
      // See if GATT server was unable to transmit an ATT response
      if (pMsg->hdr.status == blePending)
      {
        Log_warning1("Outgoing RF FIFO full. Re-schedule transmission of msg with opcode 0x%02x",
          pMsg->method);
    
        // No HCI buffer was available. Let's try to retransmit the response
        // on the next connection event.
        if (HCI_EXT_ConnEventNoticeCmd(pMsg->connHandle, selfEntity,
                                       PRZ_CONN_EVT_END_EVT) == SUCCESS)
        {
          // First free any pending response
          Staff_freeAttRsp(FAILURE);
    
          // Hold on to the response message for retransmission
          pAttRsp = pMsg;
    
          // Don't free the response message yet
          return (FALSE);
        }
      }
      else if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT)
      {
        // ATT request-response or indication-confirmation flow control is
        // violated. All subsequent ATT requests or indications will be dropped.
        // The app is informed in case it wants to drop the connection.
    
        // Log the opcode of the message that caused the violation.
        Log_error1("Flow control violated. Opcode of offending ATT msg: 0x%02x",
          pMsg->msg.flowCtrlEvt.opcode);
      }
      else if (pMsg->method == ATT_MTU_UPDATED_EVENT)
      {
        // MTU size updated
        Log_info1("MTU Size change: %d bytes", pMsg->msg.mtuEvt.MTU);
      }
      else
      {
        // Got an expected GATT message from a peer.
        Log_info1("Recevied GATT Message. Opcode: 0x%02x", pMsg->method);
      }
    
      // Free message payload. Needed only for ATT Protocol messages
      GATT_bm_free(&pMsg->msg, pMsg->method);
    
      // It's safe to free the incoming message
      return (TRUE);
    }

    But subscription it happens only if message pending ... And I have stuck ... (

  • Hi,

    I think I understand your confusion.

    It's true that Project Zero and also simple_peripheral call the register function HCI_EXT_ConnEventNoticeCmd(pMsg->connHandle, selfEntity, PRZ_CONN_EVT_END_EVT) when a response from the stack is pending.

    However, you can call this function yourself any time you please, for example in the switch case where you get notified that a connection is established.

    You don't have to disable the connection event notification immediately like the original code does, but you can keep it turned on.

    Really, the whole retransmit business isn't something you need unless you 1) stream data to the other side, and 2) the other side performs a GATT operation on your device at the same time, so that because you are streaming, there are no available buffers for the GATT response.

    Best regards,
    Aslak
  • @Aslak N.

    Hi Aslak,

    It is cool, but I actually cannot bypass this condition:

    // Check if we got a signal because of a stack message
    if (ICall_fetchServiceMsg(&src, &dest,
        (void **)&pMsg) == ICALL_ERRNO_SUCCESS)
    {
       // ...
    }

    in debug mode, I do not see that I receive any event from Stack ... But seems like I should receive ?!

    What do I do wrong ?

  • Hi Denis,

    Not sure what you mean "bypass". It's possible you can't set a breakpoint there due to optimization level, but if you connect to something you will get a stateChange callback (for example handled by SimplePeripheral_stateChangeCB which is registered in the SimplePeripheral_gapRoleCBs struct) that sends a message to the app about SBP_STATE_CHANGE_EVT which is handled in SimplePeripheral_processStateChangeEvt in the case GAPROLE_CONNECTED.

    Best regards,
    Aslak
  • Aslak N. (3522715)

    Hi Aslak,

    But it seems that it happens not due to optimization, seems like I do not receive messages from Stack:

    static void Staff_taskFxn(UArg a0, UArg a1)
    {
      // Initialize application
      Staff_init();
    
      // Application main loop
      for (;;)
      {
        // Waits for a signal to the semaphore associated with the calling thread.
        // Note that the semaphore associated with a thread is signaled when a
        // message is queued to the message receive queue of the thread or when
        // ICall_signal() function is called onto the semaphore.
        ICall_Errno errno = ICall_wait(ICALL_TIMEOUT_FOREVER);
    
        if (errno == ICALL_ERRNO_SUCCESS)
        {
          ICall_ServiceEnum srcService;
          ICall_EntityID srcEntity;
          ICall_EntityID dest;
          ICall_HciExtEvt *pMsg = NULL;
    
          ICall_Errno fetchSrcServiceResult = ICall_fetchServiceMsg(&srcService, &dest, (void **)&pMsg); // fetchSrcServiceResult is always equal ICALL_ERRNO_NOMSG
          ICall_Errno fetchSrcEntityResult = ICall_fetchMsg(&srcEntity, &dest, (void **)&pMsg);  // This was added for testing purposes, it also always ICALL_ERRNO_NOMSG, 'cause no application sends the message to me
          // Check if we got a signal because of a stack message
          if (fetchSrcServiceResult == ICALL_ERRNO_SUCCESS ||
              fetchSrcEntityResult == ICALL_ERRNO_SUCCESS)
          {
            // ...
          }
        }
      }
      // ...
    }

    As you can see it seems like in ICall there are some messages (because I passed ICall_wait call), but when I try to fetch them I got result = ICALL_ERRNO_NOMSG

    Seems like I am doing something wrong ...

    There are only messages for my application, seems like I should register somehow my ICall_EntityID on receiving messages from BLE Stack

    But how ?

  • Seems like I have found issue with my custom board, because ADC conversion works perfectly on CC2650 LAUNCH-BOARD in any mode: ONE_SHOT or CONTINIUS

    Thanks for support !!