Add tickless idle support in Cortex-M ports.

Change CCS R4 directory name.
This commit is contained in:
Richard Barry 2012-10-16 07:55:40 +00:00
parent 6ec4c7cecb
commit e03ab659f3
21 changed files with 2395 additions and 596 deletions

View file

@ -528,5 +528,17 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * );
#define vPortFreeAligned( pvBlockToFree ) vPortFree( pvBlockToFree ) #define vPortFreeAligned( pvBlockToFree ) vPortFree( pvBlockToFree )
#endif #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 */ #endif /* INC_FREERTOS_H */

View file

@ -1320,6 +1320,27 @@ unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask );
*/ */
void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle ); 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 #ifdef __cplusplus
} }

View file

@ -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__ */
/*-----------------------------------------------------------*/

View file

@ -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
;-------------------------------------------------------------------------------

View file

@ -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__ */

View file

@ -79,17 +79,35 @@ FreeRTOS.org versions prior to V4.4.0 did not include this definition. */
#define configKERNEL_INTERRUPT_PRIORITY 255 #define configKERNEL_INTERRUPT_PRIORITY 255
#endif #endif
/* Constants required to manipulate the NVIC. */ #ifndef configSYSTICK_CLOCK_HZ
#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long *) 0xe000e010 ) #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long *) 0xe000e014 ) #if configUSE_TICKLESS_IDLE == 1
#define portNVIC_INT_CTRL ( ( volatile unsigned long *) 0xe000ed04 ) static const unsigned long ulStoppedTimerCompensation = 45UL;
#define portNVIC_SYSPRI2 ( ( volatile unsigned long *) 0xe000ed20 ) #endif
#define portNVIC_SYSTICK_CLK 0x00000004 #else /* configSYSTICK_CLOCK_HZ */
#define portNVIC_SYSTICK_INT 0x00000002 #if configUSE_TICKLESS_IDLE == 1
#define portNVIC_SYSTICK_ENABLE 0x00000001 /* Assumes the SysTick clock is slower than the CPU clock. */
#define portNVIC_PENDSVSET 0x10000000 static const unsigned long ulStoppedTimerCompensation = 45UL / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
#define portNVIC_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 ) #endif
#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 ) #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. */ /* Constants required to set up the initial stack. */
#define portINITIAL_XPSR ( 0x01000000 ) #define portINITIAL_XPSR ( 0x01000000 )
@ -119,6 +137,22 @@ void vPortSVCHandler( void ) __attribute__ (( naked ));
*/ */
static void prvPortStartFirstTask( 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 */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
@ -185,8 +219,8 @@ portBASE_TYPE xPortStartScheduler( void )
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY ); configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
/* Make PendSV, CallSV and SysTick the same priroity as the kernel. */ /* Make PendSV, CallSV and SysTick the same priroity as the kernel. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ here already. */
@ -213,7 +247,7 @@ void vPortEndScheduler( void )
void vPortYieldFromISR( void ) void vPortYieldFromISR( void )
{ {
/* Set a PendSV to request a context switch. */ /* 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 ) void xPortPendSVHandler( void )
{ {
/* This is a naked function. */ /* This is a naked function. */
@ -271,30 +333,142 @@ void xPortPendSVHandler( void )
void xPortSysTickHandler( void ) void xPortSysTickHandler( void )
{ {
unsigned long ulDummy;
/* If using preemption, also force a context switch. */ /* If using preemption, also force a context switch. */
#if configUSE_PREEMPTION == 1 #if configUSE_PREEMPTION == 1
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
#endif #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(); 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 * Setup the systick timer to generate the tick interrupts at the required
* frequency. * frequency.
*/ */
void prvSetupTimerInterrupt( void ) 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. */ /* Configure SysTick to interrupt at the requested rate. */
*(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick;
*(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -109,62 +109,36 @@ extern "C" {
/* Scheduler utilities. */ /* Scheduler utilities. */
extern void vPortYieldFromISR( void ); extern void vPortYieldFromISR( void );
#define portYIELD() vPortYieldFromISR() #define portYIELD() vPortYieldFromISR()
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR() #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR()
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Critical section management. */ /* 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 vPortEnterCritical( void );
extern void vPortExitCritical( void ); extern void vPortExitCritical( void );
extern unsigned long ulPortSetInterruptMask( void );
#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK() extern void vPortClearInterruptMask( unsigned long ulNewMaskValue );
#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK() #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 portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical() #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_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( 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 #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Generic helper function. */ /* Generic helper function. */
@ -189,8 +163,12 @@ extern void vPortExitCritical( void );
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - ucPortCountLeadingZeros( ( uxReadyPriorities ) ) ) #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 #ifdef __cplusplus
} }

View file

@ -76,17 +76,35 @@
#error This port can only be used when the project options are configured to enable hardware floating point support. #error This port can only be used when the project options are configured to enable hardware floating point support.
#endif #endif
/* Constants required to manipulate the NVIC. */ #ifndef configSYSTICK_CLOCK_HZ
#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long * ) 0xe000e010 ) #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long * ) 0xe000e014 ) #if configUSE_TICKLESS_IDLE == 1
#define portNVIC_INT_CTRL ( ( volatile unsigned long * ) 0xe000ed04 ) static const unsigned long ulStoppedTimerCompensation = 45UL;
#define portNVIC_SYSPRI2 ( ( volatile unsigned long * ) 0xe000ed20 ) #endif
#define portNVIC_SYSTICK_CLK 0x00000004 #else /* configSYSTICK_CLOCK_HZ */
#define portNVIC_SYSTICK_INT 0x00000002 #if configUSE_TICKLESS_IDLE == 1
#define portNVIC_SYSTICK_ENABLE 0x00000001 /* Assumes the SysTick clock is slower than the CPU clock. */
#define portNVIC_PENDSVSET 0x10000000 static const unsigned long ulStoppedTimerCompensation = 45UL / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
#define portNVIC_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 ) #endif
#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 ) #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. */ /* Constants required to manipulate the VFP. */
#define portFPCCR ( ( volatile unsigned long * ) 0xe000ef34 ) /* Floating point context control register. */ #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. * 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. * Function to enable the VFP.
*/ */
static void vPortEnableVFP( void ) __attribute__ (( naked )); 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( __asm volatile(
" ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */ " ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */
@ -203,9 +236,9 @@ portBASE_TYPE xPortStartScheduler( void )
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY ); configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
/* Make PendSV and SysTick the lowest priority interrupts. */ /* Make PendSV, CallSV and SysTick the same priroity as the kernel. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ here already. */
@ -221,7 +254,7 @@ portBASE_TYPE xPortStartScheduler( void )
*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS; *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
/* Start the first task. */ /* Start the first task. */
vPortStartFirstTask(); prvPortStartFirstTask();
/* Should not get here! */ /* Should not get here! */
return 0; return 0;
@ -238,7 +271,7 @@ void vPortEndScheduler( void )
void vPortYieldFromISR( void ) void vPortYieldFromISR( void )
{ {
/* Set a PendSV to request a context switch. */ /* 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 ) void xPortPendSVHandler( void )
{ {
/* This is a naked function. */ /* This is a naked function. */
@ -307,30 +368,143 @@ void xPortPendSVHandler( void )
void xPortSysTickHandler( void ) void xPortSysTickHandler( void )
{ {
unsigned long ulDummy;
/* If using preemption, also force a context switch. */ /* If using preemption, also force a context switch. */
#if configUSE_PREEMPTION == 1 #if configUSE_PREEMPTION == 1
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
#endif #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(); 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 * Setup the systick timer to generate the tick interrupts at the required
* frequency. * frequency.
*/ */
void prvSetupTimerInterrupt( void ) 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. */ /* Configure SysTick to interrupt at the requested rate. */
*(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick;
*(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -115,46 +115,15 @@ extern void vPortYieldFromISR( void );
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR() #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR()
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Critical section management. */ /* 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 vPortEnterCritical( void );
extern void vPortExitCritical( void ); extern void vPortExitCritical( void );
extern unsigned long ulPortSetInterruptMask( void );
#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK() extern void vPortClearInterruptMask( unsigned long ulNewMaskValue );
#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK() #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 portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical() #define portEXIT_CRITICAL() vPortExitCritical()
@ -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_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( 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 #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Generic helper function. */ /* 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; 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 ) ) ) #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 #ifdef __cplusplus
} }

View file

@ -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 #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
#endif #endif
/* Constants required to manipulate the NVIC. */ #ifndef configSYSTICK_CLOCK_HZ
#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long *) 0xe000e010 ) #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long *) 0xe000e014 ) #if configUSE_TICKLESS_IDLE == 1
#define portNVIC_INT_CTRL ( ( volatile unsigned long *) 0xe000ed04 ) static const unsigned long ulStoppedTimerCompensation = 45UL;
#define portNVIC_SYSPRI2 ( ( volatile unsigned long *) 0xe000ed20 ) #endif
#define portNVIC_SYSTICK_CLK 0x00000004 #else /* configSYSTICK_CLOCK_HZ */
#define portNVIC_SYSTICK_INT 0x00000002 #if configUSE_TICKLESS_IDLE == 1
#define portNVIC_SYSTICK_ENABLE 0x00000001 /* Assumes the SysTick clock is slower than the CPU clock. */
#define portNVIC_PENDSVSET 0x10000000 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_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 )
#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 ) #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. * See header file for description.
*/ */
@ -146,8 +179,8 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE
portBASE_TYPE xPortStartScheduler( void ) portBASE_TYPE xPortStartScheduler( void )
{ {
/* Make PendSV and SysTick the lowest priority interrupts. */ /* Make PendSV and SysTick the lowest priority interrupts. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ here already. */
@ -174,7 +207,7 @@ void vPortEndScheduler( void )
void vPortYieldFromISR( void ) void vPortYieldFromISR( void )
{ {
/* Set a PendSV to request a context switch. */ /* 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 ) void xPortSysTickHandler( void )
{ {
unsigned long ulDummy;
/* If using preemption, also force a context switch. */ /* If using preemption, also force a context switch. */
#if configUSE_PREEMPTION == 1 #if configUSE_PREEMPTION == 1
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
#endif #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(); 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. * frequency.
*/ */
void prvSetupTimerInterrupt( void ) 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. */ /* Configure SysTick to interrupt at the requested rate. */
*(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick;
*(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -66,34 +66,19 @@
#include <FreeRTOSConfig.h> #include <FreeRTOSConfig.h>
/* 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) RSEG CODE:CODE(2)
thumb thumb
EXTERN vPortYieldFromISR
EXTERN pxCurrentTCB EXTERN pxCurrentTCB
EXTERN vTaskSwitchContext EXTERN vTaskSwitchContext
PUBLIC vSetMSP
PUBLIC xPortPendSVHandler PUBLIC xPortPendSVHandler
PUBLIC vPortSetInterruptMask PUBLIC ulPortSetInterruptMask
PUBLIC vPortClearInterruptMask PUBLIC vPortClearInterruptMask
PUBLIC vPortSVCHandler PUBLIC vPortSVCHandler
PUBLIC vPortStartFirstTask PUBLIC vPortStartFirstTask
/*-----------------------------------------------------------*/
vSetMSP
msr msp, r0
bx lr
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -122,28 +107,26 @@ xPortPendSVHandler:
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
vPortSetInterruptMask: ulPortSetInterruptMask:
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY mrs r0, basepri
msr BASEPRI, r0 mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r1
bx r14 bx r14
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
vPortClearInterruptMask: vPortClearInterruptMask:
/* FAQ: Setting BASEPRI to 0 is not a bug. Please see msr basepri, r0
http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */
mov r0, #0
msr BASEPRI, r0
bx r14 bx r14
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
vPortSVCHandler; vPortSVCHandler:
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB ldr r3, =pxCurrentTCB
ldr r1, [r3] ldr r1, [r3]
ldr r0, [r1] ldr r0, [r1]
/* Pop the core registers. */
ldmia r0!, {r4-r11} ldmia r0!, {r4-r11}
msr psp, r0 msr psp, r0
mov r0, #0 mov r0, #0

View file

@ -106,15 +106,13 @@ extern "C" {
#define portBYTE_ALIGNMENT 8 #define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Scheduler utilities. */ /* Scheduler utilities. */
extern void vPortYieldFromISR( void ); extern void vPortYieldFromISR( void );
#define portYIELD() vPortYieldFromISR() #define portYIELD() vPortYieldFromISR()
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR() #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR()
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Check the configuration. */ /* Check the configuration. */
@ -131,32 +129,36 @@ extern void vPortYieldFromISR( void );
#include <intrinsics.h> #include <intrinsics.h>
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __CLZ( ( uxReadyPriorities ) ) ) #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 );
#define portDISABLE_INTERRUPTS() vPortSetInterruptMask()
#define portENABLE_INTERRUPTS() vPortClearInterruptMask()
#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
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. */ /* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
extern unsigned long ulPortSetInterruptMask( void );
extern void vPortClearInterruptMask( unsigned long ulNewMask );
#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 )
/*-----------------------------------------------------------*/
/* 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. 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_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
/* portNOP() is not required by this port. */
#define portNOP() #define portNOP()
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -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 #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
#endif #endif
/* Constants required to manipulate the NVIC. */ #ifndef configSYSTICK_CLOCK_HZ
#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long * ) 0xe000e010 ) #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long * ) 0xe000e014 ) #if configUSE_TICKLESS_IDLE == 1
#define portNVIC_INT_CTRL ( ( volatile unsigned long * ) 0xe000ed04 ) static const unsigned long ulStoppedTimerCompensation = 45UL;
#define portNVIC_SYSPRI2 ( ( volatile unsigned long * ) 0xe000ed20 ) #endif
#define portNVIC_SYSTICK_CLK 0x00000004 #else /* configSYSTICK_CLOCK_HZ */
#define portNVIC_SYSTICK_INT 0x00000002 #if configUSE_TICKLESS_IDLE == 1
#define portNVIC_SYSTICK_ENABLE 0x00000001 /* Assumes the SysTick clock is slower than the CPU clock. */
#define portNVIC_PENDSVSET 0x10000000 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_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 )
#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 ) #define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 )
@ -120,12 +138,27 @@ void xPortSysTickHandler( void );
extern void vPortStartFirstTask( void ); extern void vPortStartFirstTask( void );
/* /*
* Functions defined in portasm.s to enable the VFP. * Turn the VFP on.
*/ */
extern void vPortEnableVFP( void ); 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. * See header file for description.
*/ */
@ -165,8 +198,8 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE
portBASE_TYPE xPortStartScheduler( void ) portBASE_TYPE xPortStartScheduler( void )
{ {
/* Make PendSV and SysTick the lowest priority interrupts. */ /* Make PendSV and SysTick the lowest priority interrupts. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ here already. */
@ -199,7 +232,7 @@ void vPortEndScheduler( void )
void vPortYieldFromISR( void ) void vPortYieldFromISR( void )
{ {
/* Set a PendSV to request a context switch. */ /* 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 ) void xPortSysTickHandler( void )
{ {
unsigned long ulDummy;
/* If using preemption, also force a context switch. */ /* If using preemption, also force a context switch. */
#if configUSE_PREEMPTION == 1 #if configUSE_PREEMPTION == 1
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
#endif #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(); 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. * frequency.
*/ */
void prvSetupTimerInterrupt( void ) 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. */ /* Configure SysTick to interrupt at the requested rate. */
*(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick;
*(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -73,7 +73,7 @@
EXTERN vTaskSwitchContext EXTERN vTaskSwitchContext
PUBLIC xPortPendSVHandler PUBLIC xPortPendSVHandler
PUBLIC vPortSetInterruptMask PUBLIC ulPortSetInterruptMask
PUBLIC vPortClearInterruptMask PUBLIC vPortClearInterruptMask
PUBLIC vPortSVCHandler PUBLIC vPortSVCHandler
PUBLIC vPortStartFirstTask PUBLIC vPortStartFirstTask
@ -127,20 +127,16 @@ xPortPendSVHandler:
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
vPortSetInterruptMask: ulPortSetInterruptMask:
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY mrs r0, basepri
msr BASEPRI, r0 mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r1
bx r14 bx r14
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
vPortClearInterruptMask: vPortClearInterruptMask:
/* FAQ: Setting BASEPRI to 0 is not a bug. Please see msr basepri, r0
http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */
mov r0, #0
msr BASEPRI, r0
bx r14 bx r14
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -159,7 +155,7 @@ vPortSVCHandler:
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
vPortStartFirstTask: vPortStartFirstTask
/* Use the NVIC offset register to locate the stack. */ /* Use the NVIC offset register to locate the stack. */
ldr r0, =0xE000ED08 ldr r0, =0xE000ED08
ldr r0, [r0] ldr r0, [r0]

View file

@ -106,15 +106,13 @@ extern "C" {
#define portBYTE_ALIGNMENT 8 #define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Scheduler utilities. */ /* Scheduler utilities. */
extern void vPortYieldFromISR( void ); extern void vPortYieldFromISR( void );
#define portYIELD() vPortYieldFromISR() #define portYIELD() vPortYieldFromISR()
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR() #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR()
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Check the configuration. */ /* Check the configuration. */
@ -131,36 +129,42 @@ extern void vPortYieldFromISR( void );
#include <intrinsics.h> #include <intrinsics.h>
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __CLZ( ( uxReadyPriorities ) ) ) #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __CLZ( ( uxReadyPriorities ) ) )
#endif /* taskRECORD_READY_PRIORITY */ #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
/* Critical section management. */ /* Critical section management. */
extern void vPortEnterCritical( void ); extern void vPortEnterCritical( void );
extern void vPortExitCritical( void ); extern void vPortExitCritical( void );
extern void vPortSetInterruptMask( void ); extern unsigned long ulPortSetInterruptMask( void );
extern void vPortClearInterruptMask( void ); extern void vPortClearInterruptMask( unsigned long ulNewMask );
#define portDISABLE_INTERRUPTS() vPortSetInterruptMask() #define portDISABLE_INTERRUPTS() ulPortSetInterruptMask()
#define portENABLE_INTERRUPTS() vPortClearInterruptMask() #define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 )
#define portENTER_CRITICAL() vPortEnterCritical() #define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical() #define portEXIT_CRITICAL() vPortExitCritical()
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask()
/* FAQ: Setting BASEPRI to 0 is not a bug. Please see #define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask( x )
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 /* There are an uneven number of items on the initial stack, so
portALIGNMENT_ASSERT_pxCurrentTCB() will trigger false positive asserts. */ portALIGNMENT_ASSERT_pxCurrentTCB() will trigger false positive asserts. */
#define portALIGNMENT_ASSERT_pxCurrentTCB ( void ) #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_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
/* portNOP() is not required by this port. */
#define portNOP() #define portNOP()
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -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 #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
#endif #endif
/* Constants required to manipulate the NVIC. */ #ifndef configSYSTICK_CLOCK_HZ
#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long *) 0xe000e010 ) #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long *) 0xe000e014 ) #if configUSE_TICKLESS_IDLE == 1
#define portNVIC_INT_CTRL ( ( volatile unsigned long *) 0xe000ed04 ) static const unsigned long ulStoppedTimerCompensation = 45UL;
#define portNVIC_SYSPRI2 ( ( volatile unsigned long *) 0xe000ed20 ) #endif
#define portNVIC_SYSTICK_CLK 0x00000004 #else /* configSYSTICK_CLOCK_HZ */
#define portNVIC_SYSTICK_INT 0x00000002 #if configUSE_TICKLESS_IDLE == 1
#define portNVIC_SYSTICK_ENABLE 0x00000001 /* Assumes the SysTick clock is slower than the CPU clock. */
#define portNVIC_PENDSVSET 0x10000000 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_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 )
#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 ) #define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 )
@ -114,7 +132,22 @@ void vPortSVCHandler( void );
/* /*
* Start first task is a separate function so it can be tested in isolation. * Start first task is a separate function so it can be tested in isolation.
*/ */
void vPortStartFirstTask( void ); static void prvStartFirstTask( 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 */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -178,9 +211,9 @@ __asm void vPortStartFirstTask( void )
*/ */
portBASE_TYPE xPortStartScheduler( void ) portBASE_TYPE xPortStartScheduler( void )
{ {
/* Make PendSV, CallSV and SysTick the same priroity as the kernel. */ /* Make PendSV, CallSV and SysTick the same priority as the kernel. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ here already. */
@ -190,7 +223,7 @@ portBASE_TYPE xPortStartScheduler( void )
uxCriticalNesting = 0; uxCriticalNesting = 0;
/* Start the first task. */ /* Start the first task. */
vPortStartFirstTask(); prvStartFirstTask();
/* Should not get here! */ /* Should not get here! */
return 0; return 0;
@ -207,7 +240,7 @@ void vPortEndScheduler( void )
void vPortYieldFromISR( void ) void vPortYieldFromISR( void )
{ {
/* Set a PendSV to request a context switch. */ /* Set a PendSV to request a context switch. */
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -263,51 +296,164 @@ __asm void xPortPendSVHandler( void )
void xPortSysTickHandler( void ) void xPortSysTickHandler( void )
{ {
unsigned long ulDummy;
/* If using preemption, also force a context switch. */
#if configUSE_PREEMPTION == 1 #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 #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(); 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. * frequency.
*/ */
void prvSetupTimerInterrupt( void ) 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. */ /* Configure SysTick to interrupt at the requested rate. */
*(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick;
*(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; 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 PRESERVE8
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY mrs r0, basepri
msr basepri, r0 mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r1
bx r14 bx r14
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
__asm void vPortClearInterruptMask( void ) __asm void vPortClearInterruptMask( unsigned long ulNewMask )
{ {
PRESERVE8 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 msr basepri, r0
bx r14 bx r14
} }

View file

@ -106,42 +106,33 @@ extern "C" {
#define portBYTE_ALIGNMENT 8 #define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Scheduler utilities. */ /* Scheduler utilities. */
extern void vPortYield( void ); extern void vPortYield( void );
extern void vPortYieldFromISR( void ); extern void vPortYieldFromISR( void );
#define portYIELD() vPortYieldFromISR() #define portYIELD() vPortYieldFromISR()
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR() #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR()
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Critical section management. */ /* Critical section management. */
extern unsigned long ulPortSetInterruptMask( void );
extern void vPortSetInterruptMask( void ); extern void vPortClearInterruptMask( unsigned long ulNewMask );
extern void vPortClearInterruptMask( void );
extern void vPortEnterCritical( void ); extern void vPortEnterCritical( void );
extern void vPortExitCritical( void ); extern void vPortExitCritical( void );
#define portDISABLE_INTERRUPTS() vPortSetInterruptMask() #define portDISABLE_INTERRUPTS() ulPortSetInterruptMask()
#define portENABLE_INTERRUPTS() vPortClearInterruptMask() #define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 )
#define portENTER_CRITICAL() vPortEnterCritical() #define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical() #define portEXIT_CRITICAL() vPortExitCritical()
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask()
/* FAQ: Setting BASEPRI to 0 is not a bug. Please see #define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x)
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
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. */ /* Tickless/low power optimisations. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) extern void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime );
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
/*-----------------------------------------------------------*/
#define portNOP()
/* Port specific optimisations. */
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Check the configuration. */ /* Check the configuration. */
@ -158,7 +149,17 @@ http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __clz( ( uxReadyPriorities ) ) ) #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __clz( ( uxReadyPriorities ) ) )
#endif /* taskRECORD_READY_PRIORITY */ #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 #ifdef __cplusplus
} }

View file

@ -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 #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
#endif #endif
/* Constants required to manipulate the NVIC. */ #ifndef configSYSTICK_CLOCK_HZ
#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long *) 0xe000e010 ) #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long *) 0xe000e014 ) #if configUSE_TICKLESS_IDLE == 1
#define portNVIC_INT_CTRL ( ( volatile unsigned long *) 0xe000ed04 ) static const unsigned long ulStoppedTimerCompensation = 45UL;
#define portNVIC_SYSPRI2 ( ( volatile unsigned long *) 0xe000ed20 ) #endif
#define portNVIC_SYSTICK_CLK 0x00000004 #else /* configSYSTICK_CLOCK_HZ */
#define portNVIC_SYSTICK_INT 0x00000002 #if configUSE_TICKLESS_IDLE == 1
#define portNVIC_SYSTICK_ENABLE 0x00000001 /* Assumes the SysTick clock is slower than the CPU clock. */
#define portNVIC_PENDSVSET 0x10000000 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_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 )
#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 ) #define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 )
@ -125,6 +143,20 @@ static void prvStartFirstTask( void );
* Functions defined in portasm.s to enable the VFP. * Functions defined in portasm.s to enable the VFP.
*/ */
static void prvEnableVFP( void ); 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 */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -218,8 +250,8 @@ __asm void prvEnableVFP( void )
portBASE_TYPE xPortStartScheduler( void ) portBASE_TYPE xPortStartScheduler( void )
{ {
/* Make PendSV, CallSV and SysTick the same priroity as the kernel. */ /* Make PendSV, CallSV and SysTick the same priroity as the kernel. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ here already. */
@ -252,7 +284,7 @@ void vPortEndScheduler( void )
void vPortYieldFromISR( void ) void vPortYieldFromISR( void )
{ {
/* Set a PendSV to request a context switch. */ /* Set a PendSV to request a context switch. */
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -327,51 +359,164 @@ __asm void xPortPendSVHandler( void )
void xPortSysTickHandler( void ) void xPortSysTickHandler( void )
{ {
unsigned long ulDummy;
/* If using preemption, also force a context switch. */
#if configUSE_PREEMPTION == 1 #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 #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(); 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. * frequency.
*/ */
void prvSetupTimerInterrupt( void ) 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. */ /* Configure SysTick to interrupt at the requested rate. */
*(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerReloadValueForOneTick;
*(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; 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 PRESERVE8
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY mrs r0, basepri
msr basepri, r0 mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r1
bx r14 bx r14
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
__asm void vPortClearInterruptMask( void ) __asm void vPortClearInterruptMask( unsigned long ulNewMask )
{ {
PRESERVE8 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 msr basepri, r0
bx r14 bx r14
} }

View file

@ -106,46 +106,39 @@ extern "C" {
#define portBYTE_ALIGNMENT 8 #define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Scheduler utilities. */ /* Scheduler utilities. */
extern void vPortYield( void ); extern void vPortYield( void );
extern void vPortYieldFromISR( void ); extern void vPortYieldFromISR( void );
#define portYIELD() vPortYieldFromISR() #define portYIELD() vPortYieldFromISR()
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR() #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR()
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Critical section management. */ /* Critical section management. */
extern unsigned long ulPortSetInterruptMask( void );
extern void vPortSetInterruptMask( void ); extern void vPortClearInterruptMask( unsigned long ulNewMask );
extern void vPortClearInterruptMask( void );
extern void vPortEnterCritical( void ); extern void vPortEnterCritical( void );
extern void vPortExitCritical( void ); extern void vPortExitCritical( void );
#define portDISABLE_INTERRUPTS() vPortSetInterruptMask() #define portDISABLE_INTERRUPTS() ulPortSetInterruptMask()
#define portENABLE_INTERRUPTS() vPortClearInterruptMask() #define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 )
#define portENTER_CRITICAL() vPortEnterCritical() #define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical() #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 /* There are an uneven number of items on the initial stack, so
portALIGNMENT_ASSERT_pxCurrentTCB() will trigger false positive asserts. */ portALIGNMENT_ASSERT_pxCurrentTCB() will trigger false positive asserts. */
#define portALIGNMENT_ASSERT_pxCurrentTCB ( void ) #define portALIGNMENT_ASSERT_pxCurrentTCB ( void )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. */ /* Tickless/low power optimisations. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) extern void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime );
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
/*-----------------------------------------------------------*/
#define portNOP()
/* Port specific optimisations. */
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Check the configuration. */ /* Check the configuration. */
@ -162,7 +155,17 @@ portALIGNMENT_ASSERT_pxCurrentTCB() will trigger false positive asserts. */
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __clz( ( uxReadyPriorities ) ) ) #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __clz( ( uxReadyPriorities ) ) )
#endif /* taskRECORD_READY_PRIORITY */ #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 #ifdef __cplusplus
} }

View file

@ -64,7 +64,7 @@
the SafeRTOS brand: http://www.SafeRTOS.com. the SafeRTOS brand: http://www.SafeRTOS.com.
*/ */
/* Standard includes. */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -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. */ task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* FreeRTOS includes. */
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
#include "timers.h" #include "timers.h"
@ -82,39 +83,40 @@ task.h is included from an application file. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_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 #define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
/* /*
* Task control block. A task control block (TCB) is allocated to each task, * Task control block. A task control block (TCB) is allocated for each task,
* and stores the context of the 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 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 ) #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. */ 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 #endif
xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */ 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; /*< List item used to place the TCB in event lists. */ xListItem xEventListItem; /*< Used to reference a task from an event list. */
unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */ unsigned portBASE_TYPE uxPriority; /*< The priority of the task. 0 is the lowest priority. */
portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */ 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. */ signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
#if ( portSTACK_GROWTH > 0 ) #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 #endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 ) #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 #endif
#if ( configUSE_TRACE_FACILITY == 1 ) #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 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; /*< This stores a number specifically for use by third party trace code. */ unsigned portBASE_TYPE uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
#endif #endif
#if ( configUSE_MUTEXES == 1 ) #if ( configUSE_MUTEXES == 1 )
@ -126,15 +128,15 @@ typedef struct tskTaskControlBlock
#endif #endif
#if ( configGENERATE_RUN_TIME_STATS == 1 ) #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 #endif
} tskTCB; } tskTCB;
/* /*
* Some kernel aware debuggers require data to be viewed to be global, rather * Some kernel aware debuggers require the data the debugger needs access to to
* than file scope. * be global, rather than file scope.
*/ */
#ifdef portREMOVE_STATIC_QUALIFIER #ifdef portREMOVE_STATIC_QUALIFIER
#define static #define static
@ -144,7 +146,6 @@ typedef struct tskTaskControlBlock
PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL; PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;
/* Lists for ready and blocked tasks. --------------------*/ /* Lists for ready and blocked tasks. --------------------*/
PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */ PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed 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. */ PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
@ -167,7 +168,7 @@ PRIVILEGED_DATA static xList xPendingReadyList; /*< Tasks that have been r
#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) #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 #endif
@ -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 xMissedYield = ( portBASE_TYPE ) pdFALSE;
PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0; PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0U; 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 ) #if ( configGENERATE_RUN_TIME_STATS == 1 )
@ -211,10 +212,13 @@ PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 0
/*
* uxTopReadyPriority holds the priority of the highest priority ready /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
* state task. 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 ) \ #define taskRECORD_READY_PRIORITY( uxPriority ) \
{ \ { \
if( ( uxPriority ) > uxTopReadyPriority ) \ if( ( uxPriority ) > uxTopReadyPriority ) \
@ -241,12 +245,18 @@ PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Define away portRESET_READY_PRIORITY() as it is not required in this /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as
configuration. */ 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 ) #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )
#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ #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. */ /* A port optimised version is provided. Call the port defined macros. */
#define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority ) #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )
@ -258,9 +268,23 @@ PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType )
\ \
/* Find the highest priority queue that contains ready tasks. */ \ /* Find the highest priority queue that contains ready tasks. */ \
portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
} /* taskSELECT_HIGHEST_PRIORITY_TASK() */ } /* 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 */ #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/* /*
@ -630,7 +654,7 @@ tskTCB * pxNewTCB;
scheduler for the TCB and stack. */ scheduler for the TCB and stack. */
if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 ) 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? */ /* Is the task waiting on an event also? */
@ -725,6 +749,9 @@ tskTCB * pxNewTCB;
both lists. */ both lists. */
if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 ) 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 ); portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
} }
@ -775,6 +802,9 @@ tskTCB * pxNewTCB;
both lists. */ both lists. */
if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 ) 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 ); portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
} }
prvAddCurrentTaskToDelayedList( xTimeToWake ); prvAddCurrentTaskToDelayedList( xTimeToWake );
@ -882,7 +912,7 @@ tskTCB * pxNewTCB;
void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority ) void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
{ {
tskTCB *pxTCB; tskTCB *pxTCB;
unsigned portBASE_TYPE uxCurrentPriority; unsigned portBASE_TYPE uxCurrentPriority, uxPriorityUsedOnEntry;
portBASE_TYPE xYieldRequired = pdFALSE; portBASE_TYPE xYieldRequired = pdFALSE;
configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );
@ -938,7 +968,10 @@ tskTCB * pxNewTCB;
xYieldRequired = pdTRUE; 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 ) #if ( configUSE_MUTEXES == 1 )
{ {
@ -971,7 +1004,7 @@ tskTCB * pxNewTCB;
can do this even if the scheduler is suspended. */ can do this even if the scheduler is suspended. */
if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 ) if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
{ {
portRESET_READY_PRIORITY( uxCurrentPriority, uxTopReadyPriority ); taskRESET_READY_PRIORITY( uxPriorityUsedOnEntry );
} }
prvAddTaskToReadyQueue( pxTCB ); prvAddTaskToReadyQueue( pxTCB );
} }
@ -983,6 +1016,10 @@ tskTCB * pxNewTCB;
} }
} }
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
/* Remove compiler warning about unused parameter when the port
optimised task selection is not being used. */
( void ) uxPriorityUsedOnEntry;
} }
#endif #endif
@ -1011,7 +1048,7 @@ tskTCB * pxNewTCB;
/* Remove task from the ready/delayed list and place in the suspended list. */ /* Remove task from the ready/delayed list and place in the suspended list. */
if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 ) 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? */ /* Is the task waiting on an event also? */
@ -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 ) signed portBASE_TYPE xTaskResumeAll( void )
{ {
register tskTCB *pxTCB; register tskTCB *pxTCB;
@ -1553,6 +1614,13 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
} }
#endif #endif
/*----------------------------------------------------------*/
void vTaskStepTick( portTickType xTicksToJump )
{
configASSERT( xTicksToJump <= xNextTaskUnblockTime );
xTickCount += xTicksToJump;
}
/*----------------------------------------------------------- /*-----------------------------------------------------------
* SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
@ -1566,6 +1634,7 @@ tskTCB * pxTCB;
/* Called by the portable layer each time a tick interrupt occurs. /* 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 Increments the tick then checks to see if the new tick value will cause any
tasks to be unblocked. */ tasks to be unblocked. */
traceTASK_INCREMENT_TICK( xTickCount );
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
{ {
++xTickCount; ++xTickCount;
@ -1629,8 +1698,6 @@ tskTCB * pxTCB;
} }
} }
#endif #endif
traceTASK_INCREMENT_TICK( xTickCount );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -1782,6 +1849,8 @@ portTickType xTimeToWake;
exclusive access to the ready lists as the scheduler is locked. */ exclusive access to the ready lists as the scheduler is locked. */
if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 ) 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 ); portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
} }
@ -1838,6 +1907,8 @@ portTickType xTimeToWake;
function is called form a critical section. */ function is called form a critical section. */
if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 ) 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 ); portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
} }
@ -2057,6 +2128,48 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
vApplicationIdleHook(); vApplicationIdleHook();
} }
#endif #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. */ } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
@ -2521,7 +2634,7 @@ tskTCB *pxNewTCB;
{ {
if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 ) 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. */ /* 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. */ Remove ourselves from the ready list we currently appear in. */
if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 ) 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 /* Disinherit the priority before adding the task into the new
@ -2608,6 +2721,25 @@ void vTaskExitCritical( void )
#endif #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
/*-----------------------------------------------------------*/