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

osEventFlagsSet() after osKernelSuspend() in RTOS2 tick-less operation

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

Parents Reply Children
No data