mirror of
				https://github.com/FreeRTOS/FreeRTOS-Kernel.git
				synced 2025-11-04 02:32:42 -05:00 
			
		
		
		
	Rework the low power demo that uses the RTCC clock on the Pearl Gecko, and add attentional test code.
This commit is contained in:
		
							parent
							
								
									8ffe75f665
								
							
						
					
					
						commit
						9f5095f6bd
					
				
					 1 changed files with 86 additions and 42 deletions
				
			
		| 
						 | 
					@ -79,6 +79,7 @@
 | 
				
			||||||
#include "em_rtcc.h"
 | 
					#include "em_rtcc.h"
 | 
				
			||||||
#include "em_rmu.h"
 | 
					#include "em_rmu.h"
 | 
				
			||||||
#include "em_int.h"
 | 
					#include "em_int.h"
 | 
				
			||||||
 | 
					#include "em_letimer.h"
 | 
				
			||||||
#include "sleep.h"
 | 
					#include "sleep.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* SEE THE COMMENTS ABOVE THE DEFINITION OF configCREATE_LOW_POWER_DEMO IN
 | 
					/* SEE THE COMMENTS ABOVE THE DEFINITION OF configCREATE_LOW_POWER_DEMO IN
 | 
				
			||||||
| 
						 | 
					@ -88,6 +89,11 @@ in the RTOS port layer.  Therefore only build this file if the low power demo
 | 
				
			||||||
is being built. */
 | 
					is being built. */
 | 
				
			||||||
#if( configCREATE_LOW_POWER_DEMO == 1 )
 | 
					#if( configCREATE_LOW_POWER_DEMO == 1 )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* When lpUSE_TEST_TIMER is 1 a second timer will be used to bring the MCU out
 | 
				
			||||||
 | 
					of its low power state before the expected idle time has completed.  This is
 | 
				
			||||||
 | 
					done purely for test coverage purposes. */
 | 
				
			||||||
 | 
					#define lpUSE_TEST_TIMER	( 0 )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* The RTCC channel used to generate the tick interrupt. */
 | 
					/* The RTCC channel used to generate the tick interrupt. */
 | 
				
			||||||
#define lpRTCC_CHANNEL		( 1 )
 | 
					#define lpRTCC_CHANNEL		( 1 )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -191,12 +197,22 @@ void vPortSetupTimerInterrupt( void )
 | 
				
			||||||
	NVIC_EnableIRQ( RTCC_IRQn );
 | 
						NVIC_EnableIRQ( RTCC_IRQn );
 | 
				
			||||||
	RTCC_IntEnable( RTCC_IEN_CC1 );
 | 
						RTCC_IntEnable( RTCC_IEN_CC1 );
 | 
				
			||||||
	RTCC_Enable( true );
 | 
						RTCC_Enable( true );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#if( lpUSE_TEST_TIMER == 1 )
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							void prvSetupTestTimer( void );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* A second timer is used to test the path where the MCU is brought out
 | 
				
			||||||
 | 
							of a low power state by a timer other than the tick timer. */
 | 
				
			||||||
 | 
							prvSetupTestTimer();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/*-----------------------------------------------------------*/
 | 
					/*-----------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
 | 
					void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCountBeforeSleep, ulCountAfterSleep;
 | 
					uint32_t ulReloadValue, ulCompleteTickPeriods, ulCountAfterSleep;
 | 
				
			||||||
eSleepModeStatus eSleepAction;
 | 
					eSleepModeStatus eSleepAction;
 | 
				
			||||||
TickType_t xModifiableIdleTime;
 | 
					TickType_t xModifiableIdleTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -221,17 +237,9 @@ TickType_t xModifiableIdleTime;
 | 
				
			||||||
	/* Stop the RTC momentarily.  The time the RTC is stopped for is accounted
 | 
						/* Stop the RTC momentarily.  The time the RTC is stopped for is accounted
 | 
				
			||||||
	for as best it can be, but using the tickless mode will inevitably result
 | 
						for as best it can be, but using the tickless mode will inevitably result
 | 
				
			||||||
	in some tiny drift of the time maintained by the kernel with respect to
 | 
						in some tiny drift of the time maintained by the kernel with respect to
 | 
				
			||||||
	calendar time.  The count is latched before stopping the timer as stopping
 | 
						calendar time. */
 | 
				
			||||||
	the timer appears to clear the count. */
 | 
					 | 
				
			||||||
	ulCountBeforeSleep = RTCC_CounterGet();
 | 
					 | 
				
			||||||
	RTCC_Enable( false );
 | 
						RTCC_Enable( false );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If this function is re-entered before one complete tick period then the
 | 
					 | 
				
			||||||
	reload value might be set to take into account a partial time slice, but
 | 
					 | 
				
			||||||
	just reading the count assumes it is counting up to a full ticks worth - so
 | 
					 | 
				
			||||||
	add in the difference if any. */
 | 
					 | 
				
			||||||
	ulCountBeforeSleep += ( ulReloadValueForOneTick - RTCC_ChannelCCVGet( lpRTCC_CHANNEL ) );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Enter a critical section but don't use the taskENTER_CRITICAL() method as
 | 
						/* Enter a critical section but don't use the taskENTER_CRITICAL() method as
 | 
				
			||||||
	that will mask interrupts that should exit sleep mode. */
 | 
						that will mask interrupts that should exit sleep mode. */
 | 
				
			||||||
	INT_Disable();
 | 
						INT_Disable();
 | 
				
			||||||
| 
						 | 
					@ -249,20 +257,16 @@ TickType_t xModifiableIdleTime;
 | 
				
			||||||
	eSleepAction = eTaskConfirmSleepModeStatus();
 | 
						eSleepAction = eTaskConfirmSleepModeStatus();
 | 
				
			||||||
	if( eSleepAction == eAbortSleep )
 | 
						if( eSleepAction == eAbortSleep )
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		/* Restart tick and count up to whatever was left of the current time
 | 
							/* Restart tick and continue counting to complete the current time
 | 
				
			||||||
		slice. */
 | 
							slice. */
 | 
				
			||||||
		RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ( ulReloadValueForOneTick - ulCountBeforeSleep ) + ulStoppedTimerCompensation );
 | 
					 | 
				
			||||||
		RTCC_Enable( true );
 | 
							RTCC_Enable( true );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Re-enable interrupts - see comments above the cpsid instruction()
 | 
							/* Re-enable interrupts - see comments above the RTCC_Enable() call
 | 
				
			||||||
		above. */
 | 
							above. */
 | 
				
			||||||
		INT_Enable();
 | 
							INT_Enable();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		/* Adjust the reload value to take into account that the current time
 | 
					 | 
				
			||||||
		slice is already partially complete. */
 | 
					 | 
				
			||||||
		ulReloadValue -= ulCountBeforeSleep;
 | 
					 | 
				
			||||||
		RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ulReloadValue );
 | 
							RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ulReloadValue );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Restart the RTC. */
 | 
							/* Restart the RTC. */
 | 
				
			||||||
| 
						 | 
					@ -288,12 +292,11 @@ TickType_t xModifiableIdleTime;
 | 
				
			||||||
		/* Stop RTC.  Again, the time the SysTick is stopped for is accounted
 | 
							/* Stop RTC.  Again, the time the SysTick is stopped for is accounted
 | 
				
			||||||
		for as best it can be, but using the tickless mode will	inevitably
 | 
							for as best it can be, but using the tickless mode will	inevitably
 | 
				
			||||||
		result in some tiny drift of the time maintained by the	kernel with
 | 
							result in some tiny drift of the time maintained by the	kernel with
 | 
				
			||||||
		respect to calendar time.  The count value is latched before stopping
 | 
							respect to calendar time. */
 | 
				
			||||||
		the timer as stopping the timer appears to clear the count. */
 | 
					 | 
				
			||||||
		ulCountAfterSleep = RTCC_CounterGet();
 | 
					 | 
				
			||||||
		RTCC_Enable( false );
 | 
							RTCC_Enable( false );
 | 
				
			||||||
 | 
							ulCountAfterSleep = RTCC_CounterGet();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Re-enable interrupts - see comments above the cpsid instruction()
 | 
							/* Re-enable interrupts - see comments above the INT_Enable() call
 | 
				
			||||||
		above. */
 | 
							above. */
 | 
				
			||||||
		INT_Enable();
 | 
							INT_Enable();
 | 
				
			||||||
		__asm volatile( "dsb" );
 | 
							__asm volatile( "dsb" );
 | 
				
			||||||
| 
						 | 
					@ -304,40 +307,30 @@ TickType_t xModifiableIdleTime;
 | 
				
			||||||
			/* The tick interrupt has already executed, although because this
 | 
								/* The tick interrupt has already executed, although because this
 | 
				
			||||||
			function is called with the scheduler suspended the actual tick
 | 
								function is called with the scheduler suspended the actual tick
 | 
				
			||||||
			processing will not occur until after this function has exited.
 | 
								processing will not occur until after this function has exited.
 | 
				
			||||||
			Reset the reload value with whatever remains of this tick period. */
 | 
								The tick interrupt handler will already have pended the tick
 | 
				
			||||||
			ulReloadValue = ulReloadValueForOneTick - ulCountAfterSleep;
 | 
					 | 
				
			||||||
			RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ulReloadValue );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/* The tick interrupt handler will already have pended the tick
 | 
					 | 
				
			||||||
			processing in the kernel.  As the pending tick will be processed as
 | 
								processing in the kernel.  As the pending tick will be processed as
 | 
				
			||||||
			soon as this function exits, the tick value	maintained by the tick
 | 
								soon as this function exits, the tick value	maintained by the tick
 | 
				
			||||||
			is stepped forward by one less than the	time spent sleeping.  The
 | 
								is stepped forward by one less than the	time spent sleeping.  The
 | 
				
			||||||
			actual stepping of the tick appears later in this function. */
 | 
								actual stepping of the tick appears later in this function. */
 | 
				
			||||||
			ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
 | 
								ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* The interrupt should have reset the CCV value. */
 | 
				
			||||||
 | 
								configASSERT( RTCC_ChannelCCVGet( lpRTCC_CHANNEL ) == ulReloadValueForOneTick );
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			/* Something other than the tick interrupt ended the sleep.  How
 | 
								/* Something other than the tick interrupt ended the sleep.  How
 | 
				
			||||||
			many complete tick periods passed while the processor was
 | 
								many complete tick periods passed while the processor was
 | 
				
			||||||
			sleeping?  Add back in the adjustment that was made to the reload
 | 
								sleeping? */
 | 
				
			||||||
			value to account for the fact that a time slice was part way through
 | 
					 | 
				
			||||||
			when this function was called. */
 | 
					 | 
				
			||||||
			ulCountAfterSleep += ulCountBeforeSleep;
 | 
					 | 
				
			||||||
			ulCompleteTickPeriods = ulCountAfterSleep / ulReloadValueForOneTick;
 | 
								ulCompleteTickPeriods = ulCountAfterSleep / ulReloadValueForOneTick;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* The reload value is set to whatever fraction of a single tick
 | 
								/* The next interrupt is configured to occur at whatever fraction of
 | 
				
			||||||
			period remains. */
 | 
								the current tick period remains by setting the reload value back to
 | 
				
			||||||
			ulCountAfterSleep -= ( ulCompleteTickPeriods * ulReloadValueForOneTick );
 | 
								that required for one tick, and truncating the count to remove the
 | 
				
			||||||
			ulReloadValue = ulReloadValueForOneTick - ulCountAfterSleep;
 | 
								counts that are greater than the reload value. */
 | 
				
			||||||
 | 
								RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ulReloadValueForOneTick );
 | 
				
			||||||
			if( ulReloadValue == 0 )
 | 
								ulCountAfterSleep %= ulReloadValueForOneTick;
 | 
				
			||||||
			{
 | 
								RTCC_CounterSet( ulCountAfterSleep );
 | 
				
			||||||
				/* There is no fraction remaining. */
 | 
					 | 
				
			||||||
				ulReloadValue = ulReloadValueForOneTick;
 | 
					 | 
				
			||||||
				ulCompleteTickPeriods++;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ulReloadValue );
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Restart the RTC so it runs up to the alarm value.  The alarm value
 | 
							/* Restart the RTC so it runs up to the alarm value.  The alarm value
 | 
				
			||||||
| 
						 | 
					@ -379,4 +372,55 @@ void RTCC_IRQHandler( void )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/*-----------------------------------------------------------*/
 | 
					/*-----------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if( lpUSE_TEST_TIMER == 1 )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Juse used to ensure the second timer is executing. */
 | 
				
			||||||
 | 
						volatile uint32_t ulLETimerIncrements = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void LETIMER0_IRQHandler( void )
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* This ISR is used purely to bring the MCU out of sleep mode - it has
 | 
				
			||||||
 | 
							no other purpose. */
 | 
				
			||||||
 | 
							ulLETimerIncrements++;
 | 
				
			||||||
 | 
							LETIMER_IntClear( LETIMER0, LETIMER_IF_COMP0 );
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* lpUSE_TEST_TIMER == 1 */
 | 
				
			||||||
 | 
					/*-----------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if( lpUSE_TEST_TIMER == 1 )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set up a timer that used used to bring the MCU out of sleep mode using
 | 
				
			||||||
 | 
						an interrupt other than the tick interrupt.  This is done for code coverage
 | 
				
			||||||
 | 
						puposes only. */
 | 
				
			||||||
 | 
						void prvSetupTestTimer( void )
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						static const LETIMER_Init_TypeDef xLETimerInitStruct =
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							true,               /* Enable timer when init complete. */
 | 
				
			||||||
 | 
							false,              /* Stop counter during debug halt. */
 | 
				
			||||||
 | 
							true,               /* Load COMP0 into CNT on underflow. */
 | 
				
			||||||
 | 
							false,              /* Do not load COMP1 into COMP0 when REP0 reaches 0. */
 | 
				
			||||||
 | 
							0,                  /* Idle value 0 for output 0. */
 | 
				
			||||||
 | 
							0,                  /* Idle value 0 for output 1. */
 | 
				
			||||||
 | 
							letimerUFOANone,    /* No action on underflow on output 0. */
 | 
				
			||||||
 | 
							letimerUFOANone,    /* No action on underflow on output 1. */
 | 
				
			||||||
 | 
							letimerRepeatFree   /* Count until stopped by SW. */
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						const uint32_t ulCompareMatch = 32768UL / 10UL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CMU_ClockSelectSet( cmuClock_LFA, cmuSelect_LFXO );
 | 
				
			||||||
 | 
							CMU_ClockEnable( cmuClock_LETIMER0, true );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							LETIMER_CompareSet( LETIMER0, 0, ulCompareMatch );
 | 
				
			||||||
 | 
							LETIMER_IntEnable( LETIMER0, LETIMER_IF_COMP0 );
 | 
				
			||||||
 | 
							NVIC_EnableIRQ( LETIMER0_IRQn );
 | 
				
			||||||
 | 
							LETIMER_Init( LETIMER0, &xLETimerInitStruct);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* lpUSE_TEST_TIMER == 1 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* ( configCREATE_LOW_POWER_DEMO == 1 ) */
 | 
					#endif /* ( configCREATE_LOW_POWER_DEMO == 1 ) */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue