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.

Clock (timer?) CC2640 UART monitoring

Other Parts Discussed in Thread: CC2640, CC2650

I am working on a CC2640 4x4 custom board, BLE stack 2.1, CCS 6.1, TI RTOS 2.13. The UART

is used for wired sensor calibration in read callback mode and write blocking, baud rate 9600 bps.

Once calibration is complete, the idea is to switch to BLE operation without the use of UART in

steady state.

UART activity will be checked once during SimpleBLEPeripheral initialization. I can

also set it up to be checked on the clock event, but I didn't have luck getting the clock to run at the

clock event either. I constructed a one shot clock, since the wait between starting this clock is

variable. I start the clock every time I monitor UART activity.

The UART is read one byte at a time in order to extract the message length from the incoming frame.

When the end of the message is reached, the read callback function puts the UART event in the RTOS

queue. After the UART message is processed, the task sleeps a while and checks for UART activity

again.

UART activity is monitored for a period of 20 bytes to account for any gap between the receive bytes

or lack of UART activity. After a time limit of 20 bytes, the wait for UART function does nothing if UART

activity is absent. I tried using a clock to time the UART monitoring. I am having trouble getting the

clock to run. Will a timer work better in this situation. If so, how do I set one up?

Can you also comment if this set up is BLE thread safe?

Thanks,

Priya

  • Please share the code you are using to create and start the clock object.

    Here is a working example of how to create and start a one-shot clock object that will go off after 10 Clock ticks:

    Clock_Handle myClock;
    Clock_Params prms;
    Clock_Params_init(&prms);

    prms.period = 0; /* Make this a oneshot Clock object */
    prms.startFlag = FALSE; /* Clock object is manually started */
    myClock = Clock_create(myHandler, 10, &prms, NULL); /* second argument is the oneshot timeout */

    Clock_start(myClock); /* myHandler will be called in 10 Clock ticks */

    Each time Clock_start(myClock) is invoked, the oneshot will be restarted.

    Alan
  • Alan,

    Thank you for your reply. I have pasted relevant sections of the code below. If you need to see all of the SimpleBLEPeripheral file, I am happy to email the zipped up project to you. I am not finding the UART_waitFlag being set and the uart_read does not happen either. The system directly goes into BLE events.  Without the use of a clock, I can get the UART read to trigger as seen on the scope, however, after connecting to the sensor, advertising stops.

    Thanks,

    Priya

    #define UART_READ_DELAY 3000   //time the task sleeps between consecutive UART messages

    #define UART_WAIT_TIME  1000

    #define UART_MSG_EVT         0x0010

    #define WAIT_FOR_TALK_MODE_EVT                0x0080

    In SimpleBLEPeripheral_init:

    Util_constructClock(&WaitForTalkModeClock, SimpleBLEPeripheral_clockHandler,

                             UART_WAIT_TIME, 0, false, WAIT_FOR_TALK_MODE_EVT);

    In SimpleBLEPeripheral_taskFxn:

        SOH = 0;
        if (events & WAIT_FOR_TALK_MODE_EVT) {
             events &= ~WAIT_FOR_TALK_MODE_EVT;

            waitForUARTMessage();
        }

    static void waitForUARTMessage(void)
    {
     uint8_t byte;

             Util_startClock(&WaitForTalkModeClock);

             UART_waitFlag = Util_isActive(&WaitForTalkModeClock);

             if (ValidUARTMsg)
                 Util_stopClock(&WaitForTalkModeClock);

             if ((SOH == 0) || ValidUARTMsg || UART_waitFlag)
                  UART_read(uart, &byte, 1);

             if (!ValidUARTMsg && !UART_waitFlag) {};

    }

    static void UARTCallback(UART_Handle uart, void *byte, size_t size)
    {
     static uint8_t byte0, prevByte, i, MessageLength, LenInfo82, LenInfo83;

        byte0 = *((int*)byte);

        if (ValidUARTMsg){
          uart_rx_buf[i] = byte0;

          if ((uart_rx_buf[1] == 0x82) && (i == LenInfo82-1)){
           MessageLength = uart_rx_buf[i] + 5;


          if ((uart_rx_buf[1] == 0x83) && (i == LenInfo83-1)){
              MessageLength = uart_rx_buf[i] + 5;


          if ((uart_rx_buf[1] != 0x82) && (uart_rx_buf[1] != 0x83)){
           MessageLength = 5;

          i++;

                if ((uart_rx_buf[1] == 0x82) && (i == LenInfo82)){
                 ValidUARTMsg = 0;
                 i = 0;
                 UART_enqueueMsg(MessageLength);
                }

                if ((uart_rx_buf[1] != 0x82) && (i == MessageLength) && (ValidUARTMsg == 1)){
                 ValidUARTMsg = 0;
                 i = 0;
                 UART_enqueueMsg(MessageLength);
                }

        }

     if ((prevByte == 1) && ((byte0 >= 0x80) && (byte0 <= 0x8f))){
      SOH = 1;
      uart_rx_buf[0] = prevByte;
      uart_rx_buf[1] = byte0;

      if (uart_rx_buf[1] == 0x82)
          LenInfo82 = 6;
      if (uart_rx_buf[1] == 0x83)
       LenInfo83 = 5;

         prevByte = 0;
            ValidUARTMsg = 1;
            i = 2;
     }


     prevByte = byte0;
    }

  • I posted the ROV of the clock module and the events in SimpleBLEPeruipheral. The UART readcallback event is 16 and you can see it complaining about this event. Can you help explain what the message on the clock ROV means? Should I be editing the appBLE.cfg to use the clock module? Please let me know what I should do to use the clock module.
    Thanks,
    Priya
  • You've opened the "Raw" view of the Clock module which displays much more information that the basic or module views. That text string is associated with an Assert that would be raised if you try to create or construct a Clock object when the BIOS.clockEnabled configuration parameter has been set to false.
  • By default, the BIOS.clockEnabled configuration parameter is set to 'true'.
    Unless you explicitly set it to 'false' in your .cfg file, the Clock module should be fully operational.
  • Alan,

    I have attached my appBLE.cfg script to this post. Can you review it and let me know if anything is missing? Here are some sections of it:

    BIOS.clockEnabled = true;

    /* 10 us tick period */
    Clock.tickPeriod = 10;
    TIRTOS.useSPI = true;
    Clock.tickSource = Clock.TickSource_TIMER;
    Clock.swiPriority = 5;

    Thank you,

    Priya

    4265.appBLE.cfg

  • The .cfg file looks OK to me.

    In your C code, I don't see the definition of the "WaitForTalkModeClock" object. Can you verify that it is a global variable and not a function-local variable?

    If I understand your code correctly, the timeout of the clock object is 1000 ticks. That translates to 10ms. But your comment says that you want to wait for 20 character times. At 9600 baud, each character takes around 1ms to transmit. So I'm thinking that timeout should be 2000 ticks. However, from your description of the problem, I think you're saying the clock function callback never gets called, not that it gets called too soon. Is that correct?

    Since you're using CCS and have become familiar with ROV views. Can you please confirm that the "ticks" value in the Clock module's "module" view is advancing between successive halts and runs of the CPU?

    Also can you confirm that the Hwi associated with the timer interrupt used to drive the Clock module is enabled? This can be verified by examining the detailed view within the Hwi module. IntNum 20 is the timer interrupt  number. The "status" column within the detailed view tells whether the interrupt is enabled or not. It also indicates whether it is currently pending or active. (See the second row in the screen capture below)

    Alan

  • 3007.simpleBLEPeripheral.cAlan,

    Yes, the timer interrupt 20 is enabled. I created a simplified version of the application that uses only the UART. Five formatted messages are sent to the uart receive, and I use a clock to read the UART. This version works fine (processes the UART messages) without the clock. I have been editing the state machine function that monitors the UART, but in all of my versions of code, there should not be a reason why the clock callback function never gets called.

    I was also thinking of a way to add a clock to the clean copy of SimpleBLEPeripheral, but there is no easy way to re-start the one shot clock. I also think this clock I added is interfering with the periodic clock in SimpleBLEPeripheral. I notice this when I try to connect to the sensor. That periodic clock is 5000 ticks and this UART wait clock is 2000 ticks, maybe this creates problems during a connection event. (SBP uses its periodic clock during the connection event).

    I have put the simplified version of the application to this post if you have the time to review it.

    I appreciate your time and help.

    Priya

  • Today, I went to the CC2650 DK, 4x4 package. Added a clock to the clean copy of SimpleBLEPeripheral. I am still unable to execute any break point inside the clock callback function. I tried this with and without the task_sleep at the UART_MSG_EVT with no difference.

    I have attached the copy of SimpleBLEPeripheral with the clock added to this post. I appreciate pointers on getting the clock module to work. 4331.simpleBLEPeripheral.c

    Thanks,

    Priya

  • The logic for starting the two clocks requires that the appropriate bit in the 'events' variable be set. However, I don't find any place in the code where 'events' is ever initialized with the required bits being set to true, except in the clock handler itself. Could it be that the clocks are never being started because 'events' never allows them to be?

    Also, I assumed the timeout arguments passed to Util_constructClock() were in Clock tick units (ie 10us units). However, the documentation for the clockDuration argument to Util_constructClock() says the units are in milliseconds. Consequently, setting the one-shot timeouts to 2000 and 5000 will yield actual timeouts of 2 seconds and 5 seconds respectively.

    Alan

  • Alan,
    I have this in lines 152 and 153:
    #define UART_MSG_EVT 0x0010
    #define WAIT_FOR_TALK_MODE_EVT 0x0020

    The WAIT_FOR_TALK_MODE_EVT I assume is being initialized by:
    Util_constructClock(&WaitForTalkModeClock, SimpleBLEPeripheral_clockHandler,
    UART_WAIT_TIME, 0, false, WAIT_FOR_TALK_MODE_EVT);
    in line 431.

    The UART_MSG_EVT goes into the RTOS queue when UART_enqueueMsg function is called:

    while (!Queue_empty(appMsgQueue))
    {
    sbpEvt_t *pMsg = (sbpEvt_t *)Util_dequeueMsg(appMsgQueue);
    if (pMsg)
    {
    // Process message.
    SimpleBLEPeripheral_processAppMsg(pMsg);

    // Free the space from the message.
    ICall_free(pMsg);
    }
    }

    Thanks,
    Priya
  • Alan,
    About the one shot timeouts, I have the appBLE.cfg clock ticks parameter set to 10 microseconds.
    Any chance this set up can be re-created with a 2650 DK at your end?
    Thanks,
    Priya
  • As you can see in the implementation of Util_constructClock() below, the clockDuration and clockPeriod arguments are translated from millisecond units into Clock.tickPeriod units:

    Clock_Handle Util_constructClock(Clock_Struct *pClock,
    Clock_FuncPtr clockCB,
    uint32_t clockDuration,
    uint32_t clockPeriod,
    uint8_t startFlag,
    UArg arg)
    {
    Clock_Params clockParams;

    // Convert clockDuration in milliseconds to ticks.
    uint32_t clockTicks = clockDuration * (1000 / Clock_tickPeriod);

    // Setup parameters.
    Clock_Params_init(&clockParams);

    // Setup argument.
    clockParams.arg = arg;

    // If period is 0, this is a one-shot timer.
    clockParams.period = clockPeriod * (1000 / Clock_tickPeriod);

    // Starts immediately after construction if true, otherwise wait for a call
    // to start.
    clockParams.startFlag = startFlag;

    // Initialize clock instance.
    Clock_construct(pClock, clockCB, clockTicks, &clockParams);

    return Clock_handle(pClock);
    }
  • In this function call:

    Util_constructClock(&WaitForTalkModeClock, SimpleBLEPeripheral_clockHandler,
    UART_WAIT_TIME, 0, false, WAIT_FOR_TALK_MODE_EVT);

    The last argument will get passed to your SimpleBLEPeripheral_clockHandle() function when the clock object times out. The content of the 'events' variable are not affected by Util_constructClock().

    Please confirm that the two calls to Util_startClock() in your code are occurring by placing breakpoints at the call sites.

    Alan
  • Alan,
    I changed #define UART_WAIT_TIME 2 (period of one shot clock = 20 ms).

    Can you tell me if Task_sleep(2000) translates to 20 ms or 2 seconds?

    The breakpoint in Util_startClock does not get executed. I am not able to see a connection between how the SimpleBLEPeripheral one shot clock gets started. I guess this clock is used for connection events and that's probably when it will start. I don't think we want UART monitoring to happen at the end of advertising event and we certainly don't want to connect to the sensor to start monitoring UART activity. How else to start this clock?


    if (events & WAIT_FOR_TALK_MODE_EVT) {
    events &= ~WAIT_FOR_TALK_MODE_EVT;

    Util_startClock(&WaitForTalkModeClock);
    waitForUARTMessage();
    }

    Thank you,
    Priya
  • Alan,
    Will the use of a timer be a workaround to this clock starting problem? How do set up a timer in CC2640?
    Thanks,
    Priya
  • I'm not understanding the problem.

    1)You've configured two ONE SHOT clocks to not start until YOU want them to start (ie the 'false' argument you passed to Util_constructClock()) .

    2)The one shot clocks won't start unless YOU start them by calling Util_startClock().

    3) Your logic won't call Util_startClock() until 'events' has certain bits turned on.

    4) The only code that turns those bits on is your SimpleBLEPeripheral_clockHandler() which only gets called if YOU call Util_startClock(), which won't called because of 3).

    Have I missed something?

    Alan
  • One of the one shot clocks comes with SimpeBLEPeripheral and I suspect gets started at a connection event. I don't use this clock in my application.

    I cannot wait to start the UART one shot clock at a BLE event (advertising or connection-- it drains battery life and cannot be done during sensor calibration). What other event do I create to start this clock? Do I keep calling construct clock inside the wait_ForUARTMessage function and have it start right away?

    Thanks,

    Priya

  • One more concern about starting the clock right away-- I can do this one time from SimpleBLEPeripheral_init, though I don't know how initialization will handle a potential 20 ms wait. The use of UART in our application does not want the BLE stack at all which is what is complicating this issue.

    Thanks,
    Priya
  • I'm still not understanding. Here, you are constructing two one-shot clock objects:

    // Create one-shot clocks for internal periodic events.
    Util_constructClock(&periodicClock, SimpleBLEPeripheral_clockHandler,
    SBP_PERIODIC_EVT_PERIOD, 0, false, SBP_PERIODIC_EVT);

    Util_constructClock(&WaitForTalkModeClock, SimpleBLEPeripheral_clockHandler,
    UART_WAIT_TIME, 0, false, WAIT_FOR_TALK_MODE_EVT);

    Neither of these are starting immediately because you have the startFlag set to false.

    In your "SimpleBLEPeripheral_taskFxn" you have this logic that conditionally starts these one-shot clock objects based on bits in 'events':

    if (events & WAIT_FOR_TALK_MODE_EVT) {
    events &= ~WAIT_FOR_TALK_MODE_EVT;

    Util_startClock(&WaitForTalkModeClock);
    waitForUARTMessage();
    }


    if (events & SBP_PERIODIC_EVT)
    {
    events &= ~SBP_PERIODIC_EVT;

    Util_startClock(&periodicClock);

    // Perform periodic application task
    SimpleBLEPeripheral_performPeriodicTask();
    }

    However, the only code that turns on the bits in 'events' is the clock function that only gets called when the one-shot clocks time out:

    static void SimpleBLEPeripheral_clockHandler(UArg arg)
    {
    // Store the event.
    events |= arg;

    // Wake up the application.
    Semaphore_post(sem);
    }

    Alan
  • Alan,
    I didn't realize you need to come to the end of the clock period for the clock event to trigger. I will give this a try on Monday and update. I appreciate the help.
    Have a good weekend,
    Priya
  • Alan-- I got started on re-ordering the sequence of events in my application. If I run into any further difficulties, I will post a new question. Thank you for resolving my confusion with the Clock API.
    Best regards,
    Priya