+/*\r
+ FreeRTOS V8.2.3 - Copyright (C) 2015 Real Time Engineers Ltd.\r
+ All rights reserved\r
+\r
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
+\r
+ This file is part of the FreeRTOS distribution.\r
+\r
+ FreeRTOS is free software; you can redistribute it and/or modify it under\r
+ the terms of the GNU General Public License (version 2) as published by the\r
+ Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.\r
+\r
+ ***************************************************************************\r
+ >>! NOTE: The modification to the GPL is included to allow you to !<<\r
+ >>! distribute a combined work that includes FreeRTOS without being !<<\r
+ >>! obliged to provide the source code for proprietary components !<<\r
+ >>! outside of the FreeRTOS kernel. !<<\r
+ ***************************************************************************\r
+\r
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following\r
+ link: http://www.freertos.org/a00114.html\r
+\r
+ ***************************************************************************\r
+ * *\r
+ * FreeRTOS provides completely free yet professionally developed, *\r
+ * robust, strictly quality controlled, supported, and cross *\r
+ * platform software that is more than just the market leader, it *\r
+ * is the industry's de facto standard. *\r
+ * *\r
+ * Help yourself get started quickly while simultaneously helping *\r
+ * to support the FreeRTOS project by purchasing a FreeRTOS *\r
+ * tutorial book, reference manual, or both: *\r
+ * http://www.FreeRTOS.org/Documentation *\r
+ * *\r
+ ***************************************************************************\r
+\r
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading\r
+ the FAQ page "My application does not run, what could be wrong?". Have you\r
+ defined configASSERT()?\r
+\r
+ http://www.FreeRTOS.org/support - In return for receiving this top quality\r
+ embedded software for free we request you assist our global community by\r
+ participating in the support forum.\r
+\r
+ http://www.FreeRTOS.org/training - Investing in training allows your team to\r
+ be as productive as possible as early as possible. Now you can receive\r
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers\r
+ Ltd, and the world's leading authority on the world's leading RTOS.\r
+\r
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
+\r
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.\r
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.\r
+\r
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High\r
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS\r
+ licenses offer ticketed support, indemnification and commercial middleware.\r
+\r
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
+ engineered and independently SIL3 certified version for use in safety and\r
+ mission critical applications that require provable dependability.\r
+\r
+ 1 tab == 4 spaces!\r
+*/\r
+\r
+/* Standard includes. */\r
+#include "limits.h"\r
+\r
+/* FreeRTOS includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+\r
+/* SiLabs library includes. */\r
+#include "em_cmu.h"\r
+#include "em_burtc.h"\r
+#include "em_rmu.h"\r
+#include "em_int.h"\r
+#include "sleep.h"\r
+\r
+/* This file contains functions that will override the default implementations\r
+in the RTOS port layer. Therefore only build this file if the low power demo\r
+is being built. */\r
+#if( configCREATE_LOW_POWER_DEMO == 1 )\r
+\r
+#define mainTIMER_FREQUENCY_HZ ( 2000UL )\r
+\r
+/*\r
+ * The low power demo does not use the SysTick, so override the\r
+ * vPortSetupTickInterrupt() function with an implementation that configures\r
+ * a low power clock source. NOTE: This function name must not be changed as\r
+ * it is called from the RTOS portable layer.\r
+ */\r
+void vPortSetupTimerInterrupt( void );\r
+\r
+/* Override the default definition of vPortSuppressTicksAndSleep() that is\r
+ * weakly defined in the FreeRTOS Cortex-M port layer with a version that\r
+ * manages the BURTC clock, as the tick is generated from the low power BURTC\r
+ * and not the SysTick as would normally be the case on a Cortex-M.\r
+ */\r
+void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/* Calculate how many clock increments make up a single tick period. */\r
+static const uint32_t ulReloadValueForOneTick = ( mainTIMER_FREQUENCY_HZ / configTICK_RATE_HZ );\r
+\r
+/* Calculate the maximum number of ticks that can be suppressed when using the\r
+high resolution clock and low resolution clock respectively. */\r
+static uint32_t xMaximumPossibleSuppressedTicks = 0;\r
+\r
+/* Flag set from the tick interrupt to allow the sleep processing to know if\r
+sleep mode was exited because of an timer interrupt or a different interrupt. */\r
+static volatile uint32_t ulTickFlag = pdFALSE;\r
+\r
+/* As the clock is only 2KHz, it is likely a value of 1 will be too much, so\r
+use zero - but leave the value here to assist porting to different clock\r
+speeds. */\r
+static const uint32_t ulStoppedTimerCompensation = 0UL;\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+void vPortSetupTimerInterrupt( void )\r
+{\r
+BURTC_Init_TypeDef xBURTCInitStruct = BURTC_INIT_DEFAULT;\r
+\r
+ xMaximumPossibleSuppressedTicks = ULONG_MAX / ulReloadValueForOneTick;\r
+\r
+ /* Ensure LE modules are accessible. */\r
+ CMU_ClockEnable( cmuClock_CORELE, true );\r
+\r
+ /* Enable access to BURTC registers. */\r
+ RMU_ResetControl( rmuResetBU, false );\r
+\r
+ /* Generate the tick interrupt from BURTC. */\r
+ xBURTCInitStruct.mode = burtcModeEM3; /* Operational in EM3. */\r
+ xBURTCInitStruct.clkSel = burtcClkSelULFRCO;/* ULFRCO clock. */\r
+ xBURTCInitStruct.clkDiv = burtcClkDiv_1; /* 2kHz ULFRCO clock. */\r
+ xBURTCInitStruct.compare0Top = true; /* Wrap on COMP0. */\r
+ BURTC_IntDisable( BURTC_IF_COMP0 );\r
+ BURTC_Init( &xBURTCInitStruct );\r
+\r
+ /* The tick interrupt must be set to the lowest possible. */\r
+ NVIC_SetPriority( BURTC_IRQn, configKERNEL_INTERRUPT_PRIORITY );\r
+ NVIC_ClearPendingIRQ( BURTC_IRQn );\r
+ NVIC_EnableIRQ( BURTC_IRQn );\r
+ BURTC_CompareSet( 0, ulReloadValueForOneTick );\r
+ BURTC_IntClear( BURTC_IF_COMP0 );\r
+ BURTC_IntEnable( BURTC_IF_COMP0 );\r
+ BURTC_CounterReset();\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )\r
+{\r
+uint32_t ulReloadValue, ulCompleteTickPeriods, ulCurrentCount;\r
+eSleepModeStatus eSleepAction;\r
+TickType_t xModifiableIdleTime;\r
+\r
+ /* THIS FUNCTION IS CALLED WITH THE SCHEDULER SUSPENDED. */\r
+\r
+ /* Make sure the BURTC reload value does not overflow the counter. */\r
+ if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )\r
+ {\r
+ xExpectedIdleTime = xMaximumPossibleSuppressedTicks;\r
+ }\r
+\r
+ /* Calculate the reload value required to wait xExpectedIdleTime tick\r
+ periods. */\r
+ ulReloadValue = ulReloadValueForOneTick * xExpectedIdleTime;\r
+ if( ulReloadValue > ulStoppedTimerCompensation )\r
+ {\r
+ /* Compensate for the fact that the BURTC is going to be stopped\r
+ momentarily. */\r
+ ulReloadValue -= ulStoppedTimerCompensation;\r
+ }\r
+\r
+ /* Stop the BURTC momentarily. The time the BURTC is stopped for is\r
+ accounted for as best it can be, but using the tickless mode will inevitably\r
+ result in some tiny drift of the time maintained by the kernel with respect\r
+ to calendar time. The count is latched before stopping the timer as\r
+ stopping the timer appears to clear the count. */\r
+ ulCurrentCount = BURTC_CounterGet();\r
+ BURTC_Enable( false );\r
+\r
+ /* Enter a critical section but don't use the taskENTER_CRITICAL() method as\r
+ that will mask interrupts that should exit sleep mode. */\r
+ INT_Disable();\r
+\r
+ /* The tick flag is set to false before sleeping. If it is true when sleep\r
+ mode is exited then sleep mode was probably exited because the tick was\r
+ suppressed for the entire xExpectedIdleTime period. */\r
+ ulTickFlag = pdFALSE;\r
+\r
+ /* If a context switch is pending then abandon the low power entry as the\r
+ context switch might have been pended by an external interrupt that requires\r
+ processing. */\r
+ eSleepAction = eTaskConfirmSleepModeStatus();\r
+ if( eSleepAction == eAbortSleep )\r
+ {\r
+ /* Restart tick and count up to whatever was left of the current time\r
+ slice. */\r
+ BURTC_CompareSet( 0, ulReloadValueForOneTick - ulCurrentCount );\r
+ BURTC_Enable( true );\r
+\r
+ /* Re-enable interrupts - see comments above the cpsid instruction()\r
+ above. */\r
+ INT_Enable();\r
+ }\r
+ else\r
+ {\r
+ /* Adjust the reload value to take into account that the current time\r
+ slice is already partially complete. */\r
+ ulReloadValue -= ulCurrentCount;\r
+ BURTC_CompareSet( 0, ulReloadValue );\r
+\r
+ /* Restart the BURTC. */\r
+ BURTC_Enable( true );\r
+\r
+ /* Allow the application to define some pre-sleep processing. */\r
+ xModifiableIdleTime = xExpectedIdleTime;\r
+ configPRE_SLEEP_PROCESSING( xModifiableIdleTime );\r
+\r
+ /* xExpectedIdleTime being set to 0 by configPRE_SLEEP_PROCESSING()\r
+ means the application defined code has already executed the WAIT\r
+ instruction. */\r
+ if( xModifiableIdleTime > 0 )\r
+ {\r
+ __asm volatile( "dsb" );\r
+ SLEEP_Sleep();\r
+ __asm volatile( "isb" );\r
+ }\r
+\r
+ /* Allow the application to define some post sleep processing. */\r
+ configPOST_SLEEP_PROCESSING( xModifiableIdleTime );\r
+\r
+ /* Stop BURTC. Again, the time the SysTick is stopped for is accounted\r
+ for as best it can be, but using the tickless mode will inevitably\r
+ result in some tiny drift of the time maintained by the kernel with\r
+ respect to calendar time. The count value is latched before stopping\r
+ the timer as stopping the timer appears to clear the count. */\r
+ ulCurrentCount = BURTC_CounterGet();\r
+ BURTC_Enable( false );\r
+\r
+ /* Re-enable interrupts - see comments above the cpsid instruction()\r
+ above. */\r
+ INT_Enable();\r
+\r
+ if( ulTickFlag != pdFALSE )\r
+ {\r
+ /* The tick interrupt has already executed, although because this\r
+ function is called with the scheduler suspended the actual tick\r
+ processing will not occur until after this function has exited.\r
+ Reset the reload value with whatever remains of this tick period. */\r
+ ulReloadValue = ulReloadValueForOneTick - ulCurrentCount;\r
+ BURTC_CompareSet( 0, ulReloadValue );\r
+\r
+ /* The tick interrupt handler will already have pended the tick\r
+ processing in the kernel. As the pending tick will be processed as\r
+ soon as this function exits, the tick value maintained by the tick\r
+ is stepped forward by one less than the time spent sleeping. The\r
+ actual stepping of the tick appears later in this function. */\r
+ ulCompleteTickPeriods = xExpectedIdleTime - 1UL;\r
+ }\r
+ else\r
+ {\r
+ /* Something other than the tick interrupt ended the sleep. How\r
+ many complete tick periods passed while the processor was\r
+ sleeping? */\r
+ ulCompleteTickPeriods = ulCurrentCount / ulReloadValueForOneTick;\r
+\r
+ /* The reload value is set to whatever fraction of a single tick\r
+ period remains. */\r
+ ulReloadValue = ulCurrentCount - ( ulCompleteTickPeriods * ulReloadValueForOneTick );\r
+ if( ulReloadValue == 0 )\r
+ {\r
+ /* There is no fraction remaining. */\r
+ ulReloadValue = ulReloadValueForOneTick;\r
+ ulCompleteTickPeriods++;\r
+ }\r
+\r
+ BURTC_CompareSet( 0, ulReloadValue );\r
+ }\r
+\r
+ /* Restart the BURTC so it runs up to the alarm value. The alarm value\r
+ will get set to the value required to generate exactly one tick period\r
+ the next time the BURTC interrupt executes. */\r
+ BURTC_Enable( true );\r
+\r
+ /* Wind the tick forward by the number of tick periods that the CPU\r
+ remained in a low power state. */\r
+ vTaskStepTick( ulCompleteTickPeriods );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void BURTC_IRQHandler(void)\r
+{\r
+ if( ulTickFlag == pdFALSE )\r
+ {\r
+ /* Set BURTC interrupt to one system tick period*/\r
+ BURTC_Enable( false );\r
+ BURTC_CompareSet( 0, ulReloadValueForOneTick );\r
+ ulTickFlag = pdTRUE;\r
+ BURTC_Enable( true );\r
+ }\r
+\r
+ BURTC_IntClear( _RTC_IFC_MASK );\r
+\r
+ /* Critical section which protect incrementing the tick*/\r
+ ( void ) portSET_INTERRUPT_MASK_FROM_ISR();\r
+ {\r
+ if( xTaskIncrementTick() != pdFALSE )\r
+ {\r
+ /* Pend a context switch. */\r
+ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;\r
+ }\r
+ }\r
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 );\r
+}\r
+\r
+#endif /* ( configCREATE_LOW_POWER_DEMO == 1 ) */\r
+\r