Hi all,
I'm implementing a low power application based on CMSIS RTOS2 with ATSAML22 MCU. I have an RTOS2 tick-less operation like this:
// OS Idle Thread __NO_RETURN void osRtxIdleThread (void *argument) { (void)argument; for (;;) { // Returns OS ticks to sleep osTickSleep = osKernelSuspend(); if (osTickSleep > 0) { // Is there some time to sleep? // Start the wake up timer WakeUp_TIMER_Start(); // Enter the low power state LowPower_MCU_Enter(); #ifdef __DEBUG__ // Go to IDLE mode _set_sleep_mode(2); #endif /* #ifdef __DEBUG__ */ #ifdef __RELEASE__ // Go to SLEEP mode _set_sleep_mode(4); #endif /* #ifdef __RELEASE__ */ __DSB(): __WFI(); __NOP(); // Leave the low power state LowPower_MCU_Exit(); // Check if wake up timer interrupt happened WakeUp_TIMER_Check(); // Calculate how long we slept osTickSleep = (dwWakeUpTimerValue * OS_TICK_FREQ + (WAKE_UP_TIMER_CLOCK - 1U)) / WAKE_UP_TIMER_CLOCK; } // Adjust the kernel ticks with the amount of ticks slept osKernelResume(osTickSleep); } } /* END of function osRtxIdleThread */
When an interrupt is fired while in stop mode I can wakeup and continue working in my app. But the problem is when the interrupt is fired between osKernelSuspend() and go to sleep. The interrupt have is like this:
void IRQHandler (void) { osEventFlagsSet(evt_id, EVT_FLAG_1); }
Theorically, when the IRQHandler() is fired the thread which is waiting for the event is resumed from blocked state. But if the IRQHandler() is fired between osKernelSuspend() and go to sleep the thread is not resumed and the MCU enters in sleep. I know that the solution should be to use WFE instead of WFI but it seems that ATSAML22 MCU does not support the WFE instruction and I fixed the idle thread like:
// OS Idle Thread __NO_RETURN void osRtxIdleThread (void *argument) { (void)argument; for (;;) { // Get enabled IRQs in NVIC uint32_t dwEnableIRQn = NVIC->ISER[0]; // Disable all IRQs in NVIC NVIC->ICER[0] = 0xFFFFFFFF; __DSB(); __ISB(); // Returns OS ticks to sleep osTickSleep = osKernelSuspend(); if (osTickSleep > 0) { // Is there some time to sleep? // Start the wake up timer WakeUp_TIMER_Start(); // Enter the low power state LowPower_MCU_Enter(); #ifdef __DEBUG__ // Go to IDLE mode _set_sleep_mode(2); #endif /* #ifdef __DEBUG__ */ #ifdef __RELEASE__ // Go to SLEEP mode _set_sleep_mode(4); #endif /* #ifdef __RELEASE__ */ // Some IRQ pending? if (NVIC->ISPR[0] == 0) { // Re-Enable IRQs in NVIC __COMPILER_BARRIER(); NVIC->ISER[0] = dwEnableIRQn; __COMPILER_BARRIER(); _go_to_sleep(); } __NOP(); // Leave the low power state LowPower_MCU_Exit(); // Check if wake up timer interrupt happened WakeUp_TIMER_Check(); // Calculate how long we slept osTickSleep = (dwWakeUpTimerValue * OS_TICK_FREQ + (WAKE_UP_TIMER_CLOCK - 1U)) / WAKE_UP_TIMER_CLOCK; } // Adjust the kernel ticks with the amount of ticks slept osKernelResume(osTickSleep); // Re-Enable IRQs in NVIC __COMPILER_BARRIER(); NVIC->ISER[0] = dwEnableIRQn; __COMPILER_BARRIER(); } } /* END of function osRtxIdleThread */
Is it a good solution? Or, how can I know if there is any thread right now in ready state to avoid enter in stop mode?
Best regards
Fabrizio
Please repost this question in the below link:
github.com/.../issues