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.

  • Hello,

    Sorry for late reply. I was on leave last week.

    Could you please try to use RTC2 instead of RTC0? 

  • Hi Kazi,
    I have tried RTC1 instead of RTC0. But facing below issue while compiling.

Reply Children
  • -- Found assembler: C:/ncs/toolchains/cf2149caf2/opt/zephyr-sdk/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc.exe
    CMake Warning at C:/ncs/v2.6.1/zephyr/CMakeLists.txt:862 (message):
    No SOURCES given to Zephyr library: drivers__rtc Excluding target from build.
    Dropping partition 'nonsecure_storage' since it is empty.
    -- Configuring done
    -- Generating done
    -- Build files have been written to: C:/ncs/v2.6.1/zephyr/samples/drivers/counter/alarm/build_4
    -- west build: building application
    [2/219] Generating include/generated/version.h
    -- Zephyr version: 3.5.99 (C:/ncs/v2.6.1/zephyr), build: v3.5.99-ncs1-1
    [7/219] Generating ../../tfm/CMakeCache.txt
    CMake Warning at cmake/version.cmake:22 (message):
    Actual TF-M version is not available from Git repository. Settled tov2.0.0
    Call Stack (most recent call first):CMakeLists.txt:22 (include)-- Found Git: C:/ncs/toolchains/cf2149caf2/mingw64/bin/git.exe (found version "2.37.3.windows.1")
    -- The C compiler identification is GNU 12.2.0
    -- The CXX compiler identification is GNU 12.2.0
    -- The ASM compiler identification is GNU
    -- Found assembler: C:/ncs/toolchains/cf2149caf2/opt/zephyr-sdk/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc.exe
    -- Found Python3: C:/ncs/toolchains/cf2149caf2/opt/bin/python.exe (found version "3.9.13") found components: Interpreter CMake Deprecation Warning at C:/ncs/v2.6.1/zephyr/cmake/modules/FindDeprecated.cmake:121(message):
    'PYTHON_PREFER' variable is deprecated. Please use Python3_EXECUTABLEinstead.
    Call Stack (most recent call first):
    C:/ncs/v2.6.1/zephyr/cmake/modules/python.cmake:16 (find_package)
    C:/ncs/v2.6.1/zephyr/cmake/modules/user_cache.cmake:30 (include)
    C:/ncs/v2.6.1/zephyr/cmake/modules/extensions.cmake:5 (include)
    C:/ncs/v2.6.1/nrf/subsys/nrf_security/tfm/CMakeLists.txt:38 (include) -- Found Python3: C:/ncs/toolchains/cf2149caf2/opt/bin/python.exe (found suitable version "3.9.13", minimum required is "3.8") found components: Interpreter
    -- Cache files will be written to: C:/ncs/v2.6.1/zephyr/.cache
    -- Configuring done
    -- Generating done
    CMake Warning:
    Manually-specified variables were not used by the project:CRYPTO_RNG_MODULE_ENABLED
    MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE
    PYTHON_PREFER-- Build files have been written to: C:/ncs/v2.6.1/zephyr/samples/drivers/counter/alarm/build_4/tfm
    [163/167] Linking C executable bin\tfm_s.axf
    Memory region Used Size Region Size %age Used
    FLASH: 32112 B 32 KB 98.00%
    RAM: 10416 B 32 KB 31.79%
    [15/219] Performing install step for 'tfm'
    -- Install configuration: "MinSizeRel"
    ----- Installing platform NS -----
    [137/219] Building C object CMakeFiles/app.dir/src/main.c.obj
    C:/ncs/v2.6.1/zephyr/samples/drivers/counter/alarm/src/main.c: In function 'test_counter_interrupt_fn':
    C:/ncs/v2.6.1/zephyr/samples/drivers/counter/alarm/src/main.c:77:25: warning: unused variable 'datetime_get' [-Wunused-variable]
    77 | struct rtc_time datetime_get;
    | ^~~~~~~~~~~~
    C:/ncs/v2.6.1/zephyr/samples/drivers/counter/alarm/src/main.c: In function 'test_set_get_time':
    C:/ncs/v2.6.1/zephyr/samples/drivers/counter/alarm/src/main.c:120:33: warning: unused variable 'datetime_get' [-Wunused-variable]
    120 | struct rtc_time datetime_get;
    | ^~~~~~~~~~~~
    C:/ncs/v2.6.1/zephyr/samples/drivers/counter/alarm/src/main.c: At top level:
    C:/ncs/v2.6.1/zephyr/samples/drivers/counter/alarm/src/main.c:117:13: warning: 'test_set_get_time' defined but not used [-Wunused-function]
    117 | static void test_set_get_time(void)
    | ^~~~~~~~~~~~~~~~~
    [181/219] Building C object zephyr/drivers/timer/CMakeFiles/drivers__timer.dir/nrf_rtc_timer.c.obj
    FAILED: zephyr/drivers/timer/CMakeFiles/drivers__timer.dir/nrf_rtc_timer.c.obj
    C:\ncs\toolchains\cf2149caf2\opt\zephyr-sdk\arm-zephyr-eabi\bin\arm-zephyr-eabi-gcc.exe -DKERNEL -DMBEDTLS_CONFIG_FILE=\"nrf-config.h\" -DMBEDTLS_PSA_CRYPTO_CONFIG_FILE=\"nrf-psa-crypto-want-config.h\" -DMBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE=\"nrf-psa-crypto-config.h\" -DNRF5340_XXAA_APPLICATION -DNRF_SKIP_FICR_NS_COPY_TO_RAM -DNRF_TRUSTZONE_NONSECURE -DPICOLIBC_LONG_LONG_PRINTF_SCANF -DUSE_PARTITION_MANAGER=1 -D_FORTIFY_SOURCE=1 -D_POSIX_C_SOURCE=200809 -D__LINUX_ERRNO_EXTENSIONS__ -D__PROGRAM_START -D__ZEPHYR_SUPERVISOR__ -D__ZEPHYR__=1 map=C:/ncs/v2.6.1/zephyr/samples/drivers/counter/alarm=CMAKE_SOURCE_DIR -fmacro-prefix-map=C:/ncs/v2.6.1/zephyr=ZEPHYR_BASE -fmacro-prefix-map=C:/ncs/v2.6.1=WEST_TOPDIR -ffunction-sections -fdata-sections --specs=picolibc.specs -std=c99 -MD -MT zephyr/drivers/timer/CMakeFiles/drivers__timer.dir/nrf_rtc_timer.c.obj -MF zephyr\drivers\timer\CMakeFiles\drivers__timer.dir\nrf_rtc_timer.c.obj.d -o zephyr/drivers/timer/CMakeFiles/drivers__timer.dir/nrf_rtc_timer.c.obj -c C:/ncs/v2.6.1/zephyr/drivers/timer/nrf_rtc_timer.c
    In file included from C:/ncs/v2.6.1/zephyr/include/zephyr/toolchain.h:50,
    from C:/ncs/v2.6.1/zephyr/include/zephyr/sys/util.h:18,
    from C:/ncs/v2.6.1/zephyr/include/zephyr/init.h:13,
    from C:/ncs/v2.6.1/zephyr/drivers/timer/nrf_rtc_timer.c:8:
    C:/ncs/v2.6.1/zephyr/include/zephyr/toolchain/gcc.h:87:36: error: static assertion failed: "Counter for RTC1 must be disabled"
    87 | #define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, "" MSG)
    | ^~~~~~~~~~~~~~
    C:/ncs/v2.6.1/zephyr/drivers/timer/nrf_rtc_timer.c:33:1: note: in expansion of macro 'BUILD_ASSERT'
    33 | BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(RTC_LABEL), disabled),
    | ^~~~~~~~~~~~
    [190/219] Building C object zephyr/drivers/serial/CMakeFiles/drivers__serial.dir/uart_nrfx_uarte.c.obj
    ninja: build stopped: subcommand failed.
    FATAL ERROR: command exited with status 1: 'C:\ncs\toolchains\cf2149caf2\opt\bin\cmake.EXE' --build 'c:\ncs\v2.6.1\zephyr\samples\drivers\counter\alarm\build_4'

Related