From 07d92105bfcab648a269af097da5196738186a6d Mon Sep 17 00:00:00 2001 From: richardbarry Date: Tue, 16 Oct 2012 07:55:40 +0000 Subject: [PATCH] Add tickless idle support in Cortex-M ports. Change CCS R4 directory name. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1795 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Source/include/FreeRTOS.h | 12 + FreeRTOS/Source/include/task.h | 21 ++ .../Source/portable/CCS/ARM_Cortex-R4/port.c | 350 ++++++++++++++++++ .../portable/CCS/ARM_Cortex-R4/portASM.asm | 263 +++++++++++++ .../portable/CCS/ARM_Cortex-R4/portmacro.h | 145 ++++++++ FreeRTOS/Source/portable/GCC/ARM_CM3/port.c | 232 ++++++++++-- .../Source/portable/GCC/ARM_CM3/portmacro.h | 66 ++-- FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c | 240 ++++++++++-- .../Source/portable/GCC/ARM_CM4F/portmacro.h | 66 ++-- FreeRTOS/Source/portable/IAR/ARM_CM3/port.c | 201 ++++++++-- .../Source/portable/IAR/ARM_CM3/portasm.s | 49 +-- .../Source/portable/IAR/ARM_CM3/portmacro.h | 34 +- FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c | 215 +++++++++-- .../Source/portable/IAR/ARM_CM4F/portasm.s | 18 +- .../Source/portable/IAR/ARM_CM4F/portmacro.h | 36 +- FreeRTOS/Source/portable/MemMang/heap_1.c | 34 +- FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c | 276 ++++++++++---- .../Source/portable/RVDS/ARM_CM3/portmacro.h | 67 ++-- FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c | 283 ++++++++++---- .../Source/portable/RVDS/ARM_CM4F/portmacro.h | 43 ++- FreeRTOS/Source/tasks.c | 324 +++++++++++----- 21 files changed, 2387 insertions(+), 588 deletions(-) create mode 100644 FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/port.c create mode 100644 FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/portASM.asm create mode 100644 FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/portmacro.h diff --git a/FreeRTOS/Source/include/FreeRTOS.h b/FreeRTOS/Source/include/FreeRTOS.h index 1dc85c8a3..c8c732886 100644 --- a/FreeRTOS/Source/include/FreeRTOS.h +++ b/FreeRTOS/Source/include/FreeRTOS.h @@ -528,5 +528,17 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); #define vPortFreeAligned( pvBlockToFree ) vPortFree( pvBlockToFree ) #endif +#ifndef portSUPPRESS_TICKS_AND_SLEEP + #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) +#endif + +#ifndef portPRE_SLEEP_PROCESSING + #define portPRE_SLEEP_PROCESSING() +#endif + +#ifndef portPOST_SLEEP_PROCESSING + #define portPOST_SLEEP_PROCESSING() +#endif + #endif /* INC_FREERTOS_H */ diff --git a/FreeRTOS/Source/include/task.h b/FreeRTOS/Source/include/task.h index 6c6be5248..f38b17719 100644 --- a/FreeRTOS/Source/include/task.h +++ b/FreeRTOS/Source/include/task.h @@ -1320,6 +1320,27 @@ unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask ); */ void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle ); +/* + * Return the amount of time, in ticks, that will pass before the kernel will + * next move a task from the Blocked state to the Running state. + */ +portTickType xTaskGetExpectedIdleTime( void ); + +/* + * If tickless mode is being used, or a low power mode is implemented, then + * the tick interrupt will not execute during idle periods. When this is the + * case, the tick count value maintained by the scheduler needs to be kept up + * to date with the actual execution time by being skipped forward by the by + * a time equal to the idle period. + */ +void vTaskStepTick( portTickType xTicksToJump ); + +/* + * Returns the number of tick interrupts that have occurred while the scheduler + * has been suspended. The count pending ticks is reset if xResetOnExit is set + * to pdTRUE. + */ +unsigned portBASE_TYPE uxTaskPendingTicksGet( portBASE_TYPE xResetOnExit ); #ifdef __cplusplus } diff --git a/FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/port.c b/FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/port.c new file mode 100644 index 000000000..ded485033 --- /dev/null +++ b/FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/port.c @@ -0,0 +1,350 @@ +/* + FreeRTOS V7.2.0 - Copyright (C) 2012 Real Time Engineers Ltd. + + + *************************************************************************** + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * 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! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * + *************************************************************************** + + + 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. + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong? * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + + http://www.FreeRTOS.org - Documentation, training, latest information, + license and contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool. + + 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. +*/ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/*-----------------------------------------------------------*/ + +/* Count of the critical section nesting depth. */ +unsigned portLONG ulCriticalNesting = 9999; + +/*-----------------------------------------------------------*/ + +/* Registers required to configure the RTI. */ +#define portRTI_GCTRL_REG ( * ( ( volatile unsigned long * ) 0xFFFFFC00 ) ) +#define portRTI_TBCTRL_REG ( * ( ( volatile unsigned long * ) 0xFFFFFC04 ) ) +#define portRTI_COMPCTRL_REG ( * ( ( volatile unsigned long * ) 0xFFFFFC0C ) ) +#define portRTI_CNT0_FRC0_REG ( * ( ( volatile unsigned long * ) 0xFFFFFC10 ) ) +#define portRTI_CNT0_UC0_REG ( * ( ( volatile unsigned long * ) 0xFFFFFC14 ) ) +#define portRTI_CNT0_CPUC0_REG ( * ( ( volatile unsigned long * ) 0xFFFFFC18 ) ) +#define portRTI_CNT0_COMP0_REG ( * ( ( volatile unsigned long * ) 0xFFFFFC50 ) ) +#define portRTI_CNT0_UDCP0_REG ( * ( ( volatile unsigned long * ) 0xFFFFFC54 ) ) +#define portRTI_SETINTENA_REG ( * ( ( volatile unsigned long * ) 0xFFFFFC80 ) ) +#define portRTI_CLEARINTENA_REG ( * ( ( volatile unsigned long * ) 0xFFFFFC84 ) ) +#define portRTI_INTFLAG_REG ( * ( ( volatile unsigned long * ) 0xFFFFFC88 ) ) + + +/* Constants required to set up the initial stack of each task. */ +#define portINITIAL_SPSR ( ( portSTACK_TYPE ) 0x1F ) +#define portINITIAL_FPSCR ( ( portSTACK_TYPE ) 0x00 ) +#define portINSTRUCTION_SIZE ( ( portSTACK_TYPE ) 0x04 ) +#define portTHUMB_MODE_BIT ( ( portSTACK_TYPE ) 0x20 ) + +/* The number of words on the stack frame between the saved Top Of Stack and +R0 (in which the parameters are passed. */ +#define portSPACE_BETWEEN_TOS_AND_PARAMETERS ( 12 ) + +/*-----------------------------------------------------------*/ + +/* vPortStartFirstSTask() is defined in portASM.asm */ +extern void vPortStartFirstTask( void ); + +/*-----------------------------------------------------------*/ + +/* Saved as part of the task context. Set to pdFALSE if the task does not +require an FPU context. */ +unsigned long ulTaskHasFPUContext = 0; + +/*-----------------------------------------------------------*/ + + +/* + * See header file for description. + */ +portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) +{ +portSTACK_TYPE *pxOriginalTOS; + + pxOriginalTOS = pxTopOfStack; + + #if __TI_VFP_SUPPORT__ + { + /* Ensure the stack is correctly aligned on exit. */ + pxTopOfStack--; + } + #endif + + /* Setup the initial stack of the task. The stack is set exactly as + expected by the portRESTORE_CONTEXT() macro. */ + + /* First on the stack is the return address - which is the start of the as + the task has not executed yet. The offset is added to make the return + address appear as it would within an IRQ ISR. */ + *pxTopOfStack = ( portSTACK_TYPE ) pxCode + portINSTRUCTION_SIZE; + pxTopOfStack--; + + *pxTopOfStack = ( portSTACK_TYPE ) 0x00000000; /* R14 */ + pxTopOfStack--; + *pxTopOfStack = ( portSTACK_TYPE ) pxOriginalTOS; /* Stack used when task starts goes in R13. */ + pxTopOfStack--; + + #ifdef portPRELOAD_TASK_REGISTERS + { + *pxTopOfStack = ( portSTACK_TYPE ) 0x12121212; /* R12 */ + pxTopOfStack--; + *pxTopOfStack = ( portSTACK_TYPE ) 0x11111111; /* R11 */ + pxTopOfStack--; + *pxTopOfStack = ( portSTACK_TYPE ) 0x10101010; /* R10 */ + pxTopOfStack--; + *pxTopOfStack = ( portSTACK_TYPE ) 0x09090909; /* R9 */ + pxTopOfStack--; + *pxTopOfStack = ( portSTACK_TYPE ) 0x08080808; /* R8 */ + pxTopOfStack--; + *pxTopOfStack = ( portSTACK_TYPE ) 0x07070707; /* R7 */ + pxTopOfStack--; + *pxTopOfStack = ( portSTACK_TYPE ) 0x06060606; /* R6 */ + pxTopOfStack--; + *pxTopOfStack = ( portSTACK_TYPE ) 0x05050505; /* R5 */ + pxTopOfStack--; + *pxTopOfStack = ( portSTACK_TYPE ) 0x04040404; /* R4 */ + pxTopOfStack--; + *pxTopOfStack = ( portSTACK_TYPE ) 0x03030303; /* R3 */ + pxTopOfStack--; + *pxTopOfStack = ( portSTACK_TYPE ) 0x02020202; /* R2 */ + pxTopOfStack--; + *pxTopOfStack = ( portSTACK_TYPE ) 0x01010101; /* R1 */ + pxTopOfStack--; + } + #else + { + pxTopOfStack -= portSPACE_BETWEEN_TOS_AND_PARAMETERS; + } + #endif + + /* Function parameters are passed in R0. */ + *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */ + pxTopOfStack--; + + /* Set the status register for system mode, with interrupts enabled. */ + *pxTopOfStack = ( portSTACK_TYPE ) ( ( _get_CPSR() & ~0xFF ) | portINITIAL_SPSR ); + + if( ( ( unsigned long ) pxCode & 0x01UL ) != 0x00 ) + { + /* The task will start in thumb mode. */ + *pxTopOfStack |= portTHUMB_MODE_BIT; + } + + #ifdef __TI_VFP_SUPPORT__ + { + pxTopOfStack--; + + /* The last thing on the stack is the tasks ulUsingFPU value, which by + default is set to indicate that the stack frame does not include FPU + registers. */ + *pxTopOfStack = pdFALSE; + } + #endif + + return pxTopOfStack; +} +/*-----------------------------------------------------------*/ + +static void prvSetupTimerInterrupt(void) +{ + /* Disable timer 0. */ + portRTI_GCTRL_REG &= 0xFFFFFFFEUL; + + /* Use the internal counter. */ + portRTI_TBCTRL_REG = 0x00000000U; + + /* COMPSEL0 will use the RTIFRC0 counter. */ + portRTI_COMPCTRL_REG = 0x00000000U; + + /* Initialise the counter and the prescale counter registers. */ + portRTI_CNT0_UC0_REG = 0x00000000U; + portRTI_CNT0_FRC0_REG = 0x00000000U; + + /* Set Prescalar for RTI clock. */ + portRTI_CNT0_CPUC0_REG = 0x00000001U; + portRTI_CNT0_COMP0_REG = ( configCPU_CLOCK_HZ / 2 ) / configTICK_RATE_HZ; + portRTI_CNT0_UDCP0_REG = ( configCPU_CLOCK_HZ / 2 ) / configTICK_RATE_HZ; + + /* Clear interrupts. */ + portRTI_INTFLAG_REG = 0x0007000FU; + portRTI_CLEARINTENA_REG = 0x00070F0FU; + + /* Enable the compare 0 interrupt. */ + portRTI_SETINTENA_REG = 0x00000001U; + portRTI_GCTRL_REG |= 0x00000001U; +} +/*-----------------------------------------------------------*/ + +/* + * See header file for description. + */ +portBASE_TYPE xPortStartScheduler(void) +{ + /* Start the timer that generates the tick ISR. */ + prvSetupTimerInterrupt(); + + /* Reset the critical section nesting count read to execute the first task. */ + ulCriticalNesting = 0; + + /* Start the first task. This is done from portASM.asm as ARM mode must be + used. */ + vPortStartFirstTask(); + + /* Should not get here! */ + return pdFAIL; +} +/*-----------------------------------------------------------*/ + +/* + * See header file for description. + */ +void vPortEndScheduler(void) +{ + /* It is unlikely that the port will require this function as there + is nothing to return to. */ +} +/*-----------------------------------------------------------*/ + +#if configUSE_PREEMPTION == 0 + + /* The cooperative scheduler requires a normal IRQ service routine to + * simply increment the system tick. */ + __interrupt void vPortNonPreemptiveTick( void ) + { + /* clear clock interrupt flag */ + RTI->INTFLAG = 0x00000001; + + /* Increment the tick count - this may make a delaying task ready + to run - but a context switch is not performed. */ + vTaskIncrementTick(); + } + + #else + + /* + ************************************************************************** + * The preemptive scheduler ISR is written in assembler and can be found + * in the portASM.asm file. This will only get used if portUSE_PREEMPTION + * is set to 1 in portmacro.h + ************************************************************************** + */ + void vPortPreemptiveTick( void ); + +#endif +/*-----------------------------------------------------------*/ + + +/* + * Disable interrupts, and keep a count of the nesting depth. + */ +void vPortEnterCritical( void ) +{ + /* Disable interrupts as per portDISABLE_INTERRUPTS(); */ + portDISABLE_INTERRUPTS(); + + /* Now interrupts are disabled ulCriticalNesting can be accessed + directly. Increment ulCriticalNesting to keep a count of how many times + portENTER_CRITICAL() has been called. */ + ulCriticalNesting++; +} +/*-----------------------------------------------------------*/ + +/* + * Decrement the critical nesting count, and if it has reached zero, re-enable + * interrupts. + */ +void vPortExitCritical( void ) +{ + if( ulCriticalNesting > 0 ) + { + /* Decrement the nesting count as we are leaving a critical section. */ + ulCriticalNesting--; + + /* If the nesting level has reached zero then interrupts should be + re-enabled. */ + if( ulCriticalNesting == 0 ) + { + /* Enable interrupts as per portENABLE_INTERRUPTS(). */ + portENABLE_INTERRUPTS(); + } + } +} +/*-----------------------------------------------------------*/ + +#if __TI_VFP_SUPPORT__ + + void vPortTaskUsesFPU( void ) + { + extern void vPortInitialiseFPSCR( void ); + + /* A task is registering the fact that it needs an FPU context. Set the + FPU flag (saved as part of the task context. */ + ulTaskHasFPUContext = pdTRUE; + + /* Initialise the floating point status register. */ + vPortInitialiseFPSCR(); + } + +#endif /* __TI_VFP_SUPPORT__ */ + +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/portASM.asm b/FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/portASM.asm new file mode 100644 index 000000000..af28f68db --- /dev/null +++ b/FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/portASM.asm @@ -0,0 +1,263 @@ +;/* +; FreeRTOS V7.2.0 - Copyright (C) 2012 Real Time Engineers Ltd. +; +; +; *************************************************************************** +; * * +; * FreeRTOS tutorial books are available in pdf and paperback. * +; * Complete, revised, and edited pdf reference manuals are also * +; * available. * +; * * +; * 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! * +; * * +; * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * +; * * +; * Thank you for using FreeRTOS, and thank you for your support! * +; * * +; *************************************************************************** +; +; +; 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. +; +; 1 tab == 4 spaces! +; +; http://www.FreeRTOS.org - Documentation, latest information, license and +; contact details. +; +; http://www.SafeRTOS.com - A version that is certified for use in safety +; critical systems. +; +; http://www.OpenRTOS.com - Commercial support, development, porting, +; licensing and training services. +;*/ + + .text + .arm + .ref vTaskSwitchContext + .ref vTaskIncrementTick + .ref ulTaskHasFPUContext + .ref pxCurrentTCB + +;/*-----------------------------------------------------------*/ +; +; Save Task Context +; +portSAVE_CONTEXT .macro + DSB + + ; Push R0 as we are going to use it + STMDB SP!, {R0} + + ; Set R0 to point to the task stack pointer. + STMDB SP,{SP}^ + SUB SP, SP, #4 + LDMIA SP!,{R0} + + ; Push the return address onto the stack. + STMDB R0!, {LR} + + ; Now LR has been saved, it can be used instead of R0. + MOV LR, R0 + + ; Pop R0 so it can be saved onto the task stack. + LDMIA SP!, {R0} + + ; Push all the system mode registers onto the task stack. + STMDB LR,{R0-LR}^ + SUB LR, LR, #60 + + ; Push the SPSR onto the task stack. + MRS R0, SPSR + STMDB LR!, {R0} + + .if (__TI_VFP_SUPPORT__) + ;Determine if the task maintains an FPU context. + LDR R0, ulFPUContextConst + LDR R0, [R0] + + ; Test the flag + CMP R0, #0 + + ; If the task is not using a floating point context then skip the + ; saving of the FPU registers. + BEQ PC+3 + FSTMDBD LR!, {D0-D15} + FMRX R1, FPSCR + STMFD LR!, {R1} + + ; Save the flag + STMDB LR!, {R0} + .endif + + ; Store the new top of stack for the task. + LDR R0, pxCurrentTCBConst + LDR R0, [R0] + STR LR, [R0] + + .endm + +;/*-----------------------------------------------------------*/ +; +; Restore Task Context +; +portRESTORE_CONTEXT .macro + LDR R0, pxCurrentTCBConst + LDR R0, [R0] + LDR LR, [R0] + + .if (__TI_VFP_SUPPORT__) + ; The floating point context flag is the first thing on the stack. + LDR R0, ulFPUContextConst + LDMFD LR!, {R1} + STR R1, [R0] + + ; Test the flag + CMP R1, #0 + + ; If the task is not using a floating point context then skip the + ; VFP register loads. + BEQ PC+3 + + ; Restore the floating point context. + LDMFD LR!, {R0} + FLDMIAD LR!, {D0-D15} + FMXR FPSCR, R0 + .endif + + ; Get the SPSR from the stack. + LDMFD LR!, {R0} + MSR SPSR_CF, R0 + + ; Restore all system mode registers for the task. + LDMFD LR, {R0-R14}^ + + ; Restore the return address. + LDR LR, [LR, #+60] + + ; And return - correcting the offset in the LR to obtain the + ; correct address. + SUBS PC, LR, #4 + .endm + +;/*-----------------------------------------------------------*/ +; Start the first task by restoring its context. + + .def vPortStartFirstTask + +vPortStartFirstTask: + portRESTORE_CONTEXT + +;/*-----------------------------------------------------------*/ +; Yield to another task. + + .def vPortYieldProcessor + +vPortYieldProcessor: + ; Within an IRQ ISR the link register has an offset from the true return + ; address. SWI doesn't do this. Add the offset manually so the ISR + ; return code can be used. + ADD LR, LR, #4 + + ; First save the context of the current task. + portSAVE_CONTEXT + + ; Select the next task to execute. */ + BL vTaskSwitchContext + + ; Restore the context of the task selected to execute. + portRESTORE_CONTEXT + +;/*-----------------------------------------------------------*/ +; Yield to another task from within the FreeRTOS API + + .def vPortYeildWithinAPI + +vPortYeildWithinAPI: + ; Save the context of the current task. + + portSAVE_CONTEXT + ; Clear SSI flag. + MOVW R0, #0xFFF4 + MOVT R0, #0xFFFF + LDR R0, [R0] + + ; Select the next task to execute. */ + BL vTaskSwitchContext + + ; Restore the context of the task selected to execute. + portRESTORE_CONTEXT + +;/*-----------------------------------------------------------*/ +; Preemptive Tick + + .def vPortPreemptiveTick + +vPortPreemptiveTick: + + ; Save the context of the current task. + portSAVE_CONTEXT + + ; Clear interrupt flag + MOVW R0, #0xFC88 + MOVT R0, #0xFFFF + MOV R1, #1 + STR R1, [R0] + + ; Increment the tick count, making any adjustments to the blocked lists + ; that may be necessary. + BL vTaskIncrementTick + + ; Select the next task to execute. + BL vTaskSwitchContext + + ; Restore the context of the task selected to execute. + portRESTORE_CONTEXT + +;------------------------------------------------------------------------------- + + .def ulPortCountLeadingZeros + +ulPortCountLeadingZeros: + + CLZ R0, R0 + BX LR + +;------------------------------------------------------------------------------- + + .if (__TI_VFP_SUPPORT__) + + .def vPortInitialiseFPSCR + +vPortInitialiseFPSCR: + + MOV R0, #0 + FMXR FPSCR, R0 + BX LR + + .endif ;__TI_VFP_SUPPORT__ + + +pxCurrentTCBConst .word pxCurrentTCB +ulFPUContextConst .word ulTaskHasFPUContext +;------------------------------------------------------------------------------- + diff --git a/FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/portmacro.h b/FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/portmacro.h new file mode 100644 index 000000000..22966d992 --- /dev/null +++ b/FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/portmacro.h @@ -0,0 +1,145 @@ +/* + FreeRTOS V7.2.0 - Copyright (C) 2012 Real Time Engineers Ltd. + + + *************************************************************************** + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * 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! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * + *************************************************************************** + + + 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. + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong? * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + + http://www.FreeRTOS.org - Documentation, training, latest information, + license and contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool. + + 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. +*/ + +#ifndef __PORTMACRO_H__ +#define __PORTMACRO_H__ + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* Type definitions. */ +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT short +#define portSTACK_TYPE unsigned long +#define portBASE_TYPE long + +#if (configUSE_16_BIT_TICKS == 1) + typedef unsigned portSHORT portTickType; + #define portMAX_DELAY (portTickType) 0xFFFF +#else + typedef unsigned portLONG portTickType; + #define portMAX_DELAY (portTickType) 0xFFFFFFFFF +#endif + + +/* Architecture specifics. */ +#define portSTACK_GROWTH (-1) +#define portTICK_RATE_MS ((portTickType) 1000 / configTICK_RATE_HZ) +#define portBYTE_ALIGNMENT 8 + +/* Critical section handling. */ +extern void vPortEnterCritical(void); +extern void vPortExitCritical(void); +#define portENTER_CRITICAL() vPortEnterCritical() +#define portEXIT_CRITICAL() vPortExitCritical() +#define portDISABLE_INTERRUPTS() asm( " CPSID I" ) +#define portENABLE_INTERRUPTS() asm( " CPSIE I" ) + +/* Scheduler utilities. */ +#define portYIELD() _call_swi( 0 ) +#define portSYS_SSIR1_REG ( * ( ( volatile unsigned long * ) 0xFFFFFFB0 ) ) +#define portSYS_SSIR1_SSKEY ( 0x7500UL ) +#define portYIELD_WITHIN_API() { portSYS_SSIR1_REG = portSYS_SSIR1_SSKEY; ( void ) portSYS_SSIR1_REG; } +#define portYIELD_FROM_ISR() { portSYS_SSIR1_REG = portSYS_SSIR1_SSKEY; ( void ) portSYS_SSIR1_REG; } + +/* Architecture specific optimisations. */ +#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 + + /* Generic helper function. */ + unsigned long ulPortCountLeadingZeros( unsigned long ulBitmap ); + + /* Check the configuration. */ + #if( configMAX_PRIORITIES > 32 ) + #error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice. + #endif + + /* Store/clear the ready priorities in a bit map. */ + #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) + #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ) + + /*-----------------------------------------------------------*/ + + #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - ulPortCountLeadingZeros( ( uxReadyPriorities ) ) ) + +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + + +/* Task function macros as described on the FreeRTOS.org WEB site. */ +#define portTASK_FUNCTION(vFunction, pvParameters) void vFunction(void *pvParameters) +#define portTASK_FUNCTION_PROTO(vFunction, pvParameters) void vFunction(void *pvParameters) + +#endif /* __PORTMACRO_H__ */ + diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c index a02804ade..15bf7b4e5 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c @@ -40,7 +40,7 @@ FreeRTOS WEB site. 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -50,17 +50,17 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest information, + + http://www.FreeRTOS.org - Documentation, training, latest information, license and contact details. - + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under + 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 + provide a safety engineered and independently SIL3 certified version under the SafeRTOS brand: http://www.SafeRTOS.com. */ @@ -79,17 +79,35 @@ FreeRTOS.org versions prior to V4.4.0 did not include this definition. */ #define configKERNEL_INTERRUPT_PRIORITY 255 #endif -/* Constants required to manipulate the NVIC. */ -#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long *) 0xe000e010 ) -#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long *) 0xe000e014 ) -#define portNVIC_INT_CTRL ( ( volatile unsigned long *) 0xe000ed04 ) -#define portNVIC_SYSPRI2 ( ( volatile unsigned long *) 0xe000ed20 ) -#define portNVIC_SYSTICK_CLK 0x00000004 -#define portNVIC_SYSTICK_INT 0x00000002 -#define portNVIC_SYSTICK_ENABLE 0x00000001 -#define portNVIC_PENDSVSET 0x10000000 -#define portNVIC_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 ) -#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 ) +#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 */ + +/* 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 ) << 16UL ) +#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL ) /* Constants required to set up the initial stack. */ #define portINITIAL_XPSR ( 0x01000000 ) @@ -119,6 +137,22 @@ void vPortSVCHandler( void ) __attribute__ (( naked )); */ static void prvPortStartFirstTask( void ) __attribute__ (( naked )); +/*-----------------------------------------------------------*/ + +/* + * The number of SysTick increments that make up one tick period. + */ +static unsigned long ulTimerReloadValueForOneTick = 0; + +/* + * The maximum number of tick periods that can be suppressed is limited by the + * 24 bit resolution of the SysTick timer. + */ +#if configUSE_TICKLESS_IDLE == 1 + static unsigned long xMaximumPossibleSuppressedTicks = 0; +#endif /* configUSE_TICKLESS_IDLE */ + + /*-----------------------------------------------------------*/ /* @@ -180,13 +214,13 @@ static void prvPortStartFirstTask( void ) */ portBASE_TYPE xPortStartScheduler( void ) { - /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. + /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY ); /* Make PendSV, CallSV and SysTick the same priroity as the kernel. */ - *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; - *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; + 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. */ @@ -213,7 +247,7 @@ void vPortEndScheduler( void ) void vPortYieldFromISR( void ) { /* Set a PendSV to request a context switch. */ - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } /*-----------------------------------------------------------*/ @@ -234,6 +268,34 @@ void vPortExitCritical( void ) } /*-----------------------------------------------------------*/ +__attribute__(( naked )) unsigned long ulPortSetInterruptMask( void ) +{ + __asm volatile \ + ( \ + " mrs r0, basepri \n" \ + " mov r1, %0 \n" \ + " msr basepri, r1 \n" \ + " bx lr \n" \ + :: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "r0", "r1" \ + ); + + /* This return will not be reached but is necessary to prevent compiler + warnings. */ + return 0; +} +/*-----------------------------------------------------------*/ + +__attribute__(( naked )) void vPortClearInterruptMask( unsigned long ulNewMaskValue ) +{ + __asm volatile \ + ( \ + " msr basepri, r0 \n" \ + " bx lr \n" \ + :::"r0" \ + ); +} +/*-----------------------------------------------------------*/ + void xPortPendSVHandler( void ) { /* This is a naked function. */ @@ -271,30 +333,142 @@ void xPortPendSVHandler( void ) void xPortSysTickHandler( void ) { -unsigned long ulDummy; - /* If using preemption, also force a context switch. */ #if configUSE_PREEMPTION == 1 - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; #endif - ulDummy = portSET_INTERRUPT_MASK_FROM_ISR(); + #if configUSE_TICKLESS_IDLE == 1 + portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; + #endif + + ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); { vTaskIncrementTick(); } - portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); } /*-----------------------------------------------------------*/ +#if configUSE_TICKLESS_IDLE == 1 + + __attribute__((weak)) void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ) + { + unsigned long ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickIncrements; + + /* Make sure the SysTick reload value does not overflow the counter. */ + if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) + { + xExpectedIdleTime = xMaximumPossibleSuppressedTicks; + } + + /* 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 ) ); + 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; + + /* 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 ) + { + /* Restart SysTick. */ + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + } + 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 ) ); + portNVIC_SYSTICK_LOAD_REG = ulReloadValue; + + /* Clear the SysTick count flag and set the count value back to + zero. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + + /* 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(); + __asm volatile( "wfi" ); + portPOST_SLEEP_PROCESSING(); + + /* Stop SysTick. Again, 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; + + 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 ); + + /* The tick interrupt handler will already have pended the tick + processing in the kernel. As the pending tick will be + processed as soon as this function exits, the tick value + maintained by the tick is stepped forward by one less than the + time spent waiting. */ + ulCompleteTickPeriods = xExpectedIdleTime - 1UL; + } + 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; + + /* How many complete tick periods passed while the processor + was waiting? */ + ulCompleteTickPeriods = ulCompletedSysTickIncrements / ulTimerReloadValueForOneTick; + + /* The reload value is set to whatever fraction of a single tick + period remains. */ + portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1 ) * ulTimerReloadValueForOneTick ) - ulCompletedSysTickIncrements; + } + + /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG + again, then set portNVIC_SYSTICK_LOAD_REG back to its standard + value. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + + vTaskStepTick( ulCompleteTickPeriods ); + } + } + +#endif /* #if configUSE_TICKLESS_IDLE */ +/*-----------------------------------------------------------*/ + /* * Setup the systick timer to generate the tick interrupts at the required * frequency. */ void prvSetupTimerInterrupt( void ) { + /* Calculate the constants required to configure the tick interrupt. */ + ulTimerReloadValueForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + #if configUSE_TICKLESS_IDLE == 1 + xMaximumPossibleSuppressedTicks = 0xffffffUL / ( ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL ); + #endif /* configUSE_TICKLESS_IDLE */ + /* Configure SysTick to interrupt at the requested rate. */ - *(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; - *(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; + portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h b/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h index 75979f303..d244b7896 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h +++ b/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h @@ -109,62 +109,36 @@ extern "C" { /* Scheduler utilities. */ extern void vPortYieldFromISR( void ); - #define portYIELD() vPortYieldFromISR() - #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR() /*-----------------------------------------------------------*/ - /* Critical section management. */ - -/* - * Set basepri to portMAX_SYSCALL_INTERRUPT_PRIORITY without effecting other - * registers. r0 is clobbered. - */ -#define portSET_INTERRUPT_MASK() \ - __asm volatile \ - ( \ - " mov r0, %0 \n" \ - " msr basepri, r0 \n" \ - ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY):"r0" \ - ) - -/* - * Set basepri back to 0 without effective other registers. - * r0 is clobbered. FAQ: Setting BASEPRI to 0 is not a bug. Please see - * http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. - */ -#define portCLEAR_INTERRUPT_MASK() \ - __asm volatile \ - ( \ - " mov r0, #0 \n" \ - " msr basepri, r0 \n" \ - :::"r0" \ - ) - -/* FAQ: Setting BASEPRI to 0 in portCLEAR_INTERRUPT_MASK_FROM_ISR() is not a -bug. Please see http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before -disagreeing. */ -#define portSET_INTERRUPT_MASK_FROM_ISR() 0;portSET_INTERRUPT_MASK() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK();(void)x - - extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); - -#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK() -#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK() -#define portENTER_CRITICAL() vPortEnterCritical() -#define portEXIT_CRITICAL() vPortExitCritical() +extern unsigned long ulPortSetInterruptMask( void ); +extern void vPortClearInterruptMask( unsigned long ulNewMaskValue ); +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x) +#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() +#define portENABLE_INTERRUPTS() vPortClearInterruptMask(0) +#define portENTER_CRITICAL() vPortEnterCritical() +#define portEXIT_CRITICAL() vPortExitCritical() /*-----------------------------------------------------------*/ -/* Task function macros as described on the FreeRTOS.org WEB site. */ +/* Task function macros as described on the FreeRTOS.org WEB site. These are +not necessary for to use this port. They are defined so the common demo files +(which build with all the ports) will build. */ #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) +/*-----------------------------------------------------------*/ -#define portNOP() +/* Tickless idle/low power functionality. */ +extern void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ); +#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime ) +/*-----------------------------------------------------------*/ +/* Architecture specific optimisations. */ #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 /* Generic helper function. */ @@ -189,8 +163,12 @@ extern void vPortExitCritical( void ); #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - ucPortCountLeadingZeros( ( uxReadyPriorities ) ) ) -#endif /* taskRECORD_READY_PRIORITY */ +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + +/*-----------------------------------------------------------*/ +/* portNOP() is not required by this port. */ +#define portNOP() #ifdef __cplusplus } diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c index c2c143fe2..34e0a4632 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c @@ -40,7 +40,7 @@ FreeRTOS WEB site. 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -50,17 +50,17 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest information, + + http://www.FreeRTOS.org - Documentation, training, latest information, license and contact details. - + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under + 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 + provide a safety engineered and independently SIL3 certified version under the SafeRTOS brand: http://www.SafeRTOS.com. */ @@ -76,17 +76,35 @@ #error This port can only be used when the project options are configured to enable hardware floating point support. #endif -/* Constants required to manipulate the NVIC. */ -#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long * ) 0xe000e010 ) -#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long * ) 0xe000e014 ) -#define portNVIC_INT_CTRL ( ( volatile unsigned long * ) 0xe000ed04 ) -#define portNVIC_SYSPRI2 ( ( volatile unsigned long * ) 0xe000ed20 ) -#define portNVIC_SYSTICK_CLK 0x00000004 -#define portNVIC_SYSTICK_INT 0x00000002 -#define portNVIC_SYSTICK_ENABLE 0x00000001 -#define portNVIC_PENDSVSET 0x10000000 -#define portNVIC_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 ) -#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 ) +#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 */ + +/* 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 ) << 16UL ) +#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL ) /* Constants required to manipulate the VFP. */ #define portFPCCR ( ( volatile unsigned long * ) 0xe000ef34 ) /* Floating point context control register. */ @@ -119,13 +137,28 @@ void vPortSVCHandler( void ) __attribute__ (( naked )); /* * Start first task is a separate function so it can be tested in isolation. */ -static void vPortStartFirstTask( void ) __attribute__ (( naked )); +static void prvPortStartFirstTask( void ) __attribute__ (( naked )); /* * Function to enable the VFP. */ static void vPortEnableVFP( void ) __attribute__ (( naked )); +/*-----------------------------------------------------------*/ + +/* + * The number of SysTick increments that make up one tick period. + */ +static unsigned long ulTimerReloadValueForOneTick = 0; + +/* + * The maximum number of tick periods that can be suppressed is limited by the + * 24 bit resolution of the SysTick timer. + */ +#if configUSE_TICKLESS_IDLE == 1 + static unsigned long xMaximumPossibleSuppressedTicks = 0; +#endif /* configUSE_TICKLESS_IDLE */ + /*-----------------------------------------------------------*/ @@ -180,7 +213,7 @@ void vPortSVCHandler( void ) } /*-----------------------------------------------------------*/ -static void vPortStartFirstTask( void ) +static void prvPortStartFirstTask( void ) { __asm volatile( " ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */ @@ -199,13 +232,13 @@ static void vPortStartFirstTask( void ) */ portBASE_TYPE xPortStartScheduler( void ) { - /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. + /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY ); - /* Make PendSV and SysTick the lowest priority interrupts. */ - *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; - *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; + /* Make PendSV, CallSV and SysTick the same priroity as the kernel. */ + 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. */ @@ -221,7 +254,7 @@ portBASE_TYPE xPortStartScheduler( void ) *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS; /* Start the first task. */ - vPortStartFirstTask(); + prvPortStartFirstTask(); /* Should not get here! */ return 0; @@ -238,7 +271,7 @@ void vPortEndScheduler( void ) void vPortYieldFromISR( void ) { /* Set a PendSV to request a context switch. */ - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } /*-----------------------------------------------------------*/ @@ -259,6 +292,34 @@ void vPortExitCritical( void ) } /*-----------------------------------------------------------*/ +__attribute__(( naked )) unsigned long ulPortSetInterruptMask( void ) +{ + __asm volatile \ + ( \ + " mrs r0, basepri \n" \ + " mov r1, %0 \n" \ + " msr basepri, r1 \n" \ + " bx lr \n" \ + :: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "r0", "r1" \ + ); + + /* This return will not be reached but is necessary to prevent compiler + warnings. */ + return 0; +} +/*-----------------------------------------------------------*/ + +__attribute__(( naked )) void vPortClearInterruptMask( unsigned long ulNewMaskValue ) +{ + __asm volatile \ + ( \ + " msr basepri, r0 \n" \ + " bx lr \n" \ + :::"r0" \ + ); +} +/*-----------------------------------------------------------*/ + void xPortPendSVHandler( void ) { /* This is a naked function. */ @@ -307,30 +368,143 @@ void xPortPendSVHandler( void ) void xPortSysTickHandler( void ) { -unsigned long ulDummy; - /* If using preemption, also force a context switch. */ #if configUSE_PREEMPTION == 1 - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; + #endif + + #if configUSE_TICKLESS_IDLE == 1 + portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; #endif - ulDummy = portSET_INTERRUPT_MASK_FROM_ISR(); + ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); { vTaskIncrementTick(); } - portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); } /*-----------------------------------------------------------*/ +#if configUSE_TICKLESS_IDLE == 1 + + __attribute__((weak)) void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ) + { + unsigned long ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickIncrements; + + /* Make sure the SysTick reload value does not overflow the counter. */ + if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) + { + xExpectedIdleTime = xMaximumPossibleSuppressedTicks; + } + + /* 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 ) ); + 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; + + /* 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 ) + { + /* Restart SysTick. */ + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + } + 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 ) ); + portNVIC_SYSTICK_LOAD_REG = ulReloadValue; + + /* Clear the SysTick count flag and set the count value back to + zero. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + + /* 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(); + __asm volatile( "wfi" ); + portPOST_SLEEP_PROCESSING(); + + /* Stop SysTick. Again, 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; + + 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 ); + + /* The tick interrupt handler will already have pended the tick + processing in the kernel. As the pending tick will be + processed as soon as this function exits, the tick value + maintained by the tick is stepped forward by one less than the + time spent waiting. */ + ulCompleteTickPeriods = xExpectedIdleTime - 1UL; + } + 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; + + /* How many complete tick periods passed while the processor + was waiting? */ + ulCompleteTickPeriods = ulCompletedSysTickIncrements / ulTimerReloadValueForOneTick; + + /* The reload value is set to whatever fraction of a single tick + period remains. */ + portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1 ) * ulTimerReloadValueForOneTick ) - ulCompletedSysTickIncrements; + } + + /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG + again, then set portNVIC_SYSTICK_LOAD_REG back to its standard + value. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + + vTaskStepTick( ulCompleteTickPeriods ); + } + } + +#endif /* #if configUSE_TICKLESS_IDLE */ +/*-----------------------------------------------------------*/ + /* * Setup the systick timer to generate the tick interrupts at the required * frequency. */ void prvSetupTimerInterrupt( void ) { + /* Calculate the constants required to configure the tick interrupt. */ + ulTimerReloadValueForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + #if configUSE_TICKLESS_IDLE == 1 + xMaximumPossibleSuppressedTicks = 0xffffffUL / ( ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL ); + #endif /* configUSE_TICKLESS_IDLE */ + + /* Configure SysTick to interrupt at the requested rate. */ - *(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; - *(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; + portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h b/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h index afd7256e1..e710eb96a 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h +++ b/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h @@ -115,48 +115,17 @@ extern void vPortYieldFromISR( void ); #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR() /*-----------------------------------------------------------*/ - /* Critical section management. */ - -/* - * Set basepri to portMAX_SYSCALL_INTERRUPT_PRIORITY without effecting other - * registers. r0 is clobbered. - */ -#define portSET_INTERRUPT_MASK() \ - __asm volatile \ - ( \ - " mov r0, %0 \n" \ - " msr basepri, r0 \n" \ - ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY):"r0" \ - ) - -/* - * Set basepri back to 0 without effective other registers. - * r0 is clobbered. FAQ: Setting BASEPRI to 0 is not a bug. Please see - * http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. - */ -#define portCLEAR_INTERRUPT_MASK() \ - __asm volatile \ - ( \ - " mov r0, #0 \n" \ - " msr basepri, r0 \n" \ - :::"r0" \ - ) - -/* FAQ: Setting BASEPRI to 0 in portCLEAR_INTERRUPT_MASK_FROM_ISR() is not a -bug. Please see http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before -disagreeing. */ -#define portSET_INTERRUPT_MASK_FROM_ISR() 0;portSET_INTERRUPT_MASK() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK();(void)x - - extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); - -#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK() -#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK() -#define portENTER_CRITICAL() vPortEnterCritical() -#define portEXIT_CRITICAL() vPortExitCritical() +extern unsigned long ulPortSetInterruptMask( void ); +extern void vPortClearInterruptMask( unsigned long ulNewMaskValue ); +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x) +#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() +#define portENABLE_INTERRUPTS() vPortClearInterruptMask(0) +#define portENTER_CRITICAL() vPortEnterCritical() +#define portEXIT_CRITICAL() vPortExitCritical() /* There are an uneven number of items on the initial stack, so portALIGNMENT_ASSERT_pxCurrentTCB() will trigger false positive asserts. */ @@ -164,16 +133,23 @@ portALIGNMENT_ASSERT_pxCurrentTCB() will trigger false positive asserts. */ /*-----------------------------------------------------------*/ -/* Task function macros as described on the FreeRTOS.org WEB site. */ +/* Task function macros as described on the FreeRTOS.org WEB site. These are +not necessary for to use this port. They are defined so the common demo files +(which build with all the ports) will build. */ #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) +/*-----------------------------------------------------------*/ -#define portNOP() +/* Tickless idle/low power functionality. */ +extern void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ); +#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime ) +/*-----------------------------------------------------------*/ +/* Architecture specific optimisations. */ #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 /* Generic helper function. */ - __attribute__( ( always_inline ) ) static inline unsigned char ucPortCountLeadingZeros( ulBitmap ) + __attribute__( ( always_inline ) ) static inline unsigned char ucPortCountLeadingZeros( unsigned long ulBitmap ) { unsigned char ucReturn; @@ -194,8 +170,12 @@ portALIGNMENT_ASSERT_pxCurrentTCB() will trigger false positive asserts. */ #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - ucPortCountLeadingZeros( ( uxReadyPriorities ) ) ) -#endif /* taskRECORD_READY_PRIORITY */ +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ +/*-----------------------------------------------------------*/ + +/* portNOP() is not required by this port. */ +#define portNOP() #ifdef __cplusplus } diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c b/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c index 44f3ac896..c4368b68b 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c +++ b/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c @@ -1,6 +1,6 @@ /* FreeRTOS V7.2.0 - Copyright (C) 2012 Real Time Engineers Ltd. - + *************************************************************************** * * @@ -40,7 +40,7 @@ FreeRTOS WEB site. 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -50,17 +50,17 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest information, + + http://www.FreeRTOS.org - Documentation, training, latest information, license and contact details. - + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under + 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 + provide a safety engineered and independently SIL3 certified version under the SafeRTOS brand: http://www.SafeRTOS.com. */ @@ -76,15 +76,33 @@ #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html #endif -/* Constants required to manipulate the NVIC. */ -#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long *) 0xe000e010 ) -#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long *) 0xe000e014 ) -#define portNVIC_INT_CTRL ( ( volatile unsigned long *) 0xe000ed04 ) -#define portNVIC_SYSPRI2 ( ( volatile unsigned long *) 0xe000ed20 ) -#define portNVIC_SYSTICK_CLK 0x00000004 -#define portNVIC_SYSTICK_INT 0x00000002 -#define portNVIC_SYSTICK_ENABLE 0x00000001 -#define portNVIC_PENDSVSET 0x10000000 +#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 */ + +/* 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 ) @@ -119,6 +137,21 @@ extern void vPortStartFirstTask( void ); /*-----------------------------------------------------------*/ +/* + * The number of SysTick increments that make up one tick period. + */ +static unsigned long ulTimerReloadValueForOneTick = 0; + +/* + * The maximum number of tick periods that can be suppressed is limited by the + * 24 bit resolution of the SysTick timer. + */ +#if configUSE_TICKLESS_IDLE == 1 + static unsigned long xMaximumPossibleSuppressedTicks = 0; +#endif /* configUSE_TICKLESS_IDLE */ + +/*-----------------------------------------------------------*/ + /* * See header file for description. */ @@ -146,13 +179,13 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE portBASE_TYPE xPortStartScheduler( void ) { /* Make PendSV and SysTick the lowest priority interrupts. */ - *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; - *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; + 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(); - + /* Initialise the critical nesting count ready for the first task. */ uxCriticalNesting = 0; @@ -174,7 +207,7 @@ void vPortEndScheduler( void ) void vPortYieldFromISR( void ) { /* Set a PendSV to request a context switch. */ - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } /*-----------------------------------------------------------*/ @@ -197,30 +230,142 @@ void vPortExitCritical( void ) void xPortSysTickHandler( void ) { -unsigned long ulDummy; - /* If using preemption, also force a context switch. */ #if configUSE_PREEMPTION == 1 - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; #endif - ulDummy = portSET_INTERRUPT_MASK_FROM_ISR(); + #if configUSE_TICKLESS_IDLE == 1 + portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; + #endif + + ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); { vTaskIncrementTick(); } - portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); } /*-----------------------------------------------------------*/ +#if configUSE_TICKLESS_IDLE == 1 + + __weak void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ) + { + unsigned long ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickIncrements; + + /* Make sure the SysTick reload value does not overflow the counter. */ + if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) + { + xExpectedIdleTime = xMaximumPossibleSuppressedTicks; + } + + /* 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 ) ); + 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; + + /* 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 ) + { + /* Restart SysTick. */ + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + } + 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 ) ); + portNVIC_SYSTICK_LOAD_REG = ulReloadValue; + + /* Clear the SysTick count flag and set the count value back to + zero. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + + /* 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(); + + /* Stop SysTick. Again, 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; + + 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 ); + + /* The tick interrupt handler will already have pended the tick + processing in the kernel. As the pending tick will be + processed as soon as this function exits, the tick value + maintained by the tick is stepped forward by one less than the + time spent waiting. */ + ulCompleteTickPeriods = xExpectedIdleTime - 1UL; + } + 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; + + /* How many complete tick periods passed while the processor + was waiting? */ + ulCompleteTickPeriods = ulCompletedSysTickIncrements / ulTimerReloadValueForOneTick; + + /* The reload value is set to whatever fraction of a single tick + period remains. */ + portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1 ) * ulTimerReloadValueForOneTick ) - ulCompletedSysTickIncrements; + } + + /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG + again, then set portNVIC_SYSTICK_LOAD_REG back to its standard + value. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + + vTaskStepTick( ulCompleteTickPeriods ); + } + } + +#endif /* #if configUSE_TICKLESS_IDLE */ +/*-----------------------------------------------------------*/ + /* * Setup the systick timer to generate the tick interrupts at the required * frequency. */ void prvSetupTimerInterrupt( void ) { + /* Configure the constants required to setup the tick interrupt. */ + ulTimerReloadValueForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + #if configUSE_TICKLESS_IDLE == 1 + xMaximumPossibleSuppressedTicks = 0xffffffUL / ( ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL ); + #endif /* configUSE_TICKLESS_IDLE */ + /* Configure SysTick to interrupt at the requested rate. */ - *(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; - *(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; + portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM3/portasm.s b/FreeRTOS/Source/portable/IAR/ARM_CM3/portasm.s index c9e0bb3ca..9c766460b 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM3/portasm.s +++ b/FreeRTOS/Source/portable/IAR/ARM_CM3/portasm.s @@ -40,7 +40,7 @@ FreeRTOS WEB site. 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -50,51 +50,36 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest information, + + http://www.FreeRTOS.org - Documentation, training, latest information, license and contact details. - + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under + 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 + provide a safety engineered and independently SIL3 certified version under the SafeRTOS brand: http://www.SafeRTOS.com. */ #include -/* For backward compatibility, ensure configKERNEL_INTERRUPT_PRIORITY is -defined. The value zero should also ensure backward compatibility. -FreeRTOS.org versions prior to V4.3.0 did not include this definition. */ -#ifndef configKERNEL_INTERRUPT_PRIORITY - #define configKERNEL_INTERRUPT_PRIORITY 0 -#endif - - RSEG CODE:CODE(2) thumb - EXTERN vPortYieldFromISR EXTERN pxCurrentTCB EXTERN vTaskSwitchContext - PUBLIC vSetMSP PUBLIC xPortPendSVHandler - PUBLIC vPortSetInterruptMask + PUBLIC ulPortSetInterruptMask PUBLIC vPortClearInterruptMask PUBLIC vPortSVCHandler PUBLIC vPortStartFirstTask -/*-----------------------------------------------------------*/ -vSetMSP - msr msp, r0 - bx lr - /*-----------------------------------------------------------*/ xPortPendSVHandler: @@ -122,28 +107,26 @@ xPortPendSVHandler: /*-----------------------------------------------------------*/ -vPortSetInterruptMask: - mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY - msr BASEPRI, r0 - +ulPortSetInterruptMask: + mrs r0, basepri + mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY + msr basepri, r1 bx r14 /*-----------------------------------------------------------*/ vPortClearInterruptMask: - /* FAQ: Setting BASEPRI to 0 is not a bug. Please see - http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */ - mov r0, #0 - msr BASEPRI, r0 - + msr basepri, r0 bx r14 /*-----------------------------------------------------------*/ -vPortSVCHandler; +vPortSVCHandler: + /* Get the location of the current TCB. */ ldr r3, =pxCurrentTCB ldr r1, [r3] ldr r0, [r1] + /* Pop the core registers. */ ldmia r0!, {r4-r11} msr psp, r0 mov r0, #0 diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM3/portmacro.h b/FreeRTOS/Source/portable/IAR/ARM_CM3/portmacro.h index 662451a61..034f06c44 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM3/portmacro.h +++ b/FreeRTOS/Source/portable/IAR/ARM_CM3/portmacro.h @@ -106,15 +106,13 @@ extern "C" { #define portBYTE_ALIGNMENT 8 /*-----------------------------------------------------------*/ - /* Scheduler utilities. */ extern void vPortYieldFromISR( void ); - #define portYIELD() vPortYieldFromISR() - #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR() /*-----------------------------------------------------------*/ +/* Architecture specific optimisations. */ #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 /* Check the configuration. */ @@ -131,32 +129,36 @@ extern void vPortYieldFromISR( void ); #include #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __CLZ( ( uxReadyPriorities ) ) ) -#endif /* taskRECORD_READY_PRIORITY */ - +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ +/*-----------------------------------------------------------*/ /* Critical section management. */ - extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); -extern void vPortSetInterruptMask( void ); -extern void vPortClearInterruptMask( void ); +extern unsigned long ulPortSetInterruptMask( void ); +extern void vPortClearInterruptMask( unsigned long ulNewMask ); -#define portDISABLE_INTERRUPTS() vPortSetInterruptMask() -#define portENABLE_INTERRUPTS() vPortClearInterruptMask() +#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() +#define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 ) #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical() +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask( x ) +/*-----------------------------------------------------------*/ -/* FAQ: Setting BASEPRI to 0 is not a bug. Please see -http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */ -#define portSET_INTERRUPT_MASK_FROM_ISR() 0;vPortSetInterruptMask() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask();(void)x - +/* Tickless/low power functionality. */ +extern void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ); +#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime ) /*-----------------------------------------------------------*/ -/* Task function macros as described on the FreeRTOS.org WEB site. */ +/* Task function macros as described on the FreeRTOS.org WEB site. These are +not necessary for to use this port. They are defined so the common demo files +(which build with all the ports) will build. */ #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) +/*-----------------------------------------------------------*/ +/* portNOP() is not required by this port. */ #define portNOP() #ifdef __cplusplus diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c b/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c index 1ca5e6877..6d958c2dc 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c @@ -1,6 +1,6 @@ /* FreeRTOS V7.2.0 - Copyright (C) 2012 Real Time Engineers Ltd. - + *************************************************************************** * * @@ -40,7 +40,7 @@ FreeRTOS WEB site. 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -50,17 +50,17 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest information, + + http://www.FreeRTOS.org - Documentation, training, latest information, license and contact details. - + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under + 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 + provide a safety engineered and independently SIL3 certified version under the SafeRTOS brand: http://www.SafeRTOS.com. */ @@ -80,15 +80,33 @@ #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html #endif -/* Constants required to manipulate the NVIC. */ -#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long * ) 0xe000e010 ) -#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long * ) 0xe000e014 ) -#define portNVIC_INT_CTRL ( ( volatile unsigned long * ) 0xe000ed04 ) -#define portNVIC_SYSPRI2 ( ( volatile unsigned long * ) 0xe000ed20 ) -#define portNVIC_SYSTICK_CLK 0x00000004 -#define portNVIC_SYSTICK_INT 0x00000002 -#define portNVIC_SYSTICK_ENABLE 0x00000001 -#define portNVIC_PENDSVSET 0x10000000 +#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 */ + +/* 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 ) @@ -120,12 +138,27 @@ void xPortSysTickHandler( void ); extern void vPortStartFirstTask( void ); /* - * Functions defined in portasm.s to enable the VFP. + * Turn the VFP on. */ extern void vPortEnableVFP( void ); /*-----------------------------------------------------------*/ +/* + * The number of SysTick increments that make up one tick period. + */ +static unsigned long ulTimerReloadValueForOneTick = 0; + +/* + * The maximum number of tick periods that can be suppressed is limited by the + * 24 bit resolution of the SysTick timer. + */ +#if configUSE_TICKLESS_IDLE == 1 + static unsigned long xMaximumPossibleSuppressedTicks = 0; +#endif /* configUSE_TICKLESS_IDLE */ + +/*-----------------------------------------------------------*/ + /* * See header file for description. */ @@ -133,17 +166,17 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE { /* Simulate the stack frame as it would be created by a context switch interrupt. */ - + /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts, and to ensure alignment. */ pxTopOfStack--; - + *pxTopOfStack = portINITIAL_XPSR; /* xPSR */ pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */ pxTopOfStack--; *pxTopOfStack = 0; /* LR */ - + /* Save code space by skipping register initialisation. */ pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */ @@ -154,7 +187,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE *pxTopOfStack = portINITIAL_EXEC_RETURN; pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */ - + return pxTopOfStack; } /*-----------------------------------------------------------*/ @@ -165,22 +198,22 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE portBASE_TYPE xPortStartScheduler( void ) { /* Make PendSV and SysTick the lowest priority interrupts. */ - *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; - *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; + 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(); - + /* Initialise the critical nesting count ready for the first task. */ uxCriticalNesting = 0; /* Ensure the VFP is enabled - it should be anyway. */ vPortEnableVFP(); - + /* Lazy save always. */ *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS; - + /* Start the first task. */ vPortStartFirstTask(); @@ -199,7 +232,7 @@ void vPortEndScheduler( void ) void vPortYieldFromISR( void ) { /* Set a PendSV to request a context switch. */ - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } /*-----------------------------------------------------------*/ @@ -222,30 +255,142 @@ void vPortExitCritical( void ) void xPortSysTickHandler( void ) { -unsigned long ulDummy; - /* If using preemption, also force a context switch. */ #if configUSE_PREEMPTION == 1 - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; + #endif + + #if configUSE_TICKLESS_IDLE == 1 + portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; #endif - ulDummy = portSET_INTERRUPT_MASK_FROM_ISR(); + ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); { vTaskIncrementTick(); } - portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); } /*-----------------------------------------------------------*/ +#if configUSE_TICKLESS_IDLE == 1 + + __weak void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ) + { + unsigned long ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickIncrements; + + /* Make sure the SysTick reload value does not overflow the counter. */ + if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) + { + xExpectedIdleTime = xMaximumPossibleSuppressedTicks; + } + + /* 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 ) ); + 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; + + /* 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 ) + { + /* Restart SysTick. */ + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + } + 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 ) ); + portNVIC_SYSTICK_LOAD_REG = ulReloadValue; + + /* Clear the SysTick count flag and set the count value back to + zero. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + + /* 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(); + + /* Stop SysTick. Again, 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; + + 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 ); + + /* The tick interrupt handler will already have pended the tick + processing in the kernel. As the pending tick will be + processed as soon as this function exits, the tick value + maintained by the tick is stepped forward by one less than the + time spent waiting. */ + ulCompleteTickPeriods = xExpectedIdleTime - 1UL; + } + 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; + + /* How many complete tick periods passed while the processor + was waiting? */ + ulCompleteTickPeriods = ulCompletedSysTickIncrements / ulTimerReloadValueForOneTick; + + /* The reload value is set to whatever fraction of a single tick + period remains. */ + portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1 ) * ulTimerReloadValueForOneTick ) - ulCompletedSysTickIncrements; + } + + /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG + again, then set portNVIC_SYSTICK_LOAD_REG back to its standard + value. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + + vTaskStepTick( ulCompleteTickPeriods ); + } + } + +#endif /* #if configUSE_TICKLESS_IDLE */ +/*-----------------------------------------------------------*/ + /* * Setup the systick timer to generate the tick interrupts at the required * frequency. */ void prvSetupTimerInterrupt( void ) { + /* Configure the constants required to setup the tick interrupt. */ + ulTimerReloadValueForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + #if configUSE_TICKLESS_IDLE == 1 + xMaximumPossibleSuppressedTicks = 0xffffffUL / ( ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL ); + #endif /* configUSE_TICKLESS_IDLE */ + /* Configure SysTick to interrupt at the requested rate. */ - *(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; - *(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; + portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM4F/portasm.s b/FreeRTOS/Source/portable/IAR/ARM_CM4F/portasm.s index 26eb6267e..5ecd502d1 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM4F/portasm.s +++ b/FreeRTOS/Source/portable/IAR/ARM_CM4F/portasm.s @@ -73,7 +73,7 @@ EXTERN vTaskSwitchContext PUBLIC xPortPendSVHandler - PUBLIC vPortSetInterruptMask + PUBLIC ulPortSetInterruptMask PUBLIC vPortClearInterruptMask PUBLIC vPortSVCHandler PUBLIC vPortStartFirstTask @@ -127,20 +127,16 @@ xPortPendSVHandler: /*-----------------------------------------------------------*/ -vPortSetInterruptMask: - mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY - msr BASEPRI, r0 - +ulPortSetInterruptMask: + mrs r0, basepri + mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY + msr basepri, r1 bx r14 /*-----------------------------------------------------------*/ vPortClearInterruptMask: - /* FAQ: Setting BASEPRI to 0 is not a bug. Please see - http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */ - mov r0, #0 - msr BASEPRI, r0 - + msr basepri, r0 bx r14 /*-----------------------------------------------------------*/ @@ -159,7 +155,7 @@ vPortSVCHandler: /*-----------------------------------------------------------*/ -vPortStartFirstTask: +vPortStartFirstTask /* Use the NVIC offset register to locate the stack. */ ldr r0, =0xE000ED08 ldr r0, [r0] diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM4F/portmacro.h b/FreeRTOS/Source/portable/IAR/ARM_CM4F/portmacro.h index c218de87f..f825609b4 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM4F/portmacro.h +++ b/FreeRTOS/Source/portable/IAR/ARM_CM4F/portmacro.h @@ -106,15 +106,13 @@ extern "C" { #define portBYTE_ALIGNMENT 8 /*-----------------------------------------------------------*/ - /* Scheduler utilities. */ extern void vPortYieldFromISR( void ); - #define portYIELD() vPortYieldFromISR() - #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR() /*-----------------------------------------------------------*/ +/* Architecture specific optimisations. */ #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 /* Check the configuration. */ @@ -131,36 +129,42 @@ extern void vPortYieldFromISR( void ); #include #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __CLZ( ( uxReadyPriorities ) ) ) -#endif /* taskRECORD_READY_PRIORITY */ - +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ +/*-----------------------------------------------------------*/ /* Critical section management. */ - extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); -extern void vPortSetInterruptMask( void ); -extern void vPortClearInterruptMask( void ); +extern unsigned long ulPortSetInterruptMask( void ); +extern void vPortClearInterruptMask( unsigned long ulNewMask ); -#define portDISABLE_INTERRUPTS() vPortSetInterruptMask() -#define portENABLE_INTERRUPTS() vPortClearInterruptMask() +#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() +#define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 ) #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical() - -/* FAQ: Setting BASEPRI to 0 is not a bug. Please see -http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */ -#define portSET_INTERRUPT_MASK_FROM_ISR() 0;vPortSetInterruptMask() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask();(void)x +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask( x ) +/*-----------------------------------------------------------*/ /* There are an uneven number of items on the initial stack, so portALIGNMENT_ASSERT_pxCurrentTCB() will trigger false positive asserts. */ #define portALIGNMENT_ASSERT_pxCurrentTCB ( void ) +/*-----------------------------------------------------------*/ + +/* Tickless/low power functionality. */ +extern void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ); +#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime ) /*-----------------------------------------------------------*/ -/* Task function macros as described on the FreeRTOS.org WEB site. */ +/* Task function macros as described on the FreeRTOS.org WEB site. These are +not necessary for to use this port. They are defined so the common demo files +(which build with all the ports) will build. */ #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) +/*-----------------------------------------------------------*/ +/* portNOP() is not required by this port. */ #define portNOP() #ifdef __cplusplus diff --git a/FreeRTOS/Source/portable/MemMang/heap_1.c b/FreeRTOS/Source/portable/MemMang/heap_1.c index fa45fc3fa..e44b32d7e 100644 --- a/FreeRTOS/Source/portable/MemMang/heap_1.c +++ b/FreeRTOS/Source/portable/MemMang/heap_1.c @@ -1,6 +1,6 @@ /* FreeRTOS V7.2.0 - Copyright (C) 2012 Real Time Engineers Ltd. - + *************************************************************************** * * @@ -40,7 +40,7 @@ FreeRTOS WEB site. 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -50,17 +50,17 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest information, + + http://www.FreeRTOS.org - Documentation, training, latest information, license and contact details. - + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under + 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 + provide a safety engineered and independently SIL3 certified version under the SafeRTOS brand: http://www.SafeRTOS.com. */ @@ -69,7 +69,7 @@ * The simplest possible implementation of pvPortMalloc(). Note that this * implementation does NOT allow allocated memory to be freed again. * - * See heap_2.c, heap_3.c and heap_4.c for alternative implementations, and the + * See heap_2.c, heap_3.c and heap_4.c for alternative implementations, and the * memory management pages of http://www.FreeRTOS.org for more information. */ #include @@ -92,7 +92,7 @@ static union xRTOS_HEAP volatile portDOUBLE dDummy; #else volatile unsigned long ulDummy; - #endif + #endif unsigned char ucHeap[ configTOTAL_HEAP_SIZE ]; } xHeap; @@ -101,7 +101,7 @@ static size_t xNextFreeByte = ( size_t ) 0; void *pvPortMalloc( size_t xWantedSize ) { -void *pvReturn = NULL; +void *pvReturn = NULL; /* Ensure that blocks are always aligned to the required number of bytes. */ #if portBYTE_ALIGNMENT != 1 @@ -121,11 +121,11 @@ void *pvReturn = NULL; /* Return the next free byte then increment the index past this block. */ pvReturn = &( xHeap.ucHeap[ xNextFreeByte ] ); - xNextFreeByte += xWantedSize; - } + xNextFreeByte += xWantedSize; + } } xTaskResumeAll(); - + #if( configUSE_MALLOC_FAILED_HOOK == 1 ) { if( pvReturn == NULL ) @@ -134,7 +134,7 @@ void *pvReturn = NULL; vApplicationMallocFailedHook(); } } - #endif + #endif return pvReturn; } @@ -143,10 +143,10 @@ void *pvReturn = NULL; void vPortFree( void *pv ) { /* Memory cannot be freed using this scheme. See heap_2.c, heap_3.c and - heap_4.c for alternative implementations, and the memory management pages of + heap_4.c for alternative implementations, and the memory management pages of http://www.FreeRTOS.org for more information. */ ( void ) pv; - + /* Force an assert as it is invalid to call this function. */ configASSERT( pv == NULL ); } diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c b/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c index d109cecd3..94b838484 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c @@ -1,6 +1,6 @@ /* FreeRTOS V7.2.0 - Copyright (C) 2012 Real Time Engineers Ltd. - + *************************************************************************** * * @@ -40,7 +40,7 @@ FreeRTOS WEB site. 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -50,17 +50,17 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest information, + + http://www.FreeRTOS.org - Documentation, training, latest information, license and contact details. - + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under + 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 + provide a safety engineered and independently SIL3 certified version under the SafeRTOS brand: http://www.SafeRTOS.com. */ @@ -80,17 +80,35 @@ #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html #endif -/* Constants required to manipulate the NVIC. */ -#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long *) 0xe000e010 ) -#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long *) 0xe000e014 ) -#define portNVIC_INT_CTRL ( ( volatile unsigned long *) 0xe000ed04 ) -#define portNVIC_SYSPRI2 ( ( volatile unsigned long *) 0xe000ed20 ) -#define portNVIC_SYSTICK_CLK 0x00000004 -#define portNVIC_SYSTICK_INT 0x00000002 -#define portNVIC_SYSTICK_ENABLE 0x00000001 -#define portNVIC_PENDSVSET 0x10000000 -#define portNVIC_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 ) -#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 ) +#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 */ + +/* 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 ) /* Constants required to set up the initial stack. */ #define portINITIAL_XPSR ( 0x01000000 ) @@ -99,7 +117,7 @@ variable. */ static unsigned portBASE_TYPE uxCriticalNesting = 0xaaaaaaaa; -/* +/* * Setup the timer to generate the tick interrupts. */ static void prvSetupTimerInterrupt( void ); @@ -114,12 +132,27 @@ void vPortSVCHandler( void ); /* * Start first task is a separate function so it can be tested in isolation. */ -void vPortStartFirstTask( void ); +static void prvStartFirstTask( void ); /*-----------------------------------------------------------*/ -/* - * See header file for description. +/* + * The number of SysTick increments that make up one tick period. + */ +static unsigned long ulTimerReloadValueForOneTick = 0; + +/* + * The maximum number of tick periods that can be suppressed is limited by the + * 24 bit resolution of the SysTick timer. + */ +#if configUSE_TICKLESS_IDLE == 1 + static unsigned long xMaximumPossibleSuppressedTicks = 0; +#endif /* configUSE_TICKLESS_IDLE */ + +/*-----------------------------------------------------------*/ + +/* + * See header file for description. */ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) { @@ -143,15 +176,15 @@ __asm void vPortSVCHandler( void ) { PRESERVE8 - ldr r3, =pxCurrentTCB /* Restore the context. */ - ldr r1, [r3] /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */ - ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */ + ldr r3, =pxCurrentTCB /* Restore the context. */ + ldr r1, [r3] /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */ + ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */ ldmia r0!, {r4-r11} /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */ - msr psp, r0 /* Restore the task stack pointer. */ + msr psp, r0 /* Restore the task stack pointer. */ mov r0, #0 msr basepri, r0 - orr r14, #0xd - bx r14 + orr r14, #0xd + bx r14 } /*-----------------------------------------------------------*/ @@ -173,24 +206,24 @@ __asm void vPortStartFirstTask( void ) } /*-----------------------------------------------------------*/ -/* - * See header file for description. +/* + * See header file for description. */ portBASE_TYPE xPortStartScheduler( void ) { - /* Make PendSV, CallSV and SysTick the same priroity as the kernel. */ - *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; - *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; + /* Make PendSV, CallSV and SysTick the same priority as the kernel. */ + 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(); - + /* Initialise the critical nesting count ready for the first task. */ uxCriticalNesting = 0; /* Start the first task. */ - vPortStartFirstTask(); + prvStartFirstTask(); /* Should not get here! */ return 0; @@ -207,7 +240,7 @@ void vPortEndScheduler( void ) void vPortYieldFromISR( void ) { /* Set a PendSV to request a context switch. */ - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } /*-----------------------------------------------------------*/ @@ -236,26 +269,26 @@ __asm void xPortPendSVHandler( void ) PRESERVE8 - mrs r0, psp + mrs r0, psp - ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */ - ldr r2, [r3] + ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */ + ldr r2, [r3] - stmdb r0!, {r4-r11} /* Save the remaining registers. */ - str r0, [r2] /* Save the new top of stack into the first member of the TCB. */ + stmdb r0!, {r4-r11} /* Save the remaining registers. */ + str r0, [r2] /* Save the new top of stack into the first member of the TCB. */ - stmdb sp!, {r3, r14} + stmdb sp!, {r3, r14} mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY - msr basepri, r0 + msr basepri, r0 bl vTaskSwitchContext mov r0, #0 msr basepri, r0 - ldmia sp!, {r3, r14} + ldmia sp!, {r3, r14} - ldr r1, [r3] - ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */ - ldmia r0!, {r4-r11} /* Pop the registers and the critical nesting count. */ - msr psp, r0 + ldr r1, [r3] + ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */ + ldmia r0!, {r4-r11} /* Pop the registers and the critical nesting count. */ + msr psp, r0 bx r14 nop } @@ -263,51 +296,164 @@ __asm void xPortPendSVHandler( void ) void xPortSysTickHandler( void ) { -unsigned long ulDummy; - - /* If using preemption, also force a context switch. */ #if configUSE_PREEMPTION == 1 - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + { + /* If using preemption, also force a context switch. */ + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; + } + #endif + + #if configUSE_TICKLESS_IDLE == 1 + portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; #endif - ulDummy = portSET_INTERRUPT_MASK_FROM_ISR(); + ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); { vTaskIncrementTick(); } - portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); } /*-----------------------------------------------------------*/ +#if configUSE_TICKLESS_IDLE == 1 + + __weak void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ) + { + unsigned long ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickIncrements; + + /* Make sure the SysTick reload value does not overflow the counter. */ + if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) + { + xExpectedIdleTime = xMaximumPossibleSuppressedTicks; + } + + /* 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 ) ); + 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; + + /* 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 ) + { + /* Restart SysTick. */ + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + } + 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 ) ); + portNVIC_SYSTICK_LOAD_REG = ulReloadValue; + + /* Clear the SysTick count flag and set the count value back to + zero. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + + /* 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(); + + /* Stop SysTick. Again, 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; + + 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 ); + + /* The tick interrupt handler will already have pended the tick + processing in the kernel. As the pending tick will be + processed as soon as this function exits, the tick value + maintained by the tick is stepped forward by one less than the + time spent waiting. */ + ulCompleteTickPeriods = xExpectedIdleTime - 1UL; + } + 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; + + /* How many complete tick periods passed while the processor + was waiting? */ + ulCompleteTickPeriods = ulCompletedSysTickIncrements / ulTimerReloadValueForOneTick; + + /* The reload value is set to whatever fraction of a single tick + period remains. */ + portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1 ) * ulTimerReloadValueForOneTick ) - ulCompletedSysTickIncrements; + } + + /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG + again, then set portNVIC_SYSTICK_LOAD_REG back to its standard + value. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + + vTaskStepTick( ulCompleteTickPeriods ); + } + } + +#endif /* #if configUSE_TICKLESS_IDLE */ + +/*-----------------------------------------------------------*/ + /* - * Setup the systick timer to generate the tick interrupts at the required + * Setup the SysTick timer to generate the tick interrupts at the required * frequency. */ void prvSetupTimerInterrupt( void ) { + /* Calculate the constants required to configure the tick interrupt. */ + ulTimerReloadValueForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + #if configUSE_TICKLESS_IDLE == 1 + xMaximumPossibleSuppressedTicks = 0xffffffUL / ( ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL ); + #endif /* configUSE_TICKLESS_IDLE */ + /* Configure SysTick to interrupt at the requested rate. */ - *(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; - *(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; + portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ -__asm void vPortSetInterruptMask( void ) +__asm unsigned long ulPortSetInterruptMask( void ) { PRESERVE8 - mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY - msr basepri, r0 + mrs r0, basepri + mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY + msr basepri, r1 bx r14 } /*-----------------------------------------------------------*/ -__asm void vPortClearInterruptMask( void ) +__asm void vPortClearInterruptMask( unsigned long ulNewMask ) { PRESERVE8 - /* FAQ: Setting BASEPRI to 0 is not a bug. Please see - http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */ - mov r0, #0 msr basepri, r0 bx r14 } diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM3/portmacro.h b/FreeRTOS/Source/portable/RVDS/ARM_CM3/portmacro.h index b252093cb..012c11e1a 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM3/portmacro.h +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM3/portmacro.h @@ -1,6 +1,6 @@ /* FreeRTOS V7.2.0 - Copyright (C) 2012 Real Time Engineers Ltd. - + *************************************************************************** * * @@ -40,7 +40,7 @@ FreeRTOS WEB site. 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -50,17 +50,17 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest information, + + http://www.FreeRTOS.org - Documentation, training, latest information, license and contact details. - + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under + 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 + provide a safety engineered and independently SIL3 certified version under the SafeRTOS brand: http://www.SafeRTOS.com. */ @@ -73,7 +73,7 @@ extern "C" { #endif /*----------------------------------------------------------- - * Port specific definitions. + * Port specific definitions. * * The settings in this file configure FreeRTOS correctly for the * given hardware and compiler. @@ -98,50 +98,41 @@ extern "C" { typedef unsigned portLONG portTickType; #define portMAX_DELAY ( portTickType ) 0xffffffff #endif -/*-----------------------------------------------------------*/ +/*-----------------------------------------------------------*/ /* Architecture specifics. */ #define portSTACK_GROWTH ( -1 ) -#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ ) +#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ ) #define portBYTE_ALIGNMENT 8 -/*-----------------------------------------------------------*/ - +/*-----------------------------------------------------------*/ /* Scheduler utilities. */ extern void vPortYield( void ); extern void vPortYieldFromISR( void ); - #define portYIELD() vPortYieldFromISR() #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR() /*-----------------------------------------------------------*/ - /* Critical section management. */ - -extern void vPortSetInterruptMask( void ); -extern void vPortClearInterruptMask( void ); +extern unsigned long ulPortSetInterruptMask( void ); +extern void vPortClearInterruptMask( unsigned long ulNewMask ); extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); -#define portDISABLE_INTERRUPTS() vPortSetInterruptMask() -#define portENABLE_INTERRUPTS() vPortClearInterruptMask() +#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() +#define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 ) #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical() - -/* FAQ: Setting BASEPRI to 0 is not a bug. Please see -http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */ -#define portSET_INTERRUPT_MASK_FROM_ISR() 0;vPortSetInterruptMask() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask();(void)x - +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x) /*-----------------------------------------------------------*/ -/* Task function macros as described on the FreeRTOS.org WEB site. */ -#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) -#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) - -#define portNOP() - +/* Tickless/low power optimisations. */ +extern void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ); +#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime ) +/*-----------------------------------------------------------*/ +/* Port specific optimisations. */ #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 /* Check the configuration. */ @@ -154,11 +145,21 @@ http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */ #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ) /*-----------------------------------------------------------*/ - + #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __clz( ( uxReadyPriorities ) ) ) #endif /* taskRECORD_READY_PRIORITY */ +/*-----------------------------------------------------------*/ + +/* Task function macros as described on the FreeRTOS.org WEB site. These are +not necessary for to use this port. They are defined so the common demo files +(which build with all the ports) will build. */ +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) +/*-----------------------------------------------------------*/ +/* portNOP() is not required by this port. */ +#define portNOP() #ifdef __cplusplus } diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c index a8fdad686..9676f65be 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c @@ -1,6 +1,6 @@ /* FreeRTOS V7.2.0 - Copyright (C) 2012 Real Time Engineers Ltd. - + *************************************************************************** * * @@ -40,7 +40,7 @@ FreeRTOS WEB site. 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -50,17 +50,17 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest information, + + http://www.FreeRTOS.org - Documentation, training, latest information, license and contact details. - + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under + 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 + provide a safety engineered and independently SIL3 certified version under the SafeRTOS brand: http://www.SafeRTOS.com. */ @@ -72,7 +72,7 @@ #include "FreeRTOS.h" #include "task.h" -#ifndef __TARGET_FPU_VFP +#ifndef __TARGET_FPU_VFP #error This port can only be used when the project options are configured to enable hardware floating point support. #endif @@ -80,17 +80,35 @@ #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html #endif -/* Constants required to manipulate the NVIC. */ -#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long *) 0xe000e010 ) -#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long *) 0xe000e014 ) -#define portNVIC_INT_CTRL ( ( volatile unsigned long *) 0xe000ed04 ) -#define portNVIC_SYSPRI2 ( ( volatile unsigned long *) 0xe000ed20 ) -#define portNVIC_SYSTICK_CLK 0x00000004 -#define portNVIC_SYSTICK_INT 0x00000002 -#define portNVIC_SYSTICK_ENABLE 0x00000001 -#define portNVIC_PENDSVSET 0x10000000 -#define portNVIC_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 ) -#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 ) +#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 */ + +/* 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 ) /* Constants required to manipulate the VFP. */ #define portFPCCR ( ( volatile unsigned long * ) 0xe000ef34 ) /* Floating point context control register. */ @@ -104,7 +122,7 @@ variable. */ static unsigned portBASE_TYPE uxCriticalNesting = 0xaaaaaaaa; -/* +/* * Setup the timer to generate the tick interrupts. */ static void prvSetupTimerInterrupt( void ); @@ -125,27 +143,41 @@ static void prvStartFirstTask( void ); * Functions defined in portasm.s to enable the VFP. */ static void prvEnableVFP( void ); +/*-----------------------------------------------------------*/ + +/* + * The number of SysTick increments that make up one tick period. + */ +static unsigned long ulTimerReloadValueForOneTick = 0; + +/* + * The maximum number of tick periods that can be suppressed is limited by the + * 24 bit resolution of the SysTick timer. + */ +#if configUSE_TICKLESS_IDLE == 1 + static unsigned long xMaximumPossibleSuppressedTicks = 0; +#endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ -/* - * See header file for description. +/* + * See header file for description. */ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) { /* Simulate the stack frame as it would be created by a context switch interrupt. */ - + /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts, and to ensure alignment. */ pxTopOfStack--; - + *pxTopOfStack = portINITIAL_XPSR; /* xPSR */ pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */ pxTopOfStack--; *pxTopOfStack = 0; /* LR */ - + /* Save code space by skipping register initialisation. */ pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */ @@ -156,7 +188,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE *pxTopOfStack = portINITIAL_EXEC_RETURN; pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */ - + return pxTopOfStack; } /*-----------------------------------------------------------*/ @@ -173,7 +205,7 @@ __asm void vPortSVCHandler( void ) ldmia r0!, {r4-r11, r14} msr psp, r0 mov r0, #0 - msr basepri, r0 + msr basepri, r0 bx r14 } /*-----------------------------------------------------------*/ @@ -199,41 +231,41 @@ __asm void prvStartFirstTask( void ) __asm void prvEnableVFP( void ) { PRESERVE8 - + /* The FPU enable bits are in the CPACR. */ ldr.w r0, =0xE000ED88 ldr r1, [r0] - + /* Enable CP10 and CP11 coprocessors, then save back. */ orr r1, r1, #( 0xf << 20 ) str r1, [r0] - bx r14 + bx r14 nop } /*-----------------------------------------------------------*/ -/* - * See header file for description. +/* + * See header file for description. */ portBASE_TYPE xPortStartScheduler( void ) { /* Make PendSV, CallSV and SysTick the same priroity as the kernel. */ - *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; - *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; + 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(); - + /* Initialise the critical nesting count ready for the first task. */ uxCriticalNesting = 0; /* Ensure the VFP is enabled - it should be anyway. */ prvEnableVFP(); - + /* Lazy save always. */ *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS; - + /* Start the first task. */ prvStartFirstTask(); @@ -252,7 +284,7 @@ void vPortEndScheduler( void ) void vPortYieldFromISR( void ) { /* Set a PendSV to request a context switch. */ - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } /*-----------------------------------------------------------*/ @@ -281,11 +313,11 @@ __asm void xPortPendSVHandler( void ) PRESERVE8 - mrs r0, psp - + mrs r0, psp + /* Get the location of the current TCB. */ - ldr r3, =pxCurrentTCB - ldr r2, [r3] + ldr r3, =pxCurrentTCB + ldr r2, [r3] /* Is the task using the FPU context? If so, push high vfp registers. */ tst r14, #0x10 @@ -293,85 +325,198 @@ __asm void xPortPendSVHandler( void ) vstmdbeq r0!, {s16-s31} /* Save the core registers. */ - stmdb r0!, {r4-r11, r14} - + stmdb r0!, {r4-r11, r14} + /* Save the new top of stack into the first member of the TCB. */ str r0, [r2] - + stmdb sp!, {r3, r14} mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r0 - bl vTaskSwitchContext + bl vTaskSwitchContext mov r0, #0 msr basepri, r0 ldmia sp!, {r3, r14} /* The first item in pxCurrentTCB is the task top of stack. */ - ldr r1, [r3] + ldr r1, [r3] ldr r0, [r1] - + /* Pop the core registers. */ ldmia r0!, {r4-r11, r14} - /* Is the task using the FPU context? If so, pop the high vfp registers + /* Is the task using the FPU context? If so, pop the high vfp registers too. */ tst r14, #0x10 it eq vldmiaeq r0!, {s16-s31} - - msr psp, r0 - bx r14 - nop + + msr psp, r0 + bx r14 + nop } /*-----------------------------------------------------------*/ void xPortSysTickHandler( void ) { -unsigned long ulDummy; - - /* If using preemption, also force a context switch. */ #if configUSE_PREEMPTION == 1 - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + { + /* If using preemption, also force a context switch. */ + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; + } #endif - ulDummy = portSET_INTERRUPT_MASK_FROM_ISR(); + #if configUSE_TICKLESS_IDLE == 1 + portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; + #endif + + ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); { vTaskIncrementTick(); } - portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); } /*-----------------------------------------------------------*/ +#if configUSE_TICKLESS_IDLE == 1 + + __weak void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ) + { + unsigned long ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickIncrements; + + /* Make sure the SysTick reload value does not overflow the counter. */ + if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) + { + xExpectedIdleTime = xMaximumPossibleSuppressedTicks; + } + + /* 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 ) ); + 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; + + /* 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 ) + { + /* Restart SysTick. */ + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + } + 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 ) ); + portNVIC_SYSTICK_LOAD_REG = ulReloadValue; + + /* Clear the SysTick count flag and set the count value back to + zero. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + + /* 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(); + + /* Stop SysTick. Again, 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; + + 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 ); + + /* The tick interrupt handler will already have pended the tick + processing in the kernel. As the pending tick will be + processed as soon as this function exits, the tick value + maintained by the tick is stepped forward by one less than the + time spent waiting. */ + ulCompleteTickPeriods = xExpectedIdleTime - 1UL; + } + 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; + + /* How many complete tick periods passed while the processor + was waiting? */ + ulCompleteTickPeriods = ulCompletedSysTickIncrements / ulTimerReloadValueForOneTick; + + /* The reload value is set to whatever fraction of a single tick + period remains. */ + portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1 ) * ulTimerReloadValueForOneTick ) - ulCompletedSysTickIncrements; + } + + /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG + again, then set portNVIC_SYSTICK_LOAD_REG back to its standard + value. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + + vTaskStepTick( ulCompleteTickPeriods ); + } + } + +#endif /* #if configUSE_TICKLESS_IDLE */ + +/*-----------------------------------------------------------*/ + /* * Setup the systick timer to generate the tick interrupts at the required * frequency. */ void prvSetupTimerInterrupt( void ) { + /* Calculate the constants required to configure the tick interrupt. */ + ulTimerReloadValueForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + #if configUSE_TICKLESS_IDLE == 1 + xMaximumPossibleSuppressedTicks = 0xffffffUL / ( ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL ); + #endif /* configUSE_TICKLESS_IDLE */ + /* Configure SysTick to interrupt at the requested rate. */ - *(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; - *(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; + portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick; + portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ -__asm void vPortSetInterruptMask( void ) +__asm unsigned long ulPortSetInterruptMask( void ) { PRESERVE8 - mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY - msr basepri, r0 + mrs r0, basepri + mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY + msr basepri, r1 bx r14 } /*-----------------------------------------------------------*/ -__asm void vPortClearInterruptMask( void ) +__asm void vPortClearInterruptMask( unsigned long ulNewMask ) { PRESERVE8 - /* FAQ: Setting BASEPRI to 0 is not a bug. Please see - http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */ - mov r0, #0 msr basepri, r0 bx r14 } diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/portmacro.h b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/portmacro.h index 9301eddc1..a32b6de0d 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/portmacro.h +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/portmacro.h @@ -106,46 +106,39 @@ extern "C" { #define portBYTE_ALIGNMENT 8 /*-----------------------------------------------------------*/ - /* Scheduler utilities. */ extern void vPortYield( void ); extern void vPortYieldFromISR( void ); - #define portYIELD() vPortYieldFromISR() #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR() /*-----------------------------------------------------------*/ - /* Critical section management. */ - -extern void vPortSetInterruptMask( void ); -extern void vPortClearInterruptMask( void ); +extern unsigned long ulPortSetInterruptMask( void ); +extern void vPortClearInterruptMask( unsigned long ulNewMask ); extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); -#define portDISABLE_INTERRUPTS() vPortSetInterruptMask() -#define portENABLE_INTERRUPTS() vPortClearInterruptMask() +#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() +#define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 ) #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical() +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x) -/* FAQ: Setting BASEPRI to 0 is not a bug. Please see -http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */ -#define portSET_INTERRUPT_MASK_FROM_ISR() 0;vPortSetInterruptMask() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask();(void)x +/*-----------------------------------------------------------*/ /* There are an uneven number of items on the initial stack, so portALIGNMENT_ASSERT_pxCurrentTCB() will trigger false positive asserts. */ #define portALIGNMENT_ASSERT_pxCurrentTCB ( void ) - /*-----------------------------------------------------------*/ -/* Task function macros as described on the FreeRTOS.org WEB site. */ -#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) -#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) - -#define portNOP() - +/* Tickless/low power optimisations. */ +extern void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime ); +#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime ) +/*-----------------------------------------------------------*/ +/* Port specific optimisations. */ #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 /* Check the configuration. */ @@ -158,11 +151,21 @@ portALIGNMENT_ASSERT_pxCurrentTCB() will trigger false positive asserts. */ #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ) /*-----------------------------------------------------------*/ - + #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __clz( ( uxReadyPriorities ) ) ) #endif /* taskRECORD_READY_PRIORITY */ +/*-----------------------------------------------------------*/ +/* Task function macros as described on the FreeRTOS.org WEB site. These are +not necessary for to use this port. They are defined so the common demo files +(which build with all the ports) will build. */ +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) +/*-----------------------------------------------------------*/ + +/* portNOP() is not required by this port. */ +#define portNOP() #ifdef __cplusplus } diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index e04232b33..c8edef19b 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -1,6 +1,6 @@ /* FreeRTOS V7.2.0 - Copyright (C) 2012 Real Time Engineers Ltd. - + *************************************************************************** * * @@ -40,7 +40,7 @@ FreeRTOS WEB site. 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -50,21 +50,21 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest information, + + http://www.FreeRTOS.org - Documentation, training, latest information, license and contact details. - + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under + 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 + provide a safety engineered and independently SIL3 certified version under the SafeRTOS brand: http://www.SafeRTOS.com. */ - +/* Standard includes. */ #include #include #include @@ -74,6 +74,7 @@ all the API functions to use the MPU wrappers. That should only be done when task.h is included from an application file. */ #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE +/* FreeRTOS includes. */ #include "FreeRTOS.h" #include "task.h" #include "timers.h" @@ -82,39 +83,40 @@ task.h is included from an application file. */ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /* - * Macro to define the amount of stack available to the idle task. + * Defines the size, in words, of the stack allocated to the idle task. */ #define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE /* - * Task control block. A task control block (TCB) is allocated to each task, - * and stores the context of the task. + * Task control block. A task control block (TCB) is allocated for each task, + * and stores task state information, including a pointer to the task's context + * (the task's run time environment, including register values) */ typedef struct tskTaskControlBlock { - volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */ + volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */ #if ( portUSING_MPU_WRAPPERS == 1 ) - xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */ - #endif - - xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */ - xListItem xEventListItem; /*< List item used to place the TCB in event lists. */ - unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */ + xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */ + #endif + + xListItem xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ + xListItem xEventListItem; /*< Used to reference a task from an event list. */ + unsigned portBASE_TYPE uxPriority; /*< The priority of the task. 0 is the lowest priority. */ portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */ signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ #if ( portSTACK_GROWTH > 0 ) - portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */ + portSTACK_TYPE *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */ #endif #if ( portCRITICAL_NESTING_IN_TCB == 1 ) - unsigned portBASE_TYPE uxCriticalNesting; + unsigned portBASE_TYPE uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ #endif #if ( configUSE_TRACE_FACILITY == 1 ) - unsigned portBASE_TYPE uxTCBNumber; /*< This stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */ - unsigned portBASE_TYPE uxTaskNumber; /*< This stores a number specifically for use by third party trace code. */ + unsigned portBASE_TYPE uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */ + unsigned portBASE_TYPE uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ #endif #if ( configUSE_MUTEXES == 1 ) @@ -126,15 +128,15 @@ typedef struct tskTaskControlBlock #endif #if ( configGENERATE_RUN_TIME_STATS == 1 ) - unsigned long ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */ + unsigned long ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */ #endif } tskTCB; /* - * Some kernel aware debuggers require data to be viewed to be global, rather - * than file scope. + * Some kernel aware debuggers require the data the debugger needs access to to + * be global, rather than file scope. */ #ifdef portREMOVE_STATIC_QUALIFIER #define static @@ -144,7 +146,6 @@ typedef struct tskTaskControlBlock PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL; /* Lists for ready and blocked tasks. --------------------*/ - PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */ PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */ PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ @@ -166,9 +167,9 @@ PRIVILEGED_DATA static xList xPendingReadyList; /*< Tasks that have been r #endif #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) - - PRIVILEGED_DATA static xTaskHandle xIdleTaskHandle = NULL; - + + PRIVILEGED_DATA static xTaskHandle xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ + #endif /* File private variables. --------------------------------*/ @@ -182,7 +183,7 @@ PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsi PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE; PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0; PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0U; -PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType ) portMAX_DELAY; +PRIVILEGED_DATA static volatile portTickType xNextTaskUnblockTime = ( portTickType ) portMAX_DELAY; #if ( configGENERATE_RUN_TIME_STATS == 1 ) @@ -211,10 +212,13 @@ PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType ) /*-----------------------------------------------------------*/ #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 - /* - * uxTopReadyPriority holds the priority of the highest priority ready - * state task. - */ + + /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is + performed in a generic way that is not optimised to any particular + microcontroller architecture. */ + + /* uxTopReadyPriority holds the priority of the highest priority ready + state task. */ #define taskRECORD_READY_PRIORITY( uxPriority ) \ { \ if( ( uxPriority ) > uxTopReadyPriority ) \ @@ -241,26 +245,46 @@ PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType ) /*-----------------------------------------------------------*/ - /* Define away portRESET_READY_PRIORITY() as it is not required in this - configuration. */ + /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as + they are only required when a port optimised method of task selection is + being used. */ + #define taskRESET_READY_PRIORITY( uxPriority ) #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority ) #else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is + performed in a way that is tailored to the particular microcontroller + architecture being used. */ + /* A port optimised version is provided. Call the port defined macros. */ #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority ) /*-----------------------------------------------------------*/ - #define taskSELECT_HIGHEST_PRIORITY_TASK() \ - { \ - unsigned portBASE_TYPE uxTopPriority; \ - \ - /* Find the highest priority queue that contains ready tasks. */ \ - portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ - listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ + #define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + unsigned portBASE_TYPE uxTopPriority; \ + \ + /* Find the highest priority queue that contains ready tasks. */ \ + portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ + configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ } /* taskSELECT_HIGHEST_PRIORITY_TASK() */ + /*-----------------------------------------------------------*/ + + /* A port optimised version is provided, call it only if the TCB being reset + is being referenced from a ready list. If it is referenced from a delayed + or suspended list then it won't be in a ready list. */ + #define taskRESET_READY_PRIORITY( uxPriority ) \ + { \ + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == 0 ) \ + { \ + portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \ + } \ + } + #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ /* @@ -270,9 +294,9 @@ PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType ) * executing task, then it will only be rescheduled after the currently * executing task has been rescheduled. */ -#define prvAddTaskToReadyQueue( pxTCB ) \ - traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ - taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \ +#define prvAddTaskToReadyQueue( pxTCB ) \ + traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ + taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \ vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) ) /*-----------------------------------------------------------*/ @@ -348,7 +372,7 @@ portTickType xItemValue; \ /* Callback function prototypes. --------------------------*/ extern void vApplicationStackOverflowHook( xTaskHandle pxTask, signed char *pcTaskName ); extern void vApplicationTickHook( void ); - + /* File private functions. --------------------------------*/ /* @@ -488,7 +512,7 @@ tskTCB * pxNewTCB; #else { pxTopOfStack = pxNewTCB->pxStack; - + /* Check the alignment of the stack buffer is correct. */ configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); @@ -526,7 +550,7 @@ tskTCB * pxNewTCB; required.*/ *pxCreatedTask = ( xTaskHandle ) pxNewTCB; } - + /* We are going to manipulate the task queues to add this task to a ready list, so must make sure no interrupts occur. */ taskENTER_CRITICAL(); @@ -630,7 +654,7 @@ tskTCB * pxNewTCB; scheduler for the TCB and stack. */ if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 ) { - portRESET_READY_PRIORITY( pxTCB->uxPriority, uxTopReadyPriority ); + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); } /* Is the task waiting on an event also? */ @@ -725,6 +749,9 @@ tskTCB * pxNewTCB; both lists. */ if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 ) { + /* The current task must be in a ready list, so there is + no need to check, and the port reset macro can be called + directly. */ portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); } @@ -775,6 +802,9 @@ tskTCB * pxNewTCB; both lists. */ if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 ) { + /* The current task must be in a ready list, so there is + no need to check, and the port reset macro can be called + directly. */ portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); } prvAddCurrentTaskToDelayedList( xTimeToWake ); @@ -794,7 +824,7 @@ tskTCB * pxNewTCB; /*-----------------------------------------------------------*/ #if ( INCLUDE_eTaskStateGet == 1 ) - + eTaskState eTaskStateGet( xTaskHandle pxTask ) { eTaskState eReturn; @@ -818,7 +848,7 @@ tskTCB * pxNewTCB; if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) ) { - /* The task being queried is referenced from one of the Blocked + /* The task being queried is referenced from one of the Blocked lists. */ eReturn = eBlocked; } @@ -826,7 +856,7 @@ tskTCB * pxNewTCB; #if ( INCLUDE_vTaskSuspend == 1 ) else if( pxStateList == &xSuspendedTaskList ) { - /* The task being queried is referenced from the suspended + /* The task being queried is referenced from the suspended list. */ eReturn = eSuspended; } @@ -835,7 +865,7 @@ tskTCB * pxNewTCB; #if ( INCLUDE_vTaskDelete == 1 ) else if( pxStateList == &xTasksWaitingTermination ) { - /* The task being queried is referenced from the deleted + /* The task being queried is referenced from the deleted tasks list. */ eReturn = eDeleted; } @@ -882,7 +912,7 @@ tskTCB * pxNewTCB; void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority ) { tskTCB *pxTCB; - unsigned portBASE_TYPE uxCurrentPriority; + unsigned portBASE_TYPE uxCurrentPriority, uxPriorityUsedOnEntry; portBASE_TYPE xYieldRequired = pdFALSE; configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); @@ -938,7 +968,10 @@ tskTCB * pxNewTCB; xYieldRequired = pdTRUE; } - + /* Remember the ready list the task might be referenced from + before its uxPriority member is changed so the + taskRESET_READY_PRIORITY() macro can function correctly. */ + uxPriorityUsedOnEntry = pxTCB->uxPriority; #if ( configUSE_MUTEXES == 1 ) { @@ -971,7 +1004,7 @@ tskTCB * pxNewTCB; can do this even if the scheduler is suspended. */ if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 ) { - portRESET_READY_PRIORITY( uxCurrentPriority, uxTopReadyPriority ); + taskRESET_READY_PRIORITY( uxPriorityUsedOnEntry ); } prvAddTaskToReadyQueue( pxTCB ); } @@ -983,6 +1016,10 @@ tskTCB * pxNewTCB; } } taskEXIT_CRITICAL(); + + /* Remove compiler warning about unused parameter when the port + optimised task selection is not being used. */ + ( void ) uxPriorityUsedOnEntry; } #endif @@ -1011,7 +1048,7 @@ tskTCB * pxNewTCB; /* Remove task from the ready/delayed list and place in the suspended list. */ if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 ) { - portRESET_READY_PRIORITY( pxTCB->uxPriority, uxTopReadyPriority ); + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); } /* Is the task waiting on an event also? */ @@ -1228,7 +1265,7 @@ portBASE_TYPE xReturn; macro must be defined to configure the timer/counter used to generate the run time counter time base. */ portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); - + /* Setting up the timer tick is hardware specific and thus in the portable interface. */ if( xPortStartScheduler() != pdFALSE ) @@ -1266,6 +1303,30 @@ void vTaskSuspendAll( void ) } /*----------------------------------------------------------*/ +portTickType xTaskGetExpectedIdleTime( void ) +{ +portTickType xReturn; + + if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY ) + { + xReturn = 0; + } + else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 ) + { + /* There are other idle priority tasks in the ready state. If + time slicing is used then the very next tick interrupt must be + processed. */ + xReturn = 0; + } + else + { + xReturn = xNextTaskUnblockTime - xTickCount; + } + + return xReturn; +} +/*----------------------------------------------------------*/ + signed portBASE_TYPE xTaskResumeAll( void ) { register tskTCB *pxTCB; @@ -1488,7 +1549,7 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) /* Divide ulTotalRunTime by 100 to make the percentage caluclations simpler in the prvGenerateRunTimeStatsForTasksInList() function. */ ulTotalRunTime /= 100UL; - + /* Run through all the lists that could potentially contain a TCB, generating a table of run timer percentages in the provided buffer. */ @@ -1551,8 +1612,15 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) configASSERT( ( xIdleTaskHandle != NULL ) ); return xIdleTaskHandle; } - + #endif +/*----------------------------------------------------------*/ + +void vTaskStepTick( portTickType xTicksToJump ) +{ + configASSERT( xTicksToJump <= xNextTaskUnblockTime ); + xTickCount += xTicksToJump; +} /*----------------------------------------------------------- * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES @@ -1566,6 +1634,7 @@ tskTCB * pxTCB; /* Called by the portable layer each time a tick interrupt occurs. Increments the tick then checks to see if the new tick value will cause any tasks to be unblocked. */ + traceTASK_INCREMENT_TICK( xTickCount ); if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) { ++xTickCount; @@ -1577,17 +1646,17 @@ tskTCB * pxTCB; If there are any items in pxDelayedTaskList here then there is an error! */ configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); - + pxTemp = pxDelayedTaskList; pxDelayedTaskList = pxOverflowDelayedTaskList; pxOverflowDelayedTaskList = pxTemp; xNumOfOverflows++; - + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) { /* The new current delayed list is empty. Set xNextTaskUnblockTime to the maximum possible value so it is - extremely unlikely that the + extremely unlikely that the if( xTickCount >= xNextTaskUnblockTime ) test will pass until there is an item in the delayed list. */ xNextTaskUnblockTime = portMAX_DELAY; @@ -1629,8 +1698,6 @@ tskTCB * pxTCB; } } #endif - - traceTASK_INCREMENT_TICK( xTickCount ); } /*-----------------------------------------------------------*/ @@ -1732,17 +1799,17 @@ void vTaskSwitchContext( void ) else { traceTASK_SWITCHED_OUT(); - + #if ( configGENERATE_RUN_TIME_STATS == 1 ) { unsigned long ulTempCounter; - + #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE portALT_GET_RUN_TIME_COUNTER_VALUE( ulTempCounter ); #else ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE(); #endif - + /* Add the amount of time the task has been running to the accumulated time so far. The time the task started running was stored in ulTaskSwitchedInTime. Note that there is no overflow protection here @@ -1752,12 +1819,12 @@ void vTaskSwitchContext( void ) ulTaskSwitchedInTime = ulTempCounter; } #endif - + taskFIRST_CHECK_FOR_STACK_OVERFLOW(); taskSECOND_CHECK_FOR_STACK_OVERFLOW(); - + taskSELECT_HIGHEST_PRIORITY_TASK(); - + traceTASK_SWITCHED_IN(); } } @@ -1782,6 +1849,8 @@ portTickType xTimeToWake; exclusive access to the ready lists as the scheduler is locked. */ if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 ) { + /* The current task must be in a ready list, so there is no need to + check, and the port reset macro can be called directly. */ portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); } @@ -1826,7 +1895,7 @@ portTickType xTimeToWake; designed for use by kernel code, and has special calling requirements - it should be called from a critical section. */ - + /* Place the event list item of the TCB in the appropriate event list. In this case it is assume that this is the only task that is going to be waiting on this event list, so the faster vListInsertEnd() function @@ -1838,6 +1907,8 @@ portTickType xTimeToWake; function is called form a critical section. */ if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 ) { + /* The current task must be in a ready list, so there is no need to + check, and the port reset macro can be called directly. */ portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); } @@ -1846,7 +1917,7 @@ portTickType xTimeToWake; xTimeToWake = xTickCount + xTicksToWait; prvAddCurrentTaskToDelayedList( xTimeToWake ); } - + #endif /* configUSE_TIMERS */ /*-----------------------------------------------------------*/ @@ -1865,7 +1936,7 @@ portBASE_TYPE xReturn; If an event is for a queue that is locked then this function will never get called - the lock count on the queue will get modified instead. This means we can always expect exclusive access to the event list here. - + This function assumes that a check has already been made to ensure that pxEventList is not empty. */ pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); @@ -1966,7 +2037,7 @@ void vTaskMissedYield( void ) { unsigned portBASE_TYPE uxReturn; tskTCB *pxTCB; - + if( xTask != NULL ) { pxTCB = ( tskTCB * ) xTask; @@ -1976,7 +2047,7 @@ void vTaskMissedYield( void ) { uxReturn = 0U; } - + return uxReturn; } #endif @@ -1986,7 +2057,7 @@ void vTaskMissedYield( void ) void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle ) { tskTCB *pxTCB; - + if( xTask != NULL ) { pxTCB = ( tskTCB * ) xTask; @@ -2057,6 +2128,48 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) vApplicationIdleHook(); } #endif + + #if ( configUSE_TICKLESS_IDLE == 1 ) + { + portTickType xExpectedIdleTime; + /* If the expected idle time is 1 then the idle time would end at + the end of the current time slice. The idle time must be at least + 2 to ensure any pended ticks between this point and the tick being + stopped can be legitimately stepped over when the tick suppression + routines returns. */ + const portTickType xMinimumExpectedIdleTime = ( portTickType ) 2; + + /* Don't enter low power if there are still tasks waiting + deletion. */ + if( uxTasksDeleted == 0 ) + { + /* It is not desirable to suspend then resume the scheduler on + each iteration of the idle task. Therefore, a preliminary + test of the expected idle time is performed without the + scheduler suspended. The result here is not necessarily + valid. */ + xExpectedIdleTime = xTaskGetExpectedIdleTime(); + + if( xExpectedIdleTime >= xMinimumExpectedIdleTime ) + { + vTaskSuspendAll(); + { + /* Now the scheduler is suspended, the expected idle + time can be sampled again, and this time its value can + be used. */ + configASSERT( xNextTaskUnblockTime >= xTickCount ); + xExpectedIdleTime = xTaskGetExpectedIdleTime(); + + if( xExpectedIdleTime >= xMinimumExpectedIdleTime ) + { + portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ); + } + } + xTaskResumeAll(); + } + } + } + #endif } } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */ @@ -2144,7 +2257,7 @@ static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions ) { tskTCB *pxTCB; - + if( xTaskToModify == pxCurrentTCB ) { xTaskToModify = NULL; @@ -2304,8 +2417,8 @@ tskTCB *pxNewTCB; { usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack ); } - #endif - + #endif + sprintf( pcStatusString, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber ); strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatusString ); @@ -2349,7 +2462,7 @@ tskTCB *pxNewTCB; { #ifdef portLU_PRINTF_SPECIFIER_REQUIRED { - sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter, ulStatsAsPercentage ); + sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter, ulStatsAsPercentage ); } #else { @@ -2365,7 +2478,7 @@ tskTCB *pxNewTCB; consumed less than 1% of the total run time. */ #ifdef portLU_PRINTF_SPECIFIER_REQUIRED { - sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter ); + sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter ); } #else { @@ -2516,12 +2629,12 @@ tskTCB *pxNewTCB; listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority ); /* If the task being modified is in the ready state it will need to - be moved in to a new list. */ + be moved into a new list. */ if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE ) { if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 ) { - portRESET_READY_PRIORITY( pxTCB->uxPriority, uxTopReadyPriority ); + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); } /* Inherit the priority before being moved into the new list. */ @@ -2556,7 +2669,7 @@ tskTCB *pxNewTCB; Remove ourselves from the ready list we currently appear in. */ if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 ) { - portRESET_READY_PRIORITY( pxTCB->uxPriority, uxTopReadyPriority ); + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); } /* Disinherit the priority before adding the task into the new @@ -2589,21 +2702,40 @@ tskTCB *pxNewTCB; #if ( portCRITICAL_NESTING_IN_TCB == 1 ) -void vTaskExitCritical( void ) -{ - if( xSchedulerRunning != pdFALSE ) + void vTaskExitCritical( void ) { - if( pxCurrentTCB->uxCriticalNesting > 0U ) + if( xSchedulerRunning != pdFALSE ) { - ( pxCurrentTCB->uxCriticalNesting )--; - - if( pxCurrentTCB->uxCriticalNesting == 0U ) + if( pxCurrentTCB->uxCriticalNesting > 0U ) { - portENABLE_INTERRUPTS(); + ( pxCurrentTCB->uxCriticalNesting )--; + + if( pxCurrentTCB->uxCriticalNesting == 0U ) + { + portENABLE_INTERRUPTS(); + } } } } -} + +#endif +/*-----------------------------------------------------------*/ + +#if ( configUSE_TICKLESS_IDLE == 1 ) + + unsigned portBASE_TYPE uxTaskPendingTicksGet( portBASE_TYPE xResetOnExit ) + { + unsigned portBASE_TYPE uxReturn; + + uxReturn = uxMissedTicks; + + if( xResetOnExit == pdTRUE ) + { + uxMissedTicks = 0; + } + + return uxReturn; + } #endif /*-----------------------------------------------------------*/ -- 2.39.5