X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=FreeRTOS%2FSource%2Fportable%2FIAR%2FARM_CM4F%2Fport.c;h=3cdd25b3048a49e5467c754993101fb2f27de034;hb=4c4a171cb817e52f4e9c57c314f039df5b65efa3;hp=61c08cb6802d004681f32cef70ce04f20d743665;hpb=4fc98ea9360d27da61c0096a3a46abcf64ca400d;p=freertos diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c b/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c index 61c08cb68..3cdd25b30 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c @@ -1,48 +1,40 @@ /* - FreeRTOS V7.3.0 - Copyright (C) 2012 Real Time Engineers Ltd. + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. - FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT - http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. *************************************************************************** * * - * FreeRTOS tutorial books are available in pdf and paperback. * - * Complete, revised, and edited pdf reference manuals are also * - * available. * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * * * - * Purchasing FreeRTOS documentation will not only help you, by * - * ensuring you get running as quickly as possible and with an * - * in-depth knowledge of how to use FreeRTOS, it will also help * - * the FreeRTOS project to continue with its mission of providing * - * professional grade, cross platform, de facto standard solutions * - * for microcontrollers - completely free of charge! * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * * * - * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * - * * - * Thank you for using FreeRTOS, and thank you for your support! * + * Thank you! * * * *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - >>>NOTE<<< The modification to the GPL is included to allow you to - distribute a combined work that includes FreeRTOS without being obliged to - provide the source code for proprietary components outside of the FreeRTOS - kernel. FreeRTOS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. You should have received a copy of the GNU General Public - License and the FreeRTOS license exception along with FreeRTOS; if not it - can be viewed here: http://www.freertos.org/a00114.html and also obtained - by writing to Richard Barry, contact details for whom are available on the - FreeRTOS WEB site. + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available from the following + link: http://www.freertos.org/a00114.html 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -52,24 +44,31 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest versions, license - and contact details. - + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool. + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under - the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also - provide a safety engineered and independently SIL3 certified version under - the SafeRTOS brand: http://www.SafeRTOS.com. + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! */ /*----------------------------------------------------------- * Implementation of functions defined in portable.h for the ARM CM4F port. *----------------------------------------------------------*/ +/* Compiler includes. */ +#include + /* Scheduler includes. */ #include "FreeRTOS.h" #include "task.h" @@ -84,50 +83,61 @@ #ifndef configSYSTICK_CLOCK_HZ #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ - #if configUSE_TICKLESS_IDLE == 1 - static const unsigned long ulStoppedTimerCompensation = 45UL; - #endif -#else /* configSYSTICK_CLOCK_HZ */ - #if configUSE_TICKLESS_IDLE == 1 - /* Assumes the SysTick clock is slower than the CPU clock. */ - static const unsigned long ulStoppedTimerCompensation = 45UL / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ ); - #endif -#endif /* configSYSTICK_CLOCK_HZ */ +#endif /* Constants required to manipulate the core. Registers first... */ #define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile unsigned long * ) 0xe000e010 ) ) #define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile unsigned long * ) 0xe000e014 ) ) #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile unsigned long * ) 0xe000e018 ) ) -#define portNVIC_INT_CTRL_REG ( * ( ( volatile unsigned long * ) 0xe000ed04 ) ) #define portNVIC_SYSPRI2_REG ( * ( ( volatile unsigned long * ) 0xe000ed20 ) ) /* ...then bits in the registers. */ #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL ) #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL ) #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL ) #define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL ) -#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL ) #define portNVIC_PENDSVCLEAR_BIT ( 1UL << 27UL ) #define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL ) -#define portNVIC_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 ) -#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 ) +#define portNVIC_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL ) +#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL ) + +/* Constants required to check the validity of an interrupt priority. */ +#define portFIRST_USER_INTERRUPT_NUMBER ( 16 ) +#define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 ) +#define portAIRCR_REG ( * ( ( volatile unsigned long * ) 0xE000ED0C ) ) +#define portMAX_8_BIT_VALUE ( ( unsigned char ) 0xff ) +#define portTOP_BIT_OF_BYTE ( ( unsigned char ) 0x80 ) +#define portMAX_PRIGROUP_BITS ( ( unsigned char ) 7 ) +#define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL ) +#define portPRIGROUP_SHIFT ( 8UL ) /* Constants required to manipulate the VFP. */ -#define portFPCCR ( ( volatile unsigned long * ) 0xe000ef34 ) /* Floating point context control register. */ -#define portASPEN_AND_LSPEN_BITS ( 0x3UL << 30UL ) +#define portFPCCR ( ( volatile unsigned long * ) 0xe000ef34 ) /* Floating point context control register. */ +#define portASPEN_AND_LSPEN_BITS ( 0x3UL << 30UL ) /* Constants required to set up the initial stack. */ -#define portINITIAL_XPSR ( 0x01000000 ) -#define portINITIAL_EXEC_RETURN ( 0xfffffffd ) +#define portINITIAL_XPSR ( 0x01000000 ) +#define portINITIAL_EXEC_RETURN ( 0xfffffffd ) + +/* The systick is a 24-bit counter. */ +#define portMAX_24_BIT_NUMBER ( 0xffffffUL ) + +/* A fiddle factor to estimate the number of SysTick counts that would have +occurred while the SysTick counter is stopped during tickless idle +calculations. */ +#define portMISSED_COUNTS_FACTOR ( 45UL ) + /* Each task maintains its own interrupt status in the critical nesting variable. */ static unsigned portBASE_TYPE uxCriticalNesting = 0xaaaaaaaa; /* - * Setup the timer to generate the tick interrupts. + * Setup the timer to generate the tick interrupts. The implementation in this + * file is weak to allow application writers to change the timer used to + * generate the tick interrupt. */ -static void prvSetupTimerInterrupt( void ); +void vPortSetupTimerInterrupt( void ); /* * Exception handlers. @@ -149,7 +159,9 @@ extern void vPortEnableVFP( void ); /* * The number of SysTick increments that make up one tick period. */ -static unsigned long ulTimerReloadValueForOneTick = 0; +#if configUSE_TICKLESS_IDLE == 1 + static unsigned long ulTimerCountsForOneTick = 0; +#endif /* configUSE_TICKLESS_IDLE */ /* * The maximum number of tick periods that can be suppressed is limited by the @@ -159,6 +171,25 @@ static unsigned long ulTimerReloadValueForOneTick = 0; static unsigned long xMaximumPossibleSuppressedTicks = 0; #endif /* configUSE_TICKLESS_IDLE */ +/* + * Compensate for the CPU cycles that pass while the SysTick is stopped (low + * power functionality only. + */ +#if configUSE_TICKLESS_IDLE == 1 + static unsigned long ulStoppedTimerCompensation = 0; +#endif /* configUSE_TICKLESS_IDLE */ + +/* + * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure + * FreeRTOS API functions are not called from interrupts that have been assigned + * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. + */ +#if ( configASSERT_DEFINED == 1 ) + static unsigned char ucMaxSysCallPriority = 0; + static unsigned long ulMaxPRIGROUPValue = 0; + static const volatile unsigned char * const pcInterruptPriorityRegisters = ( const volatile unsigned char * const ) portNVIC_IP_REGISTERS_OFFSET_16; +#endif /* configASSERT_DEFINED */ + /*-----------------------------------------------------------*/ /* @@ -199,13 +230,57 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE */ portBASE_TYPE xPortStartScheduler( void ) { + #if( configASSERT_DEFINED == 1 ) + { + volatile unsigned long ulOriginalPriority; + volatile char * const pcFirstUserPriorityRegister = ( volatile char * const ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER ); + volatile unsigned char ucMaxPriorityValue; + + /* Determine the maximum priority from which ISR safe FreeRTOS API + functions can be called. ISR safe functions are those that end in + "FromISR". FreeRTOS maintains separate thread and ISR API functions to + ensure interrupt entry is as fast and simple as possible. + + Save the interrupt priority value that is about to be clobbered. */ + ulOriginalPriority = *pcFirstUserPriorityRegister; + + /* Determine the number of priority bits available. First write to all + possible bits. */ + *pcFirstUserPriorityRegister = portMAX_8_BIT_VALUE; + + /* Read the value back to see how many bits stuck. */ + ucMaxPriorityValue = *pcFirstUserPriorityRegister; + + /* Use the same mask on the maximum system call priority. */ + ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; + + /* Calculate the maximum acceptable priority group value for the number + of bits read back. */ + ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; + while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) + { + ulMaxPRIGROUPValue--; + ucMaxPriorityValue <<= ( unsigned char ) 0x01; + } + + /* Shift the priority group value back to its position within the AIRCR + register. */ + ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; + ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; + + /* Restore the clobbered interrupt priority register to its original + value. */ + *pcFirstUserPriorityRegister = ulOriginalPriority; + } + #endif /* conifgASSERT_DEFINED */ + /* Make PendSV and SysTick the lowest priority interrupts. */ portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; /* Start the timer that generates the tick ISR. Interrupts are disabled here already. */ - prvSetupTimerInterrupt(); + vPortSetupTimerInterrupt(); /* Initialise the critical nesting count ready for the first task. */ uxCriticalNesting = 0; @@ -231,10 +306,15 @@ void vPortEndScheduler( void ) } /*-----------------------------------------------------------*/ -void vPortYieldFromISR( void ) +void vPortYield( void ) { /* Set a PendSV to request a context switch. */ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; + + /* Barriers are normally not required but do ensure the code is completely + within the specified behaviour for the architecture. */ + __DSB(); + __ISB(); } /*-----------------------------------------------------------*/ @@ -242,6 +322,8 @@ void vPortEnterCritical( void ) { portDISABLE_INTERRUPTS(); uxCriticalNesting++; + __DSB(); + __ISB(); } /*-----------------------------------------------------------*/ @@ -257,18 +339,19 @@ void vPortExitCritical( void ) void xPortSysTickHandler( void ) { - /* If using preemption, also force a context switch. */ - #if configUSE_PREEMPTION == 1 - portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; - #endif - - #if configUSE_TICKLESS_IDLE == 1 - portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; - #endif - + /* The SysTick runs at the lowest interrupt priority, so when this interrupt + executes all interrupts must be unmasked. There is therefore no need to + save and then restore the interrupt mask value as its value is already + known. */ ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); { - vTaskIncrementTick(); + /* Increment the RTOS tick. */ + if( xTaskIncrementTick() != pdFALSE ) + { + /* A context switch is required. Context switching is performed in + the PendSV interrupt. Pend the PendSV interrupt. */ + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; + } } portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); } @@ -278,7 +361,8 @@ void xPortSysTickHandler( void ) __weak void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ) { - unsigned long ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickIncrements; + unsigned long ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements; + portTickType xModifiableIdleTime; /* Make sure the SysTick reload value does not overflow the counter. */ if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) @@ -286,35 +370,39 @@ void xPortSysTickHandler( void ) xExpectedIdleTime = xMaximumPossibleSuppressedTicks; } + /* Stop the SysTick momentarily. The time the SysTick is stopped for + is accounted 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 calendar time. */ + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT; + /* Calculate the reload value required to wait xExpectedIdleTime tick periods. -1 is used because this code will execute part way - through one of the tick periods, and the fraction of a tick period is - accounted for later. */ - ulReloadValue = ( ulTimerReloadValueForOneTick * ( xExpectedIdleTime - 1UL ) ); + through one of the tick periods. */ + ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) ); if( ulReloadValue > ulStoppedTimerCompensation ) { ulReloadValue -= ulStoppedTimerCompensation; } - /* Stop the SysTick momentarily. The time the SysTick is stopped for - is accounted 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 calendar time. */ - portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT; + /* Enter a critical section but don't use the taskENTER_CRITICAL() + method as that will mask interrupts that should exit sleep mode. */ + __disable_interrupt(); - /* If a context switch is pending then abandon the low power entry as - the context switch might have been pended by an external interrupt that - requires processing. */ - if( ( portNVIC_INT_CTRL_REG & portNVIC_PENDSVSET_BIT ) != 0 ) + /* If a context switch is pending or a task is waiting for the scheduler + to be unsuspended then abandon the low power entry. */ + if( eTaskConfirmSleepModeStatus() == eAbortSleep ) { /* Restart SysTick. */ portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + + /* Re-enable interrupts - see comments above __disable_interrupt() + call above. */ + __enable_interrupt(); } else { - /* Adjust the reload value to take into account that the current - time slice is already partially complete. */ - ulReloadValue += ( portNVIC_SYSTICK_LOAD_REG - ( portNVIC_SYSTICK_LOAD_REG - portNVIC_SYSTICK_CURRENT_VALUE_REG ) ); + /* Set the new reload value. */ portNVIC_SYSTICK_LOAD_REG = ulReloadValue; /* Clear the SysTick count flag and set the count value back to @@ -324,10 +412,20 @@ void xPortSysTickHandler( void ) /* Restart SysTick. */ portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; - /* Sleep until something happens. */ - portPRE_SLEEP_PROCESSING(); - __WFI(); - portPOST_SLEEP_PROCESSING(); + /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can + set its parameter to 0 to indicate that its implementation contains + its own wait for interrupt or wait for event instruction, and so wfi + should not be executed again. However, the original expected idle + time variable must remain unmodified, so a copy is taken. */ + xModifiableIdleTime = xExpectedIdleTime; + configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); + if( xModifiableIdleTime > 0 ) + { + __DSB(); + __WFI(); + __ISB(); + } + configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); /* Stop SysTick. Again, the time the SysTick is stopped for is accounted for as best it can be, but using the tickless mode will @@ -335,13 +433,17 @@ void xPortSysTickHandler( void ) kernel with respect to calendar time. */ portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT; + /* Re-enable interrupts - see comments above __disable_interrupt() + call above. */ + __enable_interrupt(); + if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) { /* The tick interrupt has already executed, and the SysTick - count reloaded with the portNVIC_SYSTICK_LOAD_REG value. - Reset the portNVIC_SYSTICK_LOAD_REG with whatever remains of - this tick period. */ - portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); + count reloaded with ulReloadValue. Reset the + portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick + period. */ + portNVIC_SYSTICK_LOAD_REG = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); /* The tick interrupt handler will already have pended the tick processing in the kernel. As the pending tick will be @@ -353,25 +455,33 @@ void xPortSysTickHandler( void ) else { /* Something other than the tick interrupt ended the sleep. - Work out how long the sleep lasted. */ - ulCompletedSysTickIncrements = ( xExpectedIdleTime * ulTimerReloadValueForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG; + Work out how long the sleep lasted rounded to complete tick + periods (not the ulReload value which accounted for part + ticks). */ + ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG; /* How many complete tick periods passed while the processor was waiting? */ - ulCompleteTickPeriods = ulCompletedSysTickIncrements / ulTimerReloadValueForOneTick; + ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick; /* The reload value is set to whatever fraction of a single tick period remains. */ - portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1 ) * ulTimerReloadValueForOneTick ) - ulCompletedSysTickIncrements; + portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1 ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements; } /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG again, then set portNVIC_SYSTICK_LOAD_REG back to its standard - value. */ + value. The critical section is used to ensure the tick interrupt + can only execute once in the case that the reload register is near + zero. */ portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; - portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; - - vTaskStepTick( ulCompleteTickPeriods ); + portENTER_CRITICAL(); + { + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + vTaskStepTick( ulCompleteTickPeriods ); + portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; + } + portEXIT_CRITICAL(); } } @@ -382,17 +492,100 @@ void xPortSysTickHandler( void ) * Setup the systick timer to generate the tick interrupts at the required * frequency. */ -void prvSetupTimerInterrupt( void ) +__weak void vPortSetupTimerInterrupt( void ) { - /* Configure the constants required to setup the tick interrupt. */ - ulTimerReloadValueForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + /* Calculate the constants required to configure the tick interrupt. */ #if configUSE_TICKLESS_IDLE == 1 - xMaximumPossibleSuppressedTicks = 0xffffffUL / ( ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL ); + { + ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); + xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; + ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ ); + } #endif /* configUSE_TICKLESS_IDLE */ /* Configure SysTick to interrupt at the requested rate. */ - portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ + +#if( configASSERT_DEFINED == 1 ) + + void vPortValidateInterruptPriority( void ) + { + unsigned long ulCurrentInterrupt; + unsigned char ucCurrentPriority; + + /* Obtain the number of the currently executing interrupt. */ + __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); + + /* Is the interrupt number a user defined interrupt? */ + if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ) + { + /* Look up the interrupt's priority. */ + ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ]; + + /* The following assertion will fail if a service routine (ISR) for + an interrupt that has been assigned a priority above + configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API + function. ISR safe FreeRTOS API functions must *only* be called + from interrupts that have been assigned a priority at or below + configMAX_SYSCALL_INTERRUPT_PRIORITY. + + Numerically low interrupt priority numbers represent logically high + interrupt priorities, therefore the priority of the interrupt must + be set to a value equal to or numerically *higher* than + configMAX_SYSCALL_INTERRUPT_PRIORITY. + + Interrupts that use the FreeRTOS API must not be left at their + default priority of zero as that is the highest possible priority, + which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, + and therefore also guaranteed to be invalid. + + FreeRTOS maintains separate thread and ISR API functions to ensure + interrupt entry is as fast and simple as possible. + + The following links provide detailed information: + http://www.freertos.org/RTOS-Cortex-M3-M4.html + http://www.freertos.org/FAQHelp.html */ + configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); + } + + /* Priority grouping: The interrupt controller (NVIC) allows the bits + that define each interrupt's priority to be split between bits that + define the interrupt's pre-emption priority bits and bits that define + the interrupt's sub-priority. For simplicity all bits must be defined + to be pre-emption priority bits. The following assertion will fail if + this is not the case (if some bits represent a sub-priority). + + If the application only uses CMSIS libraries for interrupt + configuration then the correct setting can be achieved on all Cortex-M + devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the + scheduler. Note however that some vendor specific peripheral libraries + assume a non-zero priority group setting, in which cases using a value + of zero will result in unpredicable behaviour. */ + configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); + } + +#endif /* configASSERT_DEFINED */ + + + + + + + + + + + + + + + + + + + +