NRF9160 unexpected exit of idle state (periodic wake up every3m40s and 4m50s)

Hi !

I've been through a lot of documentation but did not find any matching my case.

I'm using a custom board with an NRF9160 chosen for its ability to connect to LTE.

I'm developping under NCS v3.0.2.

In this project, few things are wired on the NRF9160 :

  • a PIR sensor on a GPIO which is supposed to be my only wake-up source.
  • 5 GPIO driving mosfets for LEDs and peripherals' powers
  • 3 UARTS : UART0 for debug, UART2 for a sensor (DFRobot A01NYUB) along with one GPIO managing the power of this sensor, and UART1 for another microcontroller along with one GPIO managing the Enable PIN of this microcontroller.

My application is some sort of IoT project that may be sleeping for 3-5 days and can be awaken up to 10 times a day.

Now my problem seems odd because of the very specific time spent between two wake-ups : alternatively 3 minutes and 40 seconds and 4 minutes and 50 seconds. I tell it here because maybe it rings a bell regarding some typical Zephyr timers or modem's cycle ?

As far as I know, I properly cut RX irq on UART1 and I disable the other microcontroller with its Enable PIN so it's unlikely to send anything.

I don't have any other thread but the main one (I declare and abort some to make LEDs blink and I faced the issue once when I forgot to abort one but then my app woke up instantly).

I hope I cut the modem the best I can (I don't use GNSS yet, I'm calling lte_lc_power_off(), and I even tried to NOT initialize the nrf_modem library or anything related but the problem was still there.

Here is my prj.conf :

# Enable MPU
CONFIG_ARM_MPU=y

# Enable hardware stack protection
CONFIG_HW_STACK_PROTECTION=y

# Enable TrustZone-M
CONFIG_ARM_TRUSTZONE_M=y

# Stacks and heaps
CONFIG_MAIN_STACK_SIZE=3072
CONFIG_HEAP_MEM_POOL_SIZE=16384

#Power Management
CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=n

#DEBUG
CONFIG_USE_SEGGER_RTT=n
CONFIG_RTT_CONSOLE=n

#CONSO
CONFIG_POWEROFF=y

#UART
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_UART_ASYNC_API=y
CONFIG_UART_1_INTERRUPT_DRIVEN=n
CONFIG_UART_1_ASYNC=y
CONFIG_UART_NRFX_UARTE_ENHANCED_RX=n
CONFIG_UART_1_NRF_HW_ASYNC=y
CONFIG_UART_1_NRF_HW_ASYNC_TIMER=1
CONFIG_NRFX_TIMER1=y

#LOG
CONFIG_LOG=y

# Modem library
# CONFIG_TRUSTED_EXECUTION_NONSECURE=y
CONFIG_NRF_MODEM_LIB=y
CONFIG_NRF_MODEM_LIB_ON_FAULT_RESET_MODEM=y
CONFIG_MODEM_KEY_MGMT=y
CONFIG_DATE_TIME=y

# Network
CONFIG_NETWORKING=y
CONFIG_NET_NATIVE=n
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_OFFLOAD=y
CONFIG_POSIX_API=y
# CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_NET_IPV4=y
# CONFIG_NET_TCP=y
CONFIG_NET_IPV6=y
CONFIG_NET_CONNECTION_MANAGER=y
CONFIG_NET_CONNECTION_MANAGER_MONITOR_STACK_SIZE=1024
# CONFIG_NET_LOG=y
# CONFIG_NET_SOCKETS_LOG_LEVEL_DBG=y
# CONFIG_LTE_LINK_CONTROL_LOG_LEVEL_DBG=y

# LTE link control
CONFIG_LTE_LINK_CONTROL=y

# Disable Modem traces, since we need UART1 for HCI
CONFIG_NRF_MODEM_LIB_TRACE=n

# HTTP
CONFIG_HTTP_CLIENT=y
CONFIG_HW_ID_LIBRARY=y
CONFIG_HW_ID_LIBRARY_SOURCE_DEVICE_ID=y

# A01NYUB
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_SENSOR=y
CONFIG_A01NYUB=y
CONFIG_CBPRINTF_FP_SUPPORT=y

# SEN0381
CONFIG_GPIO=y

# LIBC
CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=4096
CONFIG_CBPRINTF_FP_SUPPORT=y

# CRYPTO
CONFIG_MBEDTLS=y
CONFIG_MBEDTLS_LEGACY_CRYPTO_C=y
CONFIG_MBEDTLS_SHA256_C=y
CONFIG_MBEDTLS_HMAC_DRBG_C=y
CONFIG_MBEDTLS_MD_C=y
CONFIG_MBEDTLS_CIPHER_C=y
CONFIG_MBEDTLS_ENABLE_HEAP=y
CONFIG_MBEDTLS_HEAP_SIZE=8192

CONFIG_TICKLESS_KERNEL=y

My program is sequential : the only living sensor throws an interrupt that awakens my NRF9160, I power up some device and the other microcontroller, and if nothing happens for 30 seconds, I cut the device's power, call lte_lc_poweroff, stop UART1 RX, disable the other microcontroller, wait for 2 seconds and call k_cpu_idle.

That's it for the nominal use case and yet the problem appears.

Now I've been through lots of tests to identify my wake-up source :

  1. Listing enabled IRQs right before k_cpu_idle and tracing wake-up source with
    for (int i = 0; i < 128; i++) {
        if (NVIC->ISER[i >> 5] & (1 << (i & 0x1F))) {
            printk("IRQ %d enabled\n", i);
        }
    }
    k_sleep(K_MSEC(2000));
    k_cpu_idle();
    uint32_t icsr = SCB->ICSR;
    int irq = (int)(icsr & SCB_ICSR_VECTACTIVE_Msk);
    irq -= 16;
    if(irq>=0) LOG_INF("Leaving idle because of IRQ %d", irq);
    else LOG_INF("Leaving idle because of internal exception (vect %d)", irq);
    printk("ICSR = 0x%08x (VECTACTIVE = %d)\n", SCB->ICSR, (int)(SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk));

    Resulting in IRQs 5, 8, 9, 10, 16, 21, 42 and 49 listed and
    <inf> main: Leaving idle because of internal exception (vect -16)
    ICSR = 0x00000000 (VECTACTIVE = 0)
  2. Consecutively to this trial and the result, I added CONFIG_TICKLESS_KERNEL=y in my prj.conf
  3. Then I added
    printk("EVENTS_PORT=%d\n", NRF_GPIOTE->EVENTS_PORT);
    printk("RTC0->EVENTS_COMPARE[0]=%d\n", NRF_RTC0->EVENTS_COMPARE[0]);
    printk("RTC0->EVTENSET=0x%08x\n", NRF_RTC0->EVTENSET);

    Result :
    EVENTS_PORT=0
    RTC0->EVENTS_COMPARE[0]=0
    RTC0->EVTENSET=0x00000000
  4. Then I tried logging Systick with
    printk("SysTick CTRL: 0x%08lx\n", SysTick->CTRL);
    printk("SysTick LOAD: %lu\n", SysTick->LOAD);
    

    and got : CTRL:0x04  LOAD:0
  5. I tried adding an irq_trap and failed at compile time using
    #include <zephyr/kernel.h>
    #include <zephyr/logging/log.h>
    LOG_MODULE_REGISTER(irqcatch, LOG_LEVEL_INF);
    
    void irq_trap(const void *arg)
    {
        uint32_t irqn = (uint32_t)arg;
        LOG_INF("=== IRQ %u triggered ===", irqn);
    }
    
    #define REPLACE_IRQ(n) \
        Z_ISR_DECLARE(n, 0, irq_trap, (void *)n)
    
    REPLACE_IRQ(0);
    REPLACE_IRQ(1);
    REPLACE_IRQ(2);
    REPLACE_IRQ(3);
    REPLACE_IRQ(4);
    REPLACE_IRQ(5);
    REPLACE_IRQ(6);
    REPLACE_IRQ(7);
    REPLACE_IRQ(8);
    REPLACE_IRQ(9);
    REPLACE_IRQ(10);
    REPLACE_IRQ(11);
    REPLACE_IRQ(12);
    REPLACE_IRQ(13);
    REPLACE_IRQ(14);
    REPLACE_IRQ(15);
    
  6. I then tried adding an idle_exit trap that was never called using 
    #include <zephyr/kernel.h>
    #include <zephyr/pm/pm.h>
    #include <zephyr/logging/log.h>
    
    LOG_MODULE_REGISTER(wakeup, LOG_LEVEL_INF);
    
    void sys_pm_notify_power_state_exit(enum pm_state state,
                                        uint8_t substate_id)
    {
        ARG_UNUSED(state);
        ARG_UNUSED(substate_id);
    
        uint32_t icsr = SCB->ICSR;
        uint32_t vect = (icsr & SCB_ICSR_VECTACTIVE_Msk);
    
        if (vect == 0) {
            LOG_INF("Wakeup from WFI without active IRQ (vect = -16). ICSR=0x%08x", icsr);
        } else {
            LOG_INF("Wakeup caused by IRQ %u", vect - 16);
        }
    }
    
  7. In the middle of all that I just added CONFIG_PM_DEVICE=y in the prj.conf, thus adding missing sleep pinctrls in the devicetree to have it compile.
  8. I tried another idle_exit trap with
    #include <zephyr/kernel.h>
    #include <zephyr/logging/log.h>
    #include <zephyr/arch/arm/aarch32/cortex_m/cmsis.h>
    
    LOG_MODULE_REGISTER(idletrace, LOG_LEVEL_INF);
    
    void z_arm_idle(unsigned int cpu)
    {
        ARG_UNUSED(cpu);
    
        /* Just before WFI */
        __DSB();
        __WFI();
        __ISB();
    
        /* Just after wakeup */
        uint32_t icsr = SCB->ICSR;
        uint32_t vect = (icsr & SCB_ICSR_VECTACTIVE_Msk);
    
        if (vect == 0) {
            LOG_INF("Wake from idle: no active IRQ (vect=-16) ICSR=0x%08x", icsr);
        } else {
            uint32_t irq = vect - 16;
            LOG_INF("Wake from idle: IRQ %u", irq);
        }
    }
    

    which gave me nothing.
  9. I've been told to look into IPC which I tried disabling in the devicetree
  10. I've been told to look into DPPI, GPIOTE or EGU events (I haven't done that yet, except for GPIOTE with some printk shown above).

Now I'm stuck and still have no idea what is the root cause of my wake-up with those silly timings of 3m40s and 4m50s ...

So I do hope it rings a bell, or obtain some kind of procedure to trace back in the best possible way a wake-up cause when using k_cpu_idle (which I hope will help not only me, given the amount of topics about nrf9160 and low power).

I thank you in advance and I'm really looking forward to hear from you.

Best regards,

Guillaume

Parents Reply Children
No Data
Related