This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

libuarte_async idle detection using hardware timer and power consumption

Hardware: nRF52840 custom board

Software:

SDK: nRF5_SDK_17.0.2_d674dde

Using FreeRTOS where #define configTICK_SOURCE FREERTOS_USE_RTC  (Using RTC as systick)

2 UART's using libuart_async to achieve 921600 baud

RTC0: SoftDevice

RTC1: FreeRTOS Systick

RTC2: Time keeping counter (Overflow event tied to Hardware Timer 1 in counter mode for overflow count)

Timer0: SoftDevice

Timer1: Counts RTC2 overflows for time keeping purposes

Timer2: NRF_LIBUARTE_DRV_UARTE0

Timer3: NRF_LIBUARTE_DRV_UARTE1

Timer4: Not used

Hello,

From my understanding, I see that libuarte_async supports idle line detection using one of the following timers:

  • Hardware Timer
  • RTC
  • App timer

Question 1: If a hardware timer is used for timeout (idle line detection), is the timer always running or does it only run while data is being received and then stop when a timeout occurs? My concern here is that hardware timers use the HFCLK and I wouldn't want the HFCLK running when no UART data is being received.

Question 2: How do you recommend I configure my timers for lowest power consumption?

I don't have enough free timers (RTC or HW Timer). App timer is inefficient because it always triggers a timeout event at the configured interval regardless if RX data is being received.

Question 3: Is it possible to use the same RTC for FreeRTOS Systick and system time counting? I don't see why I can't free up RTC2 by counting the overflow events of RTC1 and share RTC1 with FreeRTOS. I don't want to interfere with the functions of tickless idle and such though so I am not sure this is possible? If possible, I can then use RTC2 for UARTE0 timeout and Timer4 for UARTE1 timeout.

Thanks,

Derek

  • Hi

    Question 1: If a hardware timer is used for timeout (idle line detection), is the timer always running or does it only run while data is being received and then stop when a timeout occurs? My concern here is that hardware timers use the HFCLK and I wouldn't want the HFCLK running when no UART data is being received.

    Essentially the timer will run until the timeout expires. Then the timer will stop, and will not be started again until you want to receive with a timeout again. 

    It is worth mentioning that you can't run the UART in RX without the HFCLK running, because it is used for the baudrate generation, so disabling the timers won't help in this case. 

    Question 2: How do you recommend I configure my timers for lowest power consumption?

    If low power is a concern then using an RTC timer or the app_timer is the best option (the app_timer is based on the RTC), but again you won't get very low power consumption while the UART is active since it requires an active HFCLK. 

    In order to get both low power and asynchronous UART receive it is recommended to use the UART flow control lines, so that you can disable the UART and the clock when the peer doesn't have anything to send, and use the flow control lines as a wakeup source. 

    Question 3: Is it possible to use the same RTC for FreeRTOS Systick and system time counting?

    I don't have a lot of experience with FreeRTOS unfortunately (and the FreeRTOS expert is on holiday), but unless you can use a FreeRTOS timer for the system time counting I don't think these can be shared. 

    How accurate time counting do you need?

    Best regards
    Torbjørn

  • Hey Torbjørn,

    Thanks for the reply! I have a few new questions below:

    "Essentially the timer will run until the timeout expires. Then the timer will stop, and will not be started again until you want to receive with a timeout again. "

    Question 1: For libuarte_async, I thought the intention was that the receiver is always active by calling nrf_libuarte_async_enable()?

    I am communicating with a LTE modem via UART. It can send data at any time and the UART receiver must always be active.

    "If low power is a concern then using an RTC timer or the app_timer is the best option (the app_timer is based on the RTC)"

    Question 2: How is the app_timer timeout implementation lower power compared to RTC or hardware timer? When libuarte_async timeout is configured with an app_timer, app_timer_handler() in nrf_libuarte_async.c is called repeatedly at this timeout interval regardless if data is being received. For responsive timeout detection and highest data throughput, the timeout needs to be small, for example 100 usec. This will mean that the processor is being woken up every 100 usec to poll the number of UART RX bytes to detect timeout. RTC and hardware timer do this through PPI and don't require CPU. What am I missing?

    "In order to get both low power and asynchronous UART receive it is recommended to use the UART flow control lines, so that you can disable the UART and the clock when the peer doesn't have anything to send, and use the flow control lines as a wakeup source. "

    Question 3: Does libuarte_async have support for waking up from flow control lines? If not, what example can I reference to implement this?

    "How accurate time counting do you need?"

    Our time counting RTC is currently configured with a prescaler of 0 (30.517 usec resolution) but we may be open to less resolution. I realized I can free up Timer1 by counting the RTC2 overflow events in software instead of using PPI and the timer counter since I will get an overflow interrupt only every 8.53 minutes.

    Thanks,

    Derek

     

  • Hi Derek

    droberson said:
    Question 1: For libuarte_async, I thought the intention was that the receiver is always active by calling nrf_libuarte_async_enable()?

    My bad, you are correct of course. As long as the receiver is enabled the timeout timer will have to run continuously, to check whether or not any data was received in the last timeout period. 

    droberson said:
    Question 2: How is the app_timer timeout implementation lower power compared to RTC or hardware timer?

    The app_timer is not lower power than the RTC, but it should be lower power than the TIMER module, since the TIMER module runs off of the high frequency clock. 

    I do agree that if you shorten the interval the advantage over the TIMER will be smaller, since the CPU needs to wake up more often. 

    Comparing TIMER, RTC and app_timer in this case is a bit challenging though, as the UART RX will lead to quite high current consumption on its own. This makes the choice between TIMER, RTC and app_timer less relevant for power savings reasons, and is probably more a question of which hardware resources you have available.

    droberson said:
    For responsive timeout detection and highest data throughput, the timeout needs to be small, for example 100 usec.

    Having a small timeout shouldn't be a requirement for good throughput. Once you fill up one set of buffers you will get an interrupt, regardless of what the state of the timeout timer is, so if the peer is pushing data at full speed you will get interrupts continuously depending on how large the buffers are. 

    droberson said:
    Question 3: Does libuarte_async have support for waking up from flow control lines? If not, what example can I reference to implement this?

    Good question. I can't find any clear signs in the code that anything gets disabled based on the flow control lines, but I will double check this and get back to you. Worst case you would have to wait for the flow control line to get asserted, and initialize the library based on this. 

    Best regards
    Torbjørn

  • Hey Torbjørn,

    Note sure how you highlight individual comments within the post, so I will resort to quotes.

    "My bad, you are correct of course. As long as the receiver is enabled the timeout timer will have to run continuously, to check whether or not any data was received in the last timeout period."

    Question 1: Your comment above is regarding only the app timer, correct? It looks like the RTC and hardware timers are in fact stopped when a timeout occurs and restarted when a new stream of bytes is received correct?

    Looking at nrf_libuarte_async.c, function nrf_libuarte_async_init(), I see the following:

    tmr_start_tsk = nrfx_timer_task_address_get(p_libuarte->p_timer, NRF_TIMER_TASK_START);
    tmr_clear_tsk = nrfx_timer_task_address_get(p_libuarte->p_timer, NRF_TIMER_TASK_CLEAR);
    tmr_stop_tsk = nrfx_timer_task_address_get(p_libuarte->p_timer, NRF_TIMER_TASK_SHUTDOWN);
    tmr_compare_evt = nrfx_timer_compare_event_address_get(p_libuarte->p_timer, 0);

    Then further down in that same function where PPI is configured:

    /*lint -save -e666 */
    PPI_CH_SETUP(p_libuarte->p_ctrl_blk->ppi_channels[NRF_LIBUARTE_ASYNC_PPI_CH_RXRDY_CLEAR],
                 nrf_uarte_event_address_get(p_libuarte->p_libuarte->uarte, NRF_UARTE_EVENT_RXDRDY),
                 tmr_start_tsk,
                 tmr_clear_tsk);
    
    PPI_CH_SETUP(p_libuarte->p_ctrl_blk->ppi_channels[NRF_LIBUARTE_ASYNC_PPI_CH_COMPARE_SHUTDOWN],
                 tmr_compare_evt,
                 tmr_stop_tsk,
                 (uint32_t)&p_libuarte->p_libuarte->timer.p_reg->TASKS_CAPTURE[3]);
    /*lint -restore */

    It looks like tmr_start_tsk and tmr_clear_tsk is tied to the RXDRDY event via PPI. This would mean that every time a RX byte is received, the timer is reset and started.

    Then it appears that tmr_compare_evt is tied to tmr_stop_tsk via PPI. This would mean that if the timeout value is reached due to not receiving an RX byte in the timeout period, the RTC or hardware timer will be stopped. It then will be restarted once the next byte is received.

    Is my understanding of this correct? If not, please clarify.

    "Having a small timeout shouldn't be a requirement for good throughput. Once you fill up one set of buffers you will get an interrupt, regardless of what the state of the timeout timer is, so if the peer is pushing data at full speed you will get interrupts continuously depending on how large the buffers are."

    Comment 1:

    The modem I am using is configured to work in a Command->Ack flow unfortunately. For example:

    07-28-2021 16:20:45.741 ATCMD_PROC: (COMM) Executing: AT#SSENDEXT=1,1000
    07-28-2021 16:20:45.747 ATCMD_PROC: (AT_CMD_PROC) Found response: >
    07-28-2021 16:20:45.784 ATCMD_PROC: (AT_CMD_PROC) Found response: OK

    So I have to tell the modem I am about to send it a chunk of data using AT#SSENDEXT=1,1000, wait for the ">" character to be returned, then send it the data, and wait for "OK" to be returned. If it were a true data stream, then yes I agree with your statement. But for the current design of this modem, processing responses as quickly as possible is key to achieve the highest throughput in my case.

    Comment 2:

    "Good question. I can't find any clear signs in the code that anything gets disabled based on the flow control lines, but I will double check this and get back to you. Worst case you would have to wait for the flow control line to get asserted, and initialize the library based on this."

    Thanks for checking on this, I am looking forward to your response. I will also reach out to our modem manufacturer to see if they have a "Notify" interrupt via flow control than can tell our MCU that RX data is available on the UART so I can shutdown the UART when there is no incoming data.

  • Hey Torbjørn,

    Any updates?

    For some reason the forum won't let me reply inline to the previous replies so I am replying to the original post for an update.

    I have mostly resolved my issue. The modem I am using provides a RING GPIO interrupt than can be configured to alert the MCU when unsolicited responses are ready to be received over UART. I now just shutdown the UART using nrf_libuarte_async_uninit() and re-init using nrf_libuarte_async_init() and nrf_libuarte_async_enable() which seems to work well. Since the libuarte_async driver has a large enough buffer to not miss RX bytes at 921600 baud, I always call nrf_libuarte_async_rts_clear() after init as well and leave RTS asserted.

    It would still be nice to know if libuarte has some fancy power management stuff internally that puts the UART interface and timers in low power when it detects that CTS is asserted. I haven't dug into libuarte's internals enough to determine this but I am doubtful it does. I am using a second UART and libuarte as an inter-processor communications interface that would benefit from such functionality.

    Thanks,

    Derek

Related