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

Does Counter Mode Timer really need TASKS_START ?

[References]

In page 234 of nRF52832_PS_v1.4 it says
    "In both modes, the TIMER is started by triggering the START task, and stopped by triggering the STOP task."

In this post  stated:
    "You must start the timer with TASKS_START also in counter mode.", 
while the statement from @Mik contradicts as:
    "the counter even counts the signals when not started. it would save mi 8uA when not using TASK_START with the same effect in getting the counting value."

In this post  stated:
    "The information given in the document is not adequate, the designer of the TIMER gave me proper information. In COUNTER mode of the TIMER, the HFCLK is not requested unless there is a COUNT task. When COUNT task is triggered, the TIMER peripheral will request the hfclk to get one clock cycle so that it will be able to do the COUNTER increment logic. And after that it stops requesting the HFCLK. This means that if nothing else is using HFCLK, and when COUNT task is triggered then HFCLK is requested and is turned on for 62ns (1 cycle) and then requested to turn off again."

By testing with the following code, I get the same results as @Mik.
4.8 / 8.7 uA saving is measured on PCA10040 / our PCB if TASKS_START is not set.
Both w/ or w/o TASKS_START will give expected results (1,2,3 are printed)

void main(void)
{
    NRF_LOG_INIT(NULL);
    NRF_LOG_DEFAULT_BACKENDS_INIT();
    
    NRF_TIMER4->TASKS_CLEAR  = 1;
    NRF_TIMER4->SHORTS       = 0;
    NRF_TIMER4->INTENCLR     = 0xffffffff;
    NRF_TIMER4->MODE         = TIMER_MODE_MODE_LowPowerCounter << TIMER_MODE_MODE_Pos;
    NRF_TIMER4->BITMODE      = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos;
    NRF_TIMER4->PRESCALER    = 0;
    NRF_TIMER4->CC[0]        = 0;
    NRF_TIMER4->CC[1]        = 0;
    NRF_TIMER4->CC[2]        = 0;
    NRF_TIMER4->CC[3]        = 0;
    NRF_TIMER4->CC[4]        = 0;
    NRF_TIMER4->CC[5]        = 0;
    NVIC_DisableIRQ(TIMER4_IRQn);

#ifdef DO_TIMER_TASKS_START
    NRF_TIMER4->TASKS_START  = 1;
#endif

    NRF_TIMER4->TASKS_COUNT = 1;
    NRF_TIMER4->TASKS_CAPTURE[0] = 1;
    NRF_LOG_DEBUG("Timer4->CC[0] = %d", NRF_TIMER4->CC[0]);

    NRF_TIMER4->TASKS_COUNT = 1;
    NRF_TIMER4->TASKS_CAPTURE[0] = 1;
    NRF_LOG_DEBUG("Timer4->CC[0] = %d", NRF_TIMER4->CC[0]);

    NRF_TIMER4->TASKS_COUNT = 1;
    NRF_TIMER4->TASKS_CAPTURE[0] = 1;
    NRF_LOG_DEBUG("Timer4->CC[0] = %d", NRF_TIMER4->CC[0]);

    nrf_pwr_mgmt_init();

    while (1)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
}

Is it possible that Nordic confirms again in this post for the usage of counter mode timer?
4.8 / 8.7 uA is quite big compared with <2 uA current in "system on, sleep" state, and is critical for optimizing battery life.
Please help on this topic, thank you.

Parents
  • Xavier,

    The counter task might work correctly when you are doing this test after the first reset. I call this kind of result "getting lucky". This is because this was not designed this way, but the internal implementation of it makes it possible to use it. The designers of the hardware always use TASKS_START and TASKS_STOP to request the peripheral resources and release them. In this case, the clock and voltage regulators that are required by the TIMER4 is already running since the CPU is running. Imagine a situation where you have configured your device in a way, that releases all the clocks and voltage regulators are OFF. This is a very common situation on sleep mode. Then not doing a TASKS_START means missing the part where you properly register the module to resource manager. 

    I would recommend you one test.

    1) configure an RTC to generate a TICK every X seconds. (disable all interrupts on this RTC)

    2) use this tick event -> GPIOTE -> connect this task to the TASKS_COUNT

    3) Initialize your TIMER4 exactly like above except that TASKS_COUNT is coming from RTC.

    4) make the system to go to sleep __WFE()

    5) wakeup aftersometime and disable RTC ticks.

    6) check for the TIMER4 counter value

    Why are we doing this? Since we want to see that your "Lucky outcome" will survive the worst case scenario. This is not specified in spec, hence the TIMERS are not tested for this. But if you get a good result above, then you should be covered.

  •   

    static nrf_ppi_channel_t    ppi_channel_compare0;
    static nrf_ppi_channel_t    ppi_channel_compare1;
    static nrf_ppi_channel_t    ppi_channel_compare2;
    
    void main(void)
    {
        NRF_LOG_INIT(NULL);
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        nrf_drv_clock_init();
        nrf_drv_clock_lfclk_request(NULL);
    
        nrf_pwr_mgmt_init();
    
        NRF_RTC2->TASKS_STOP        = 1;
        NRF_RTC2->TASKS_CLEAR       = 1;
        NRF_RTC2->EVENTS_TICK       = 0;
        NRF_RTC2->EVENTS_OVRFLW     = 0;
        NRF_RTC2->EVENTS_COMPARE[0] = 0;
        NRF_RTC2->EVENTS_COMPARE[1] = 0;
        NRF_RTC2->EVENTS_COMPARE[2] = 0;
        NRF_RTC2->EVENTS_COMPARE[3] = 0;
        NRF_RTC2->EVTENCLR          = 0xffffffff;
        NRF_RTC2->EVTENSET          = RTC_EVTENSET_COMPARE0_Msk | RTC_EVTENSET_COMPARE1_Msk | RTC_EVTENSET_COMPARE2_Msk | RTC_EVTENSET_COMPARE3_Msk;
        NRF_RTC2->INTENCLR          = 0xffffffff;
        NRF_RTC2->INTENSET          = RTC_INTENSET_COMPARE3_Msk;
        NRF_RTC2->PRESCALER         = 0;
        NRF_RTC2->CC[0]             = 32768 * 1;
        NRF_RTC2->CC[1]             = 32768 * 2;
        NRF_RTC2->CC[2]             = 32768 * 3;
        NRF_RTC2->CC[3]             = 32768 * 4;
        NVIC_ClearPendingIRQ(RTC2_IRQn);
        NVIC_EnableIRQ(RTC2_IRQn);
    
        NRF_TIMER4->TASKS_CLEAR  = 1;
        NRF_TIMER4->SHORTS       = 0;
        NRF_TIMER4->INTENCLR     = 0xffffffff;
        NRF_TIMER4->MODE         = TIMER_MODE_MODE_LowPowerCounter;
        NRF_TIMER4->BITMODE      = TIMER_BITMODE_BITMODE_32Bit;
        NRF_TIMER4->PRESCALER    = 0;
        NRF_TIMER4->CC[0]        = 0;
        NRF_TIMER4->CC[1]        = 0;
        NRF_TIMER4->CC[2]        = 0;
        NRF_TIMER4->CC[3]        = 0;
        NRF_TIMER4->CC[4]        = 0;
        NRF_TIMER4->CC[5]        = 0;
        NVIC_DisableIRQ(TIMER4_IRQn);
    
        nrf_drv_ppi_init();
        nrf_drv_ppi_channel_alloc(&ppi_channel_compare0);
        nrf_drv_ppi_channel_assign(ppi_channel_compare0, (uint32_t)&NRF_RTC2->EVENTS_COMPARE[0], (uint32_t)&NRF_TIMER4->TASKS_COUNT);
        nrf_drv_ppi_channel_alloc(&ppi_channel_compare1);
        nrf_drv_ppi_channel_assign(ppi_channel_compare1, (uint32_t)&NRF_RTC2->EVENTS_COMPARE[1], (uint32_t)&NRF_TIMER4->TASKS_COUNT);
        nrf_drv_ppi_channel_alloc(&ppi_channel_compare2);
        nrf_drv_ppi_channel_assign(ppi_channel_compare2, (uint32_t)&NRF_RTC2->EVENTS_COMPARE[2], (uint32_t)&NRF_TIMER4->TASKS_COUNT);
    
        nrf_drv_ppi_channel_enable(ppi_channel_compare0);
        nrf_drv_ppi_channel_enable(ppi_channel_compare1);
        nrf_drv_ppi_channel_enable(ppi_channel_compare2);
    #ifdef DO_TIMER_TASKS_START
        NRF_TIMER4->TASKS_START  = 1;
    #endif
        NRF_RTC2->TASKS_START       = 1;
    
        NRF_LOG_INFO("start running");
    
        while (1)
        {
            if (NRF_LOG_PROCESS() == false)
            {
                nrf_pwr_mgmt_run();
            }
        }
    }
    
    void RTC2_IRQHandler(void)
    {
        nrf_drv_ppi_channel_disable(ppi_channel_compare0);
        nrf_drv_ppi_channel_disable(ppi_channel_compare1);
        nrf_drv_ppi_channel_disable(ppi_channel_compare2);
    
        NRF_RTC2->EVTENCLR          = RTC_EVTENCLR_COMPARE3_Msk;
        NRF_RTC2->INTENCLR          = 0xffffffff;
        NVIC_DisableIRQ(RTC2_IRQn);
    
        NRF_TIMER4->TASKS_CAPTURE[0] = 1;
        NRF_LOG_INFO("RTC2 EVENT: %u, %u, %u, %u", NRF_RTC2->EVENTS_COMPARE[0], NRF_RTC2->EVENTS_COMPARE[1], NRF_RTC2->EVENTS_COMPARE[2], NRF_RTC2->EVENTS_COMPARE[3]);
        NRF_LOG_INFO("TIMER4->CC[0] = %u", NRF_TIMER4->CC[0]);
        NRF_LOG_INFO("turned off all PPI, but keep RTC & TIMER running for current measurement");
    }

    Do you think this demonstrates "the worst case scenario"?
    Can you kindly share the results on your side?
    Do you expect any notable difference about energy consumption if softdevice is enabled (advertising)?

Reply
  •   

    static nrf_ppi_channel_t    ppi_channel_compare0;
    static nrf_ppi_channel_t    ppi_channel_compare1;
    static nrf_ppi_channel_t    ppi_channel_compare2;
    
    void main(void)
    {
        NRF_LOG_INIT(NULL);
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        nrf_drv_clock_init();
        nrf_drv_clock_lfclk_request(NULL);
    
        nrf_pwr_mgmt_init();
    
        NRF_RTC2->TASKS_STOP        = 1;
        NRF_RTC2->TASKS_CLEAR       = 1;
        NRF_RTC2->EVENTS_TICK       = 0;
        NRF_RTC2->EVENTS_OVRFLW     = 0;
        NRF_RTC2->EVENTS_COMPARE[0] = 0;
        NRF_RTC2->EVENTS_COMPARE[1] = 0;
        NRF_RTC2->EVENTS_COMPARE[2] = 0;
        NRF_RTC2->EVENTS_COMPARE[3] = 0;
        NRF_RTC2->EVTENCLR          = 0xffffffff;
        NRF_RTC2->EVTENSET          = RTC_EVTENSET_COMPARE0_Msk | RTC_EVTENSET_COMPARE1_Msk | RTC_EVTENSET_COMPARE2_Msk | RTC_EVTENSET_COMPARE3_Msk;
        NRF_RTC2->INTENCLR          = 0xffffffff;
        NRF_RTC2->INTENSET          = RTC_INTENSET_COMPARE3_Msk;
        NRF_RTC2->PRESCALER         = 0;
        NRF_RTC2->CC[0]             = 32768 * 1;
        NRF_RTC2->CC[1]             = 32768 * 2;
        NRF_RTC2->CC[2]             = 32768 * 3;
        NRF_RTC2->CC[3]             = 32768 * 4;
        NVIC_ClearPendingIRQ(RTC2_IRQn);
        NVIC_EnableIRQ(RTC2_IRQn);
    
        NRF_TIMER4->TASKS_CLEAR  = 1;
        NRF_TIMER4->SHORTS       = 0;
        NRF_TIMER4->INTENCLR     = 0xffffffff;
        NRF_TIMER4->MODE         = TIMER_MODE_MODE_LowPowerCounter;
        NRF_TIMER4->BITMODE      = TIMER_BITMODE_BITMODE_32Bit;
        NRF_TIMER4->PRESCALER    = 0;
        NRF_TIMER4->CC[0]        = 0;
        NRF_TIMER4->CC[1]        = 0;
        NRF_TIMER4->CC[2]        = 0;
        NRF_TIMER4->CC[3]        = 0;
        NRF_TIMER4->CC[4]        = 0;
        NRF_TIMER4->CC[5]        = 0;
        NVIC_DisableIRQ(TIMER4_IRQn);
    
        nrf_drv_ppi_init();
        nrf_drv_ppi_channel_alloc(&ppi_channel_compare0);
        nrf_drv_ppi_channel_assign(ppi_channel_compare0, (uint32_t)&NRF_RTC2->EVENTS_COMPARE[0], (uint32_t)&NRF_TIMER4->TASKS_COUNT);
        nrf_drv_ppi_channel_alloc(&ppi_channel_compare1);
        nrf_drv_ppi_channel_assign(ppi_channel_compare1, (uint32_t)&NRF_RTC2->EVENTS_COMPARE[1], (uint32_t)&NRF_TIMER4->TASKS_COUNT);
        nrf_drv_ppi_channel_alloc(&ppi_channel_compare2);
        nrf_drv_ppi_channel_assign(ppi_channel_compare2, (uint32_t)&NRF_RTC2->EVENTS_COMPARE[2], (uint32_t)&NRF_TIMER4->TASKS_COUNT);
    
        nrf_drv_ppi_channel_enable(ppi_channel_compare0);
        nrf_drv_ppi_channel_enable(ppi_channel_compare1);
        nrf_drv_ppi_channel_enable(ppi_channel_compare2);
    #ifdef DO_TIMER_TASKS_START
        NRF_TIMER4->TASKS_START  = 1;
    #endif
        NRF_RTC2->TASKS_START       = 1;
    
        NRF_LOG_INFO("start running");
    
        while (1)
        {
            if (NRF_LOG_PROCESS() == false)
            {
                nrf_pwr_mgmt_run();
            }
        }
    }
    
    void RTC2_IRQHandler(void)
    {
        nrf_drv_ppi_channel_disable(ppi_channel_compare0);
        nrf_drv_ppi_channel_disable(ppi_channel_compare1);
        nrf_drv_ppi_channel_disable(ppi_channel_compare2);
    
        NRF_RTC2->EVTENCLR          = RTC_EVTENCLR_COMPARE3_Msk;
        NRF_RTC2->INTENCLR          = 0xffffffff;
        NVIC_DisableIRQ(RTC2_IRQn);
    
        NRF_TIMER4->TASKS_CAPTURE[0] = 1;
        NRF_LOG_INFO("RTC2 EVENT: %u, %u, %u, %u", NRF_RTC2->EVENTS_COMPARE[0], NRF_RTC2->EVENTS_COMPARE[1], NRF_RTC2->EVENTS_COMPARE[2], NRF_RTC2->EVENTS_COMPARE[3]);
        NRF_LOG_INFO("TIMER4->CC[0] = %u", NRF_TIMER4->CC[0]);
        NRF_LOG_INFO("turned off all PPI, but keep RTC & TIMER running for current measurement");
    }

    Do you think this demonstrates "the worst case scenario"?
    Can you kindly share the results on your side?
    Do you expect any notable difference about energy consumption if softdevice is enabled (advertising)?

Children
Related