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.

  • TI Thinks Resolved

CC1312R: UART does not receive while in Task_sleep(), Semaphore_pend() or similar

Intellectual 955 points

Replies: 5

Views: 60

Part Number: CC1312R

In my application i use the UART for interactive control.In some places i have a loop that waits for some other external events like a packet receive. To abort this loop i check for a key-press/UART-RX of ESCAPE. For the waiting on the packet-receive i use RF_runCmd() with CMD_PROP_RX_SNIFF:

bool UART_getRxReady(UART_Handle hUART) {
    UARTCC26XX_Object* obj = (UARTCC26XX_Object*) (hUART->object);
    RingBuf_Handle rb = &(obj->ringBuffer);
    return (RingBuf_getCount(rb) >0);
}

bool checkAbort(UART_Handle hUART) {
  if (UART_getRxReady(hUART)) {
    char ch = 0;
    int n = UART_read(hUART, &ch, 1);
    if (ch ==ESCAPE)
      return true;
  }
  return false;
}

void waitForPacket() {
  bool done = false;
  while (!done) {
    RF_runCmd(...)
    if (packetReceived) {
      done = true;
    } else if (checkAbort())
      done = true;   
  }
}

With this loop, i never receive a character. To check i have created another test loop:

void testLoop() {
  bool done = false;
  while (!done) {
    Task_sleep(someValue);
    if (checkAbort())
      done = true;
  }
}

This loop also does not receive a character. If i omit the Task_sleep(), it works and can aborted with a ESCAPE.

I suspect it has something to do with the power-policies that shut down the UART-receive while processor goes to sleep.

An suggestion how i can make it working to receive thru UART while processor is in Task_sleep() or Semaphore_pend()?

  • Guru 56965 points

    Hi Jan,

    How do you setup your UART? Seems to me that you are not using an active read (most likely as you want to be in standby?) and in this case, the power manger would turn of the UART once it goes into standby (as there is nothing in your application setting a constraint on it).

    If you could elaborate on what you are trying to achieve in terms of UART and "sleep" then I could give you some pointers on how to best implement it. Generally, to be sure to keep receiving in the background, you have to have a UART read call active as this keeps the constraint in the system. This will however mean that you suffer in power consumption and I guess that could be an issue.

    If you need low power and sleep, then you would need to put something together with the PIN and UART driver where you first treat UART RX as a GPIO and wait for a falling edge. At this point, you would need to re-configure the PIN for UART again (removing from PIN handle and open UART driver) and perform the read. This comes at the cost of most likely loosing the first character sent to the device when in sleep.

    Best regards,

    M-W

  • In reply to M-W:

    Hi M-W,

    the first example in my post is what i want to achieve:

    I have 2 devices: Device B has an interactive interface thru serial connection and the Device L is not interactive. The Device L send every 30s a packet with some information and wait a short time to get a connection request from Device B. On Device B the user has an option to make a connection to Device L. If the option to make the connection is selected, Device B stays in a loop an listen for the periodic packet from Device L. If a packet from Device L is received, a connection is established and the two devices can communicate. After the communication is finished, Device B returns to the loop and waits for another information packet. But the user that started the wait-for-packet loop should have the option to abort the loop and to do anything other with the Device B. To abort the loop the user should send the ESCAPE-character, and the Device B should return to the menu.

    The waiting for the Packet from Device is done with repeated calls of RF_runCmd(CMD_PROP_RX_SNIFF). If the CMD_PROP_RX_SNIFF was not successful, i want to check that something is received by the UART and if the received character is ESCAPE the loop is aborted.

    Power consumption on Device B is not critical. Running the UART_read() in a background task, is something i have thought about. But this will make my application much more complex, because i always have to route the incoming characters from the UART from the background-task to the foreground-task. It would be much more simple, if i find a way that the UART does not stop receiving while staying in the RF_runCmd(), and i can get the received characters from the ringbuffer. I think everything is about the PowerManager a how it handles the UART while RF_runCmd() waits for the completion of the command.

    What is the right way to signal the PowerManager not to shut down the UART and continue to handle UART int's while in Idle?

    Regards

    Jan

  • Guru 56965 points

    In reply to Jan Ingwer Baer:

    Hi Jan,

    You can't signal the power manager to "not shutdown UART" specifically, that is not how it is designed. You can tell it to not allow standby by using the Power_setContraint(PowerCC26XX_DISALLOW_STANDBY) and this is also what the UART driver does. 

    As there is more to the driver then this, I recommend to stay with using the "normal" UART_read()" way of doing things without going the "long way" of polling the UART ringbuffer. If for nothing else, it would assure that the code would continue to work even if we see the need to update the UART backend. 

    I would think you could make a clean/simple application with using the UART read callback:

    bool readCallback(UART_Handle handle, void *buf, size_t count) {
        if (*buf == ESCAPE) {
            // Abort the current RF operation
            RF_abortCmd(...);
        }
    
        // Restart read
        UART_read(handle, buff, 1);
    }
    
    void waitForPacket() {
      bool done = false;
      while (!done) {
        // Run a infinite RX Sniff, end on OK / Abort
        RF_runCmd(...)
    
        // Received or Abort?
        if (packetReceived) {
          done = true;
        } else {
          // Command was aborted
          done = true;
        } 
      } 
    }

    Best regards,

    M-W

  • In reply to M-W:

    Hi M-W,

    thank you for your fast reply. The problem, for me, with your solution is that i can't mix UART_read() with and without callback. All the logic for my menu-system and other user input uses UART_MODE_BLOCKING for UART_read(). If i change the readMode to UART_MODE_CALLBACK i have to create some workaround to simulate a blocking UART_read() with timeout.

    I have just made a test using Power_setContraint(PowerCC26XX_DISALLOW_STANDBY) and this work as i expect. Because power consumption is not a critical point, i think i will stay with this solution.

    The 'long way' with polling the UART ringbuffer is OK. It would be more easy, if Sysconfig would use the UARTCC26X2 function table, or the functions in UARTCC26XX_control() would implement the same UART_CMD-codes that UARTCC26X2_control implements (UART_CMD_PEEK, UART_CMD_RXENABLE). But the difference between UARTCC26XX and UARTCC26X2 is another point...

    Regards

    Jan

  • Guru 56965 points

    In reply to Jan Ingwer Baer:

    Hi Jan,

    There is some differences between the XX and X2 version for sure, there is also a UART2 that adds DMA support (among other things). If starting from scratch, I would recommend checking the latter out as it will likely be the go-to driver in the future (the old will remain for legacy reasons). But hey, this was not what you asked about :)

    As for mixing the two, the blocking UART is actually just a "internal" UART callback. You would get the same in application (with controllable timeout per read basis) by wrapping:

    UART_read(...)
    
    SemaphoreP_pend(...);

    But if you find that the current approach works for you with the power constraint set, then stick with that :)

    Best regards,

    M-W

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.