RTC, timer and low power mode

We have using nrf5340-nrf7002 in our custom board. SDK version 2.6.1

We understand that the timer will not function in System OFF (deep sleep) mode. However, our project is battery-operated, so we need a sleep/low power mode to minimize power consumption.

In our products, we have planned to  implement a periodic interval cycle for10-minute sleep/low power mode and wakeup using an RTC timer interrupt. We want use the RTC to set/get calendar time. 

1 How can we achieve similar functionality in nRF5340?

2. Could you please advise us on the available low power modes in nRF devices and, specifically, how to wake up from System OFF using a timer interrupt?




Parents
  • Hello,

    ''It seems you want to use the timer based ON/OFF on the host. It is implemented in nRF5340. '' This I mentioned in my previous reply for your number 1 query. 

    Also, if you want to wake up device from sleep mode without using timer you can follow this: (Driver features (nordicsemi.com)

    The device is put into System OFF mode using the register SYSTEMOFF . The following initiate a wakeup from System OFF:

    • The DETECT signal, generated by the GPIO peripheral
    • The ANADETECT signal, generated by the LPCOMP peripheral
    • The SENSE signal, generated by the NFCT peripheral to wake-on-field
    • A valid USB voltage on the VBUS pin is detected
    • A debug session is started
    • A pin reset

    2. Could you please advise us on the available low power modes in nRF devices and, specifically, how to wake up from System OFF using a timer interrupt?

    Did you mean any nRF SoCs apart from the SoCs used in your custom board?

    You can read power modes here Power and clock management (nordicsemi.com)

  • Ok thank you for your update. 

    I have check counter alarm sample. it is working fine as expected. In that sample i have check rtc set/get API.

    My Overlay file:

    / {
        aliases {
        rtc0 = &rtc0;
    };
    };
    
    &rtc0{
    	compatible = "nordic,nrf-rtc";
    	reg = <0x14000 0x1000>;
    	cc-num = <4>;
    	interrupts = <20 NRF_DEFAULT_IRQ_PRIORITY>;
    	status = "okay";
    	clock-frequency = <32768>;
    	prescaler = <1>;
    };
    

    proj.conf file

    CONFIG_PRINTK=y
    CONFIG_COUNTER=y
    CONFIG_RTC=y
    CONFIG_RTC_UPDATE=y
    CONFIG_RTC_CALIBRATION=y
    CONFIG_RTC_ALARM=y
    CONFIG_NRF_RTC0_SECURE=y

    Main.c

    /*
     * Copyright (c) 2019 Linaro Limited
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/kernel.h>
    
    #include <zephyr/device.h>
    #include <zephyr/drivers/counter.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/sys/timeutil.h>
    #include <zephyr/drivers/rtc.h>
    
    #include <time.h>
    #define DELAY 2000000
    #define ALARM_CHANNEL_ID 0
    
    struct counter_alarm_cfg alarm_cfg;
    /* Wed Dec 31 2025 23:59:55 GMT+0000 */
    #define RTC_TEST_GET_SET_TIME	  (1767225595UL)
    #define RTC_TEST_GET_SET_TIME_TOL (1UL)
    
    #define TIMER DT_NODELABEL(rtc0)
    
    const struct device *const counter_dev = DEVICE_DT_GET(TIMER);
    
    static void test_counter_interrupt_fn(const struct device *counter_dev,
    				      uint8_t chan_id, uint32_t ticks,
    				      void *user_data)
    {
    	struct counter_alarm_cfg *config = user_data;
    	uint32_t now_ticks;
    	uint64_t now_usec;
    	int now_sec;
    	int err;
    	struct rtc_time datetime_get;
    
    	err = counter_get_value(counter_dev, &now_ticks);
    	if (err) {
    		printk("Failed to read counter value (err %d)", err);
    		return;
    	}
    
    	now_usec = counter_ticks_to_us(counter_dev, now_ticks);
    	now_sec = (int)(now_usec / USEC_PER_SEC);
    
    	printk("!!! Alarm !!!\n");
    	memset(&datetime_get, 0xFF, sizeof(datetime_get));
    
    	if(rtc_get_time(counter_dev, &datetime_get) == 0)
    	{
    		printk("get time %d:%d:%d  %d:%d:%d\n",datetime_get.tm_hour, datetime_get.tm_min, datetime_get.tm_sec, datetime_get.tm_mday, datetime_get.tm_mon, datetime_get.tm_year);
    		
    		printk("Time %04d-%02d-%02dT%02d:%02d:%02d:%06d\n", datetime_get.tm_year + 1900,
    		    datetime_get.tm_mon + 1, datetime_get.tm_mday, datetime_get.tm_hour, datetime_get.tm_min,
    		    datetime_get.tm_sec, datetime_get.tm_nsec / 1000000);
    	}
    
    	printk("Now: %u\n", now_sec);
    
    	/* Set a new alarm with a double length duration */
    	config->ticks = config->ticks * 2U;
    
    	printk("Set alarm in %u sec (%u ticks)\n",
    	       (uint32_t)(counter_ticks_to_us(counter_dev,
    					   config->ticks) / USEC_PER_SEC),
    	       config->ticks);
    
    	err = counter_set_channel_alarm(counter_dev, ALARM_CHANNEL_ID,
    					user_data);
    	if (err != 0) {
    		printk("Alarm could not be set\n");
    	}
    }
    
    static void test_set_get_time(void)
    {
    	struct rtc_time datetime_set;
    		struct rtc_time datetime_get;
    
    	// time_t timer_get;
    	time_t timer_set = RTC_TEST_GET_SET_TIME;
    
    	gmtime_r(&timer_set, (struct tm *)(&datetime_set));
    
    	// datetime_set.tm_hour = 11;
    	// datetime_set.tm_min = 46;
    	// datetime_set.tm_sec = 40;
    	// datetime_set.tm_mday = 12;
    	// datetime_set.tm_mon = 8;
    	// datetime_set.tm_year = 2024;
    
    	if(rtc_set_time(counter_dev, &datetime_set) == 0)
    	{
    		printk("set time %d:%d:%d  %d:%d:%d\n",datetime_set.tm_hour, datetime_set.tm_min, datetime_set.tm_sec, datetime_set.tm_mday, datetime_set.tm_mon, datetime_set.tm_year);
    
    		printk("Time %04d-%02d-%02dT%02d:%02d:%02d:%06d\n", datetime_set.tm_year + 1900,
    		    datetime_set.tm_mon + 1, datetime_set.tm_mday, datetime_set.tm_hour, datetime_set.tm_min,
    		    datetime_set.tm_sec, datetime_set.tm_nsec / 1000000);
    	}
    	// memset(&datetime_get, 0xFF, sizeof(datetime_get));
    	// if(rtc_get_time(counter_dev, &datetime_get) == 0)
    	// {
    	// 	printk("get time %d:%d:%d  %d:%d:%d\n",datetime_get.tm_hour, datetime_get.tm_min, datetime_get.tm_sec, datetime_get.tm_mday, datetime_get.tm_mon, datetime_get.tm_year);
    	// }
    }
    
    int main(void)
    {
    	int err;
    
    	printk("Counter alarm sample\n\n");
    
    	if (!device_is_ready(counter_dev)) {
    		printk("device not ready.\n");
    		return 0;
    	}
    
    	counter_start(counter_dev);
    
    	alarm_cfg.flags = 0;
    	alarm_cfg.ticks = counter_us_to_ticks(counter_dev, DELAY);
    	alarm_cfg.callback = test_counter_interrupt_fn;
    	alarm_cfg.user_data = &alarm_cfg;
    
    	test_set_get_time();
    	
    	err = counter_set_channel_alarm(counter_dev, ALARM_CHANNEL_ID, &alarm_cfg);
    	printk("Set alarm in %u sec (%u ticks)\n", (uint32_t)(counter_ticks_to_us(counter_dev, alarm_cfg.ticks) / USEC_PER_SEC), alarm_cfg.ticks);
    
    	if (-EINVAL == err) {
    		printk("Alarm settings invalid\n");
    	} else if (-ENOTSUP == err) {
    		printk("Alarm setting request not supported\n");
    	} else if (err != 0) {
    		printk("Error\n");
    	}
    
    	while (1) {
    		k_sleep(K_FOREVER);
    	}
    	return 0;
    }
    

    But getting invalid time and the didn't get alarm after 4sec set.

    *** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
    Counter alarm sample

    set time 23:59:55 31:11:125
    Time 2025-12-31T23:59:55:000000
    Set alarm in 2 sec (65536 ticks)
    !!! Alarm !!!
    get time -1:-1:-1 -1:-1:-1
    Time 1899-00--1T-1:-1:-1:000000
    Now: 20
    Set alarm in 4 sec (131072 ticks)


    Is there any configuration is missing? Please advise on this.

Reply
  • Ok thank you for your update. 

    I have check counter alarm sample. it is working fine as expected. In that sample i have check rtc set/get API.

    My Overlay file:

    / {
        aliases {
        rtc0 = &rtc0;
    };
    };
    
    &rtc0{
    	compatible = "nordic,nrf-rtc";
    	reg = <0x14000 0x1000>;
    	cc-num = <4>;
    	interrupts = <20 NRF_DEFAULT_IRQ_PRIORITY>;
    	status = "okay";
    	clock-frequency = <32768>;
    	prescaler = <1>;
    };
    

    proj.conf file

    CONFIG_PRINTK=y
    CONFIG_COUNTER=y
    CONFIG_RTC=y
    CONFIG_RTC_UPDATE=y
    CONFIG_RTC_CALIBRATION=y
    CONFIG_RTC_ALARM=y
    CONFIG_NRF_RTC0_SECURE=y

    Main.c

    /*
     * Copyright (c) 2019 Linaro Limited
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/kernel.h>
    
    #include <zephyr/device.h>
    #include <zephyr/drivers/counter.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/sys/timeutil.h>
    #include <zephyr/drivers/rtc.h>
    
    #include <time.h>
    #define DELAY 2000000
    #define ALARM_CHANNEL_ID 0
    
    struct counter_alarm_cfg alarm_cfg;
    /* Wed Dec 31 2025 23:59:55 GMT+0000 */
    #define RTC_TEST_GET_SET_TIME	  (1767225595UL)
    #define RTC_TEST_GET_SET_TIME_TOL (1UL)
    
    #define TIMER DT_NODELABEL(rtc0)
    
    const struct device *const counter_dev = DEVICE_DT_GET(TIMER);
    
    static void test_counter_interrupt_fn(const struct device *counter_dev,
    				      uint8_t chan_id, uint32_t ticks,
    				      void *user_data)
    {
    	struct counter_alarm_cfg *config = user_data;
    	uint32_t now_ticks;
    	uint64_t now_usec;
    	int now_sec;
    	int err;
    	struct rtc_time datetime_get;
    
    	err = counter_get_value(counter_dev, &now_ticks);
    	if (err) {
    		printk("Failed to read counter value (err %d)", err);
    		return;
    	}
    
    	now_usec = counter_ticks_to_us(counter_dev, now_ticks);
    	now_sec = (int)(now_usec / USEC_PER_SEC);
    
    	printk("!!! Alarm !!!\n");
    	memset(&datetime_get, 0xFF, sizeof(datetime_get));
    
    	if(rtc_get_time(counter_dev, &datetime_get) == 0)
    	{
    		printk("get time %d:%d:%d  %d:%d:%d\n",datetime_get.tm_hour, datetime_get.tm_min, datetime_get.tm_sec, datetime_get.tm_mday, datetime_get.tm_mon, datetime_get.tm_year);
    		
    		printk("Time %04d-%02d-%02dT%02d:%02d:%02d:%06d\n", datetime_get.tm_year + 1900,
    		    datetime_get.tm_mon + 1, datetime_get.tm_mday, datetime_get.tm_hour, datetime_get.tm_min,
    		    datetime_get.tm_sec, datetime_get.tm_nsec / 1000000);
    	}
    
    	printk("Now: %u\n", now_sec);
    
    	/* Set a new alarm with a double length duration */
    	config->ticks = config->ticks * 2U;
    
    	printk("Set alarm in %u sec (%u ticks)\n",
    	       (uint32_t)(counter_ticks_to_us(counter_dev,
    					   config->ticks) / USEC_PER_SEC),
    	       config->ticks);
    
    	err = counter_set_channel_alarm(counter_dev, ALARM_CHANNEL_ID,
    					user_data);
    	if (err != 0) {
    		printk("Alarm could not be set\n");
    	}
    }
    
    static void test_set_get_time(void)
    {
    	struct rtc_time datetime_set;
    		struct rtc_time datetime_get;
    
    	// time_t timer_get;
    	time_t timer_set = RTC_TEST_GET_SET_TIME;
    
    	gmtime_r(&timer_set, (struct tm *)(&datetime_set));
    
    	// datetime_set.tm_hour = 11;
    	// datetime_set.tm_min = 46;
    	// datetime_set.tm_sec = 40;
    	// datetime_set.tm_mday = 12;
    	// datetime_set.tm_mon = 8;
    	// datetime_set.tm_year = 2024;
    
    	if(rtc_set_time(counter_dev, &datetime_set) == 0)
    	{
    		printk("set time %d:%d:%d  %d:%d:%d\n",datetime_set.tm_hour, datetime_set.tm_min, datetime_set.tm_sec, datetime_set.tm_mday, datetime_set.tm_mon, datetime_set.tm_year);
    
    		printk("Time %04d-%02d-%02dT%02d:%02d:%02d:%06d\n", datetime_set.tm_year + 1900,
    		    datetime_set.tm_mon + 1, datetime_set.tm_mday, datetime_set.tm_hour, datetime_set.tm_min,
    		    datetime_set.tm_sec, datetime_set.tm_nsec / 1000000);
    	}
    	// memset(&datetime_get, 0xFF, sizeof(datetime_get));
    	// if(rtc_get_time(counter_dev, &datetime_get) == 0)
    	// {
    	// 	printk("get time %d:%d:%d  %d:%d:%d\n",datetime_get.tm_hour, datetime_get.tm_min, datetime_get.tm_sec, datetime_get.tm_mday, datetime_get.tm_mon, datetime_get.tm_year);
    	// }
    }
    
    int main(void)
    {
    	int err;
    
    	printk("Counter alarm sample\n\n");
    
    	if (!device_is_ready(counter_dev)) {
    		printk("device not ready.\n");
    		return 0;
    	}
    
    	counter_start(counter_dev);
    
    	alarm_cfg.flags = 0;
    	alarm_cfg.ticks = counter_us_to_ticks(counter_dev, DELAY);
    	alarm_cfg.callback = test_counter_interrupt_fn;
    	alarm_cfg.user_data = &alarm_cfg;
    
    	test_set_get_time();
    	
    	err = counter_set_channel_alarm(counter_dev, ALARM_CHANNEL_ID, &alarm_cfg);
    	printk("Set alarm in %u sec (%u ticks)\n", (uint32_t)(counter_ticks_to_us(counter_dev, alarm_cfg.ticks) / USEC_PER_SEC), alarm_cfg.ticks);
    
    	if (-EINVAL == err) {
    		printk("Alarm settings invalid\n");
    	} else if (-ENOTSUP == err) {
    		printk("Alarm setting request not supported\n");
    	} else if (err != 0) {
    		printk("Error\n");
    	}
    
    	while (1) {
    		k_sleep(K_FOREVER);
    	}
    	return 0;
    }
    

    But getting invalid time and the didn't get alarm after 4sec set.

    *** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
    Counter alarm sample

    set time 23:59:55 31:11:125
    Time 2025-12-31T23:59:55:000000
    Set alarm in 2 sec (65536 ticks)
    !!! Alarm !!!
    get time -1:-1:-1 -1:-1:-1
    Time 1899-00--1T-1:-1:-1:000000
    Now: 20
    Set alarm in 4 sec (131072 ticks)


    Is there any configuration is missing? Please advise on this.

Children
No Data
Related