This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Apollo3 Keil rt_suspend results in high current draw

System:

- Keil MDK

- Apollo3 MCU

- Keil RTX

- Arm compiler 5.06 Update 6 (build 750)

Problem:
Inside keil rtx function: os_idle_demon we suspend rtos and then enter deepsleep mode

But, it looks like calling rt_suspend inside os_idle_demon results in 90 uA current draw, preventing deepsleep mode current savings (we should only be seeing around 10uA current)

Function:

/// \brief The idle demon that runs when no other thread is ready to run
void os_idle_demon (void) 
{
   for (;;)
   {
      _mcu_manage_idle();
   }
}


static inline void _mcu_manage_idle(void)
{
    extern const uint32_t k_stimer_ticks_per_rtos_tick; // defined in RTX_Conf_CM.c
    uint32_t rtos_ticks_to_sleep;
    uint32_t rt_suspend(void); // defined in RTX, avoid using os_suspend because it sets event register

    // We need to do this BASEPRI+WFE because
    //
    // a) If we call os_suspend(), and an interrupt that triggers thread work 
    //    occurs, there might be a chance that we mistakenly enter deep sleep
    //    even though there is work to do.
    //
    // b) We can't call os_suspend() with IRQs disabled, because os_suspend()
    //    makes an SVC call and will HardFault if IRQs are disabled.
    //
    // c) We can call rt_suspend() (which is what os_suspend() calls internally)
    //    but we have to set BASEPRI to ensure that SysTick/PendSV does not
    //    inadvertently run and corrupt RTOS state while rt_suspend() modifies it.
    //
    // d) This leaves us with the issue of an IRQ being triggered while this is
    //    all occurring. To solve this, we use the WFE instruction instead of the
    //    WFI instruction. This will ensure that if an IRQ is triggered, the next
    //    WFE instruction will simply clear the event register without putting
    //    the CPU to sleep, because any IRQ sets the event register when it is
    //    triggered.

    __set_BASEPRI(0xFF); // prevent PendSV from being handled
    rtos_ticks_to_sleep = rt_suspend();
    __set_BASEPRI(0); // _enable_irq() ?
    if (0 == rtos_ticks_to_sleep)
    {
        goto do_resume;
    }

    { // bracket avoids "bypassed initialization" warnings from goto do_resume

    // Configure STIMER B/1 to wake us up
    // Don't use STIMER A/0 because RTX is already using that IRQ handler
    const uint32_t stimer_sleep_start = am_hal_stimer_counter_get();
    const uint32_t stimer_sleep_max = 0x80000000u / k_stimer_ticks_per_rtos_tick * k_stimer_ticks_per_rtos_tick;    // round down to whole RTOS tick
    const uint64_t stimer_sleep_ticks64 = (uint64_t)k_stimer_ticks_per_rtos_tick * (uint64_t)rtos_ticks_to_sleep;
    const uint32_t stimer_sleep_ticks = stimer_sleep_ticks64 < stimer_sleep_max ? stimer_sleep_ticks64 : stimer_sleep_max;
    am_hal_stimer_int_enable(AM_HAL_STIMER_INT_COMPAREB);
    am_hal_stimer_int_clear(AM_HAL_STIMER_INT_COMPAREB);
    am_hal_stimer_compare_delta_set(1, stimer_sleep_ticks);
    NVIC_SetPriority(STIMER_CMPR1_IRQn, 0xFF);
    NVIC_EnableIRQ(STIMER_CMPR1_IRQn);

    /////////////////// ENTER SLEEP

    disable_some_peripherals(); // i2c, spi ..etc
    
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    __WFE();
    
    enable_some_peripherals(); 
    
    /////////////////// EXIT SLEEP


    // Figure out how long we stopped.
    const uint32_t stimer_sleep_end = am_hal_stimer_counter_get();
    rtos_ticks_to_sleep = ((stimer_sleep_end - stimer_sleep_start) + (k_stimer_ticks_per_rtos_tick / 2)) / k_stimer_ticks_per_rtos_tick;
    
    // Disable STIMER B/1 now that we're done with it.
    NVIC_DisableIRQ(STIMER_CMPR1_IRQn);
    am_hal_stimer_int_disable(AM_HAL_STIMER_INT_COMPAREB);
    } // avoid warnings from goto do_resume
    
do_resume:
    os_resume(rtos_ticks_to_sleep); // start scheduler back up and inform how many ticks surpassed.
    __SEV(); 
    __WFE();               // clear CPU event flag
}

Why is rt_suspend causing such (relatively) high current draw and how can we fix this?