Hello guys!
We are considering using nRF52840 SoC in our future product. In that sense, we wanted to evaluate the current consumption of nRF52840 SoC in different modes of operation.
For that purpose, we created a simple Zephyr-based application (find it attached) that will do the following:
- Keep the CPU in System ON mode with RAM retention (using k_cpu_atomic_idle() API, as explained in this thread)
- Periodically wake up the CPU with kernel/RTC timer and do some processing in active mode. According to this thread, Zephyr's kernel timer is using the RTC of nRF52840 SoC.
We were also trying to set the nRF52840 SoC in both Normal Voltage and High Voltage modes by using the following setup (the HW setup should be OK according to these threads thread_1, thread_2):
The application has been compiled and flashed using nRF Connect SDK v2.1.0 and it behaves as expected. This table summarizes measured current consumptions for different configurations and modes of operation compared to the values reported in nRF52840 product specification (see page 61, CPU running):
If we compare the current consumption values, we can see that our numbers are greater. This is especially true for the Normal Voltage mode with DC/DC regulator enabled (3.3mA vs 6.63mA)
Do you have any idea what we are missing here?
Thanks in advance for your time and efforts.
/* * Copyright (c) 2012-2014 Wind River Systems, Inc. * * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr/zephyr.h> static struct k_sem my_sem; void my_work_handler(struct k_work *work) { k_sem_give(&my_sem); } K_WORK_DEFINE(my_work, my_work_handler); void my_timer_handler(void *unused) { k_work_submit(&my_work); } K_TIMER_DEFINE(my_timer, my_timer_handler, NULL); static volatile uint32_t active_cnt = 0; void main(void) { k_sem_init(&my_sem, 0, 1); /* start periodic timer */ k_timer_start(&my_timer, K_SECONDS(3), K_SECONDS(3)); uint8_t cnt = 0; /* Set output voltage from REG0 regulator stage to 1.8V */ NRF_UICR->REGOUT0 = 0; /* Set REG0 stage */ NRF_POWER->DCDCEN0 = 1; /* Set REG1 stage */ NRF_POWER->DCDCEN = 1; printk("MAINREGSTATUS: 0x%X\n", NRF_POWER->MAINREGSTATUS); printk("DCDCEN: 0x%X\n", NRF_POWER->DCDCEN); printk("DCDCEN0: 0x%X\n", NRF_POWER->DCDCEN0); for (;;) { unsigned int key = irq_lock(); /* * Wait for semaphore from ISR; if acquired, do related work, then * go to next loop iteration (the semaphore might have been given * again); else, make the CPU idle. */ if (k_sem_take(&my_sem, K_NO_WAIT) == 0) { irq_unlock(key); /* ... do processing */ printk("Hello World! %s\n", CONFIG_BOARD); for(uint32_t i = 0; i < UINT16_MAX; i++){ ++active_cnt; } } else { // printk("Preparing to enter idle...\n"); cnt++; /* put CPU to sleep to save power */ k_cpu_atomic_idle(key); printk("Counter: %d\n", cnt); } } }