Spikes in current consumption after using semaphores





can anyone tell me what are these spikes

i am some part of my code:

_SPRINTLN(DEBUG_INFO, "LOW-PWR-SYS-ON"); // debug log to show device will enter standby state

        // turn off peripherals
        pm_device_action_run(uart_dev, PM_DEVICE_ACTION_SUSPEND);
        pm_device_action_run(adc_dev, PM_DEVICE_ACTION_SUSPEND);

        // Block (sleep) the main thread, it will wake up on GPIO interrupt or timer timeout
        k_sem_take(&main_sem, K_FOREVER);

        pm_device_action_run(uart_dev, PM_DEVICE_ACTION_RESUME);
        pm_device_action_run(adc_dev, PM_DEVICE_ACTION_RESUME);

Parents
  • Hello,

    As far as I can tell, you have the same spikes in the first and second screenshot, but that is perhaps what you intended? 

    I need a bit more context. Perhaps you can upload the application you used in your measurements?

    It is an event happening every 4 seconds, so perhaps some timer waking up the CPU every 4 seconds?

    Best regards,

    Edvin

  • Hello Edvin 
    i want to send zip file of my application how can i do that?

  •  
    kindly go through below explanation:


    Description:

    I am working on an application using nRF52811 with a LoRa modem. The application handles two scenarios, Case 1 and Case 2, both leveraging Zephyr and the system off mode for ultra-low power consumption. However, I have observed unexpected behavior regarding current consumption after GPIO interrupts in Case 1.


    Observed Behavior:

    • Case 1: After waking up the main thread via GPIO interrupt and entering system-off mode, the current consumption is 300–450 µA, significantly higher than expected.
    • Case 2: Directly entering system-off mode results in current consumption of ~2.5 µA, which is expected.

    There is a significant difference in current consumption between these two cases in system-off mode.


    Application Details:

    Hardware Setup:

    • nRF52811 microcontroller.
    • LoRa modem connected to the nRF52811.

    Test Code:

    #include "inc/util.h"
    #include "inc/du_radio_hal.h"
    #include <zephyr/kernel.h>
    
    #define CASE 2
    
    int main()
    {
            // Configure LEDs
            led_init();
            // Indicate booting by LEDs
            led_on_boot();
            // Initialize the radio device
            du_radio_init();
            // Initialize GPIO pins and interrupts
            pins_init();
    
            k_sleep(K_SECONDS(5));
    
    #if CASE == 1
            shutdown_cpu(DU_SLEEP_STANDBY);
    
            while (true)
            {
                    shutdown_cpu(DU_SLEEP_SHUTDOWN);
            }
    #elif CASE == 2
            while (true)
            {
                    shutdown_cpu(DU_SLEEP_SHUTDOWN);
            }
    
    #endif
    }
    

    Test Cases:

    Case 1: GPIO Wakeup Path

    1. The main thread sleeps and is configured to wake up via GPIO interrupt.
    2. Upon a button press, the system wakes up and the main thread executes.
    3. After waking, the system is placed into system-off mode using shutdown_cpu(DU_SLEEP_SHUTDOWN).

    Result: Current consumption in system-off mode is ~300–450 µA.

    Case 2: Direct Shutdown

    1. The application directly enters system-off mode without waking the main thread.

    Result: Current consumption in system-off mode is ~2.5 µA.


    Attachments:

    1. Test Code: test-code.zip
    2. Case 1 Current Consumption Measurements: case-1-current.zip
    3. Case 2 Current Consumption Measurements: case-2-current.zip

    Expected Behavior:

    The current consumption in system-off mode for Case 1 should be consistent with Case 2, i.e., ~2.5 µA.


    Possible Cause and Questions:

    1. Could the GPIO wakeup interrupt be leaving peripherals or components (e.g., clocks, peripherals, or the LoRa modem) enabled, causing higher current consumption?
    2. Are there any additional steps required to properly power down the device after a GPIO interrupt?
    3. Is there an internal state in the nRF52811 that might differ between direct shutdown and wake-up via GPIO?

    Request for Help:

    • Guidance on why the current consumption differs between the two cases.
    • Suggestions for debugging and ensuring all peripherals are properly powered down in Case 1.
    • Any specific configurations or settings required in Zephyr to handle GPIO wakeup followed by system-off mode efficiently.




      I hope this will provide some more insights about this issue.
  • What NCS version are you using? Are you able to build the attached project for nrf52840dk_nrf52811? I am not, but perhaps I am using the wrong NCS version. 

    I could of course fix the errors, but then it is not certain we are debugging the same application anymore. 

    Best regards,

    Edvin

  • Hello,

    I have tried your code, but I am not able replicate what you are seeing. I see some different behavior in mode 1 and mode 2, but I don't have the Lora radio that you are using, so I needed to strip out that part. 

    As far as I can tell, the only difference between mode 1 and 2 is that you call shutdown_cpu(DU_SLEEP_STANDBY); in mode 1. It doesn't look like that one returns, but it is stuck in there for some reason. Does it return in your case?

    Do you have something that I can use to replicate your issue on an nRF52840 DK?

    Best regards,

    Edvin

Reply
  • Hello,

    I have tried your code, but I am not able replicate what you are seeing. I see some different behavior in mode 1 and mode 2, but I don't have the Lora radio that you are using, so I needed to strip out that part. 

    As far as I can tell, the only difference between mode 1 and 2 is that you call shutdown_cpu(DU_SLEEP_STANDBY); in mode 1. It doesn't look like that one returns, but it is stuck in there for some reason. Does it return in your case?

    Do you have something that I can use to replicate your issue on an nRF52840 DK?

    Best regards,

    Edvin

Children
  • Also, while I remember, have you tried removing 

    CONFIG_PM=y

    from your prj.conf? I get a warning when this is enabled. I see that you also have CONFIG_PM_DEVICE=y. That is the correct one.

    Best regards,

    Edvin

  • I have applied below changes in mode=1 and did not see any raise in current once it enters into SYSTEM_OFF mode.

    void shutdown_cpu(bool mode)
    {
        led_ctrl(HIGH, HIGH, HIGH);
        du_radio_sleep(DU_SLEEP_SHUTDOWN);
        sx126x_hal_deinit();
    
        // clear all the wakeup reasons before going to sleep
        clear_wakeup_reason();
    
        // get zephyr-console pointer:
        const struct device *uart_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
    
        if (mode)
        {
            _SPRINTLN(DEBUG_INFO, "LOW-PWR-SYS-OFF"); // debug log to show device will enter shutdown state
            gf_pwr_once = 0;
    
            // Disable the UART, SPI, I2C, and other communication peripherals
            NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Disabled;
            NRF_SPI0->ENABLE = SPI_ENABLE_ENABLE_Disabled;
            NRF_TWI0->ENABLE = TWI_ENABLE_ENABLE_Disabled;
    
            // Disable the ADC (if enabled)
            NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Disabled;
    
            // Disable RTC
            NRF_RTC0->TASKS_STOP = 1;
    
            // Disable timers
            NRF_TIMER0->TASKS_STOP = 1;
    
            // Disable PWM
            NRF_PWM0->ENABLE = PWM_ENABLE_ENABLE_Disabled;
    
            // Disable the radio (Bluetooth)
            NRF_RADIO->POWER = RADIO_POWER_POWER_Disabled;
    
            // Disable the CPU clock and enter low power mode
            NRF_POWER->TASKS_LOWPWR = 1;
    
            // Enter System OFF mode
            NRF_POWER->SYSTEMOFF = 1; // This will cause the chip to enter System OFF mode
        }
        else
        {
            _SPRINTLN(DEBUG_INFO, "LOW-PWR-SYS-ON"); // debug log to show device will enter standby state
    
            // turn off peripherals
            pm_device_action_run(uart_dev, PM_DEVICE_ACTION_SUSPEND);
            // Disable the UART, SPI, I2C, and other communication peripherals
    
            NRF_SPI0->ENABLE = SPI_ENABLE_ENABLE_Disabled;
            NRF_TWI0->ENABLE = TWI_ENABLE_ENABLE_Disabled;
    
            // Disable the ADC (if enabled)
            NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Disabled;
    
            // Disable RTC
            NRF_RTC0->TASKS_STOP = 1;
    
            // Disable timers
            NRF_TIMER0->TASKS_STOP = 1;
    
            // Disable PWM
            NRF_PWM0->ENABLE = PWM_ENABLE_ENABLE_Disabled;
    
            // Disable the radio (Bluetooth)
            NRF_RADIO->POWER = RADIO_POWER_POWER_Disabled;
    
            // Disable the CPU clock and enter low power mode
            NRF_POWER->TASKS_LOWPWR = 1;
    
            // If 'use_timer' is true, it means we want to use the timer to wake up the device after 'RTC_TIME' seconds.
            // This will block the main thread until the timer expires or an interrupt occurs (based on the RTC_TIME).
            if (use_timer)
            {
    
                // Wait for the semaphore to be given, with a timeout of 'RTC_TIME' seconds.
                // If the semaphore is not given within this period, it means a timeout has occurred.
                int ret = k_sem_take(&main_sem, K_SECONDS(RTC_TIME)); // Store the return value for error handling
    
                // Error handling based on the return value of k_sem_take:
                if (ret == 0)
                {
                    // Semaphore successfully taken, no timeout occurred
                    timeout_flag = false; // Reset the timeout flag
                }
                else if (ret == -EBUSY)
                {
                    // The semaphore was already taken (not a typical case for k_sem_take with timeout)
                    _SPRINTLN(DEBUG_ERROR, "Semaphore already taken. This should not happen.");
    
                    k_msleep(5000);
                    k_sem_take(&main_sem, K_SECONDS(RTC_TIME));
                }
                else if (ret == -EAGAIN)
                {
                    // Timeout occurred
                    timeout_flag = true; // Set the timeout flag to indicate the timer has expired
                    _SPRINTLN(DEBUG_WARNING, "Timer expired without semaphore being taken.");
                }
                else
                {
                    // Catch any other unexpected error codes
                    _SPRINTLN(DEBUG_ERROR, "Unexpected error during semaphore take operation: %d", ret);
                    k_msleep(5000);
                    k_sem_take(&main_sem, K_SECONDS(RTC_TIME));
                }
            }
            else
            {
                // If 'use_timer' is false, block the main thread indefinitely until a GPIO interrupt occurs.
                // The main thread will wake up when a semaphore is given by an ISR.
                int ret = k_sem_take(&main_sem, K_FOREVER); // Store the return value for error handling
    
                // Error handling based on the return value of k_sem_take:
                if (ret != 0)
                {
                    // If we exit unexpectedly (e.g., an ISR failure or other issue), log the error
                    _SPRINTLN(DEBUG_ERROR, "Failed to take semaphore with indefinite wait.");
                    k_msleep(5000);
                    k_sem_take(&main_sem, K_FOREVER);
                }
            }
    
            pm_device_action_run(uart_dev, PM_DEVICE_ACTION_RESUME);
        }
    
        adc_init();
    
        // lines to be executed after wakeup:
        du_radio_init();
        du_radio_sleep(DU_SLEEP_STANDBY);
        _SPRINTLN(DEBUG_CRITICAL, "WAKE-UP");
        k_msleep(100); // Simultaneous Button press
    }

  • CONFIG_PM=y
    This line does not seem to be doing anything.

  • Again original issue which was associated with spikes in current consumption while main thread is sleeping or blocked with use of semaphore is unresolved
    +
    Plus current consumption of overall pcb is ~10 uA, where nrf52811 SoC is consuming around ~7 uA.

    For this refer mode=0.

Related