#define portINTERRUPT_ENABLE_BIT ( 0x80UL )\r
#define portTHUMB_MODE_ADDRESS ( 0x01UL )\r
\r
+/* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary\r
+point is zero. */\r
+#define portBINARY_POINT_BITS ( ( unsigned char ) 0x03 )\r
+\r
/* Masks all bits in the APSR other than the mode bits. */\r
#define portAPSR_MODE_BITS_MASK ( 0x1F )\r
\r
automatically be set to 0 when the first task is started. */\r
volatile unsigned long ulCriticalNesting = 9999UL;\r
\r
-/* The value to be written to the interrupt controllers priority mask register\r
-to mask interrupts that can use the FreeRTOS API without masking higher priority\r
-interrupts. */\r
-const unsigned long ulPortAPIPriorityMask = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );\r
-\r
/* Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero then\r
a floating point context must be saved and restored for the task. */\r
unsigned long ulPortTaskHasFPUContext = pdFALSE;\r
if the nesting depth is 0. */\r
unsigned long ulPortInterruptNesting = 0UL;\r
\r
+\r
/*-----------------------------------------------------------*/\r
\r
/*\r
\r
if( ulAPSR != portAPSR_USER_MODE )\r
{\r
- /* Start the timer that generates the tick ISR. */\r
- configSETUP_TICK_INTERRUPT();\r
+ /* Only continue if the binary point value is set to its lowest possible\r
+ setting. See the comments in vPortValidateInterruptPriority() below for\r
+ more information. */\r
+ configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );\r
\r
- __enable_irq();\r
- vPortRestoreTaskContext();\r
+ if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE )\r
+ {\r
+ /* Start the timer that generates the tick ISR. */\r
+ configSETUP_TICK_INTERRUPT();\r
+\r
+ __enable_irq();\r
+ vPortRestoreTaskContext();\r
+ }\r
}\r
\r
/* Will only get here if xTaskStartScheduler() was called with the CPU in\r
- a non-privileged mode. */\r
+ a non-privileged mode or the binary point register was not set to its lowest\r
+ possible value. */\r
return 0;\r
}\r
/*-----------------------------------------------------------*/\r
handler runs at the lowest priority, so interrupts cannot already be masked,\r
so there is no need to save and restore the current mask value. */\r
__disable_irq();\r
- portICCPMR_PRIORITY_MASK_REGISTER = ulPortAPIPriorityMask;\r
+ portICCPMR_PRIORITY_MASK_REGISTER = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );\r
__asm( "DSB \n"\r
"ISB \n" );\r
__enable_irq();\r
unsigned long ulReturn;\r
\r
__disable_irq();\r
- if( portICCPMR_PRIORITY_MASK_REGISTER == ulPortAPIPriorityMask )\r
+ if( portICCPMR_PRIORITY_MASK_REGISTER == ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) )\r
{\r
/* Interrupts were already masked. */\r
ulReturn = pdTRUE;\r
else\r
{\r
ulReturn = pdFALSE;\r
- portICCPMR_PRIORITY_MASK_REGISTER = ulPortAPIPriorityMask;\r
+ portICCPMR_PRIORITY_MASK_REGISTER = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );\r
__asm( "DSB \n"\r
"ISB \n" );\r
}\r
\r
return ulReturn;\r
}\r
+/*-----------------------------------------------------------*/\r
+\r
+#if( configASSERT_DEFINED == 1 )\r
+\r
+ void vPortValidateInterruptPriority( void )\r
+ {\r
+ /* The following assertion will fail if a service routine (ISR) for\r
+ an interrupt that has been assigned a priority above\r
+ configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API\r
+ function. ISR safe FreeRTOS API functions must *only* be called\r
+ from interrupts that have been assigned a priority at or below\r
+ configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
+\r
+ Numerically low interrupt priority numbers represent logically high\r
+ interrupt priorities, therefore the priority of the interrupt must\r
+ be set to a value equal to or numerically *higher* than\r
+ configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
+\r
+ FreeRTOS maintains separate thread and ISR API functions to ensure\r
+ interrupt entry is as fast and simple as possible.\r
+\r
+ The following links provide detailed information:\r
+ http://www.freertos.org/RTOS-Cortex-M3-M4.html\r
+ http://www.freertos.org/FAQHelp.html */\r
+ configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );\r
+\r
+ /* Priority grouping: The interrupt controller (GIC) allows the bits\r
+ that define each interrupt's priority to be split between bits that\r
+ define the interrupt's pre-emption priority bits and bits that define\r
+ the interrupt's sub-priority. For simplicity all bits must be defined\r
+ to be pre-emption priority bits. The following assertion will fail if\r
+ this is not the case (if some bits represent a sub-priority).\r
+\r
+ The priority grouping is configured by the GIC's binary point register\r
+ (ICCBPR). Writting 0 to ICCBPR will ensure it is set to its lowest\r
+ possible value (which may be above 0). */\r
+ configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );\r
+ }\r
+\r
+#endif /* configASSERT_DEFINED */\r
\r
\r
\r
/* IAR includes. */\r
#ifdef __ICCARM__\r
+\r
#include <intrinsics.h>\r
\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
+ #ifdef __cplusplus\r
+ extern "C" {\r
+ #endif\r
+\r
+ /*-----------------------------------------------------------\r
+ * Port specific definitions.\r
+ *\r
+ * The settings in this file configure FreeRTOS correctly for the given hardware\r
+ * and compiler.\r
+ *\r
+ * These settings should not be altered.\r
+ *-----------------------------------------------------------\r
+ */\r
+\r
+ /* Type definitions. */\r
+ #define portCHAR char\r
+ #define portFLOAT float\r
+ #define portDOUBLE double\r
+ #define portLONG long\r
+ #define portSHORT short\r
+ #define portSTACK_TYPE unsigned long\r
+ #define portBASE_TYPE portLONG\r
+ typedef unsigned long portTickType;\r
+ #define portMAX_DELAY ( portTickType ) 0xffffffff\r
+\r
+ /*-----------------------------------------------------------*/\r
+\r
+ /* Hardware specifics. */\r
+ #define portSTACK_GROWTH ( -1 )\r
+ #define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )\r
+ #define portBYTE_ALIGNMENT 8\r
\r
-/*-----------------------------------------------------------\r
- * Port specific definitions.\r
- *\r
- * The settings in this file configure FreeRTOS correctly for the given hardware\r
- * and compiler.\r
- *\r
- * These settings should not be altered.\r
- *-----------------------------------------------------------\r
- */\r
-\r
-/* Type definitions. */\r
-#define portCHAR char\r
-#define portFLOAT float\r
-#define portDOUBLE double\r
-#define portLONG long\r
-#define portSHORT short\r
-#define portSTACK_TYPE unsigned long\r
-#define portBASE_TYPE portLONG\r
-typedef unsigned long portTickType;\r
-#define portMAX_DELAY ( portTickType ) 0xffffffff\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Hardware specifics. */\r
-#define portSTACK_GROWTH ( -1 )\r
-#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )\r
-#define portBYTE_ALIGNMENT 8\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Task utilities. */\r
-\r
-/* Called at the end of an ISR that can cause a context switch. */\r
-#define portEND_SWITCHING_ISR( xSwitchRequired )\\r
-{ \\r
-extern unsigned long ulPortYieldRequired; \\r
- \\r
- if( xSwitchRequired != pdFALSE ) \\r
- { \\r
- ulPortYieldRequired = pdTRUE; \\r
- } \\r
-}\r
-\r
-#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )\r
-#define portYIELD() __asm( "SWI 0" );\r
-\r
-\r
-/*-----------------------------------------------------------\r
- * Critical section control\r
- *----------------------------------------------------------*/\r
-\r
-extern void vPortEnterCritical( void );\r
-extern void vPortExitCritical( void );\r
-extern unsigned long ulPortSetInterruptMask( void );\r
-extern void vPortClearInterruptMask( unsigned long ulNewMaskValue );\r
-\r
-/* These macros do not globally disable/enable interrupts. They do mask off\r
-interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */\r
-#define portENTER_CRITICAL() vPortEnterCritical();\r
-#define portEXIT_CRITICAL() vPortExitCritical();\r
-#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask()\r
-#define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 )\r
-#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask()\r
-#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x)\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Task function macros as described on the FreeRTOS.org WEB site. These are\r
-not required for this port but included in case common demo code that uses these\r
-macros is used. */\r
-#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )\r
-#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )\r
-\r
-/* Prototype of the FreeRTOS tick handler. This must be installed as the\r
-handler for whichever peripheral is used to generate the RTOS tick. */\r
-void FreeRTOS_Tick_Handler( void );\r
-\r
-/* Any task that uses the floating point unit MUST call vPortTaskUsesFPU()\r
-before any floating point instructions are executed. */\r
-void vPortTaskUsesFPU( void );\r
-#define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()\r
-\r
-#define portLOWEST_INTERRUPT_PRIORITY ( ( ( unsigned long ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL )\r
-#define portLOWEST_USABLE_INTERRUPT_PRIORITY ( portLOWEST_INTERRUPT_PRIORITY - 1UL )\r
-\r
-/* Architecture specific optimisations. */\r
-#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1\r
-\r
- /* Store/clear the ready priorities in a bit map. */\r
- #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )\r
- #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )\r
+ /*-----------------------------------------------------------*/\r
+\r
+ /* Task utilities. */\r
+\r
+ /* Called at the end of an ISR that can cause a context switch. */\r
+ #define portEND_SWITCHING_ISR( xSwitchRequired )\\r
+ { \\r
+ extern unsigned long ulPortYieldRequired; \\r
+ \\r
+ if( xSwitchRequired != pdFALSE ) \\r
+ { \\r
+ ulPortYieldRequired = pdTRUE; \\r
+ } \\r
+ }\r
+\r
+ #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )\r
+ #define portYIELD() __asm( "SWI 0" );\r
+\r
+\r
+ /*-----------------------------------------------------------\r
+ * Critical section control\r
+ *----------------------------------------------------------*/\r
+\r
+ extern void vPortEnterCritical( void );\r
+ extern void vPortExitCritical( void );\r
+ extern unsigned long ulPortSetInterruptMask( void );\r
+ extern void vPortClearInterruptMask( unsigned long ulNewMaskValue );\r
+\r
+ /* These macros do not globally disable/enable interrupts. They do mask off\r
+ interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */\r
+ #define portENTER_CRITICAL() vPortEnterCritical();\r
+ #define portEXIT_CRITICAL() vPortExitCritical();\r
+ #define portDISABLE_INTERRUPTS() ulPortSetInterruptMask()\r
+ #define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 )\r
+ #define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask()\r
+ #define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x)\r
\r
/*-----------------------------------------------------------*/\r
\r
- #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __CLZ( uxReadyPriorities ) )\r
+ /* Task function macros as described on the FreeRTOS.org WEB site. These are\r
+ not required for this port but included in case common demo code that uses these\r
+ macros is used. */\r
+ #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )\r
+ #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )\r
\r
-#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */\r
+ /* Prototype of the FreeRTOS tick handler. This must be installed as the\r
+ handler for whichever peripheral is used to generate the RTOS tick. */\r
+ void FreeRTOS_Tick_Handler( void );\r
\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
+ /* Any task that uses the floating point unit MUST call vPortTaskUsesFPU()\r
+ before any floating point instructions are executed. */\r
+ void vPortTaskUsesFPU( void );\r
+ #define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()\r
\r
-#endif /* __ICCARM__ */\r
+ #define portLOWEST_INTERRUPT_PRIORITY ( ( ( unsigned long ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL )\r
+ #define portLOWEST_USABLE_INTERRUPT_PRIORITY ( portLOWEST_INTERRUPT_PRIORITY - 1UL )\r
+\r
+ /* Architecture specific optimisations. */\r
+ #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1\r
\r
-#define portNOP() __asm volatile( "NOP" )\r
+ /* Store/clear the ready priorities in a bit map. */\r
+ #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )\r
+ #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )\r
+\r
+ /*-----------------------------------------------------------*/\r
+\r
+ #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __CLZ( uxReadyPriorities ) )\r
+\r
+ #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */\r
+\r
+ #ifdef configASSERT\r
+ void vPortValidateInterruptPriority( void );\r
+ #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()\r
+ #else\r
+ #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID()\r
+ #endif\r
+\r
+ #define portNOP() __asm volatile( "NOP" )\r
+\r
+\r
+ #ifdef __cplusplus\r
+ }\r
+ #endif\r
+\r
+#endif /* __ICCARM__ */\r
\r
\r
/* The number of bits to shift for an interrupt priority is dependent on the\r
number of bits implemented by the interrupt controller. */\r
#if configUNIQUE_INTERRUPT_PRIORITIES == 16\r
#define portPRIORITY_SHIFT 4\r
+ #define portMAX_BINARY_POINT_VALUE 3\r
#elif configUNIQUE_INTERRUPT_PRIORITIES == 32\r
#define portPRIORITY_SHIFT 3\r
+ #define portMAX_BINARY_POINT_VALUE 2\r
#elif configUNIQUE_INTERRUPT_PRIORITIES == 64\r
#define portPRIORITY_SHIFT 2\r
+ #define portMAX_BINARY_POINT_VALUE 1\r
#elif configUNIQUE_INTERRUPT_PRIORITIES == 128\r
#define portPRIORITY_SHIFT 1\r
+ #define portMAX_BINARY_POINT_VALUE 0\r
#elif configUNIQUE_INTERRUPT_PRIORITIES == 256\r
#define portPRIORITY_SHIFT 0\r
+ #define portMAX_BINARY_POINT_VALUE 0\r
#else\r
#error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware\r
#endif\r
\r
/* Interrupt controller access addresses. */\r
-#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 )\r
-#define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C )\r
-#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 )\r
-#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )\r
-#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile unsigned long * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )\r
-#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )\r
-#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET )\r
-#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET )\r
-\r
+#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 )\r
+#define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C )\r
+#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 )\r
+#define portICCBPR_BINARY_POINT_OFFSET ( 0x08 )\r
+#define portICCRPR_RUNNING_PRIORITY_OFFSET ( 0x14 )\r
+\r
+#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )\r
+#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile unsigned char * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )\r
+#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )\r
+#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET )\r
+#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET )\r
+#define portICCBPR_BINARY_POINT_REGISTER ( *( ( const volatile unsigned long * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCBPR_BINARY_POINT_OFFSET ) ) )\r
+#define portICCRPR_RUNNING_PRIORITY_REGISTER ( *( ( const volatile unsigned char * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) )\r
\r
#endif /* PORTMACRO_H */\r
\r
/* Block sizes must not get too small. */\r
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )\r
\r
+/* Assumes 8bit bytes! */\r
+#define heapBITS_PER_BYTE ( ( size_t ) 8 )\r
+\r
/* A few bytes might be lost to byte aligning the heap start address. */\r
-#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )\r
+#define heapADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )\r
\r
/* Allocate the memory for the heap. */\r
static unsigned char ucHeap[ configTOTAL_HEAP_SIZE ];\r
static const unsigned short heapSTRUCT_SIZE = ( ( sizeof ( xBlockLink ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK );\r
\r
/* Ensure the pxEnd pointer will end up on the correct byte alignment. */\r
-static const size_t xTotalHeapSize = ( ( size_t ) configADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );\r
+static const size_t xTotalHeapSize = ( ( size_t ) heapADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );\r
\r
/* Create a couple of list links to mark the start and end of the list. */\r
static xBlockLink xStart, *pxEnd = NULL;\r
\r
/* Keeps track of the number of free bytes remaining, but says nothing about\r
fragmentation. */\r
-static size_t xFreeBytesRemaining = ( ( size_t ) configADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );\r
+static size_t xFreeBytesRemaining = ( ( size_t ) heapADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );\r
\r
-/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */\r
+/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize \r
+member of an xBlockLink structure is set then the block belongs to the \r
+application. When the bit is free the block is still part of the free heap\r
+space. */\r
+static size_t xBlockAllocatedBit = 0;\r
\r
/*-----------------------------------------------------------*/\r
\r
prvHeapInit();\r
}\r
\r
- /* The wanted size is increased so it can contain a xBlockLink\r
- structure in addition to the requested amount of bytes. */\r
- if( xWantedSize > 0 )\r
+ /* Check the requested block size is not so large that the top bit is\r
+ set. The top bit of the block size member of the xBlockLink structure \r
+ is used to determine who owns the block - the application or the\r
+ kernel, so it must be free. */\r
+ if( ( xWantedSize & xBlockAllocatedBit ) == 0 )\r
{\r
- xWantedSize += heapSTRUCT_SIZE;\r
-\r
- /* Ensure that blocks are always aligned to the required number of \r
- bytes. */\r
- if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )\r
+ /* The wanted size is increased so it can contain a xBlockLink\r
+ structure in addition to the requested amount of bytes. */\r
+ if( xWantedSize > 0 )\r
{\r
- /* Byte alignment required. */\r
- xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );\r
- }\r
- }\r
+ xWantedSize += heapSTRUCT_SIZE;\r
\r
- if( ( xWantedSize > 0 ) && ( xWantedSize < xTotalHeapSize ) )\r
- {\r
- /* Traverse the list from the start (lowest address) block until one\r
- of adequate size is found. */\r
- pxPreviousBlock = &xStart;\r
- pxBlock = xStart.pxNextFreeBlock;\r
- while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )\r
- {\r
- pxPreviousBlock = pxBlock;\r
- pxBlock = pxBlock->pxNextFreeBlock;\r
+ /* Ensure that blocks are always aligned to the required number \r
+ of bytes. */\r
+ if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )\r
+ {\r
+ /* Byte alignment required. */\r
+ xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );\r
+ }\r
}\r
\r
- /* If the end marker was reached then a block of adequate size was\r
- not found. */\r
- if( pxBlock != pxEnd )\r
+ if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )\r
{\r
- /* Return the memory space - jumping over the xBlockLink structure\r
- at its start. */\r
- pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );\r
-\r
- /* This block is being returned for use so must be taken out of\r
- the list of free blocks. */\r
- pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;\r
-\r
- /* If the block is larger than required it can be split into two. */\r
- if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )\r
+ /* Traverse the list from the start (lowest address) block until \r
+ one of adequate size is found. */\r
+ pxPreviousBlock = &xStart;\r
+ pxBlock = xStart.pxNextFreeBlock;\r
+ while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )\r
{\r
- /* This block is to be split into two. Create a new block\r
- following the number of bytes requested. The void cast is\r
- used to prevent byte alignment warnings from the compiler. */\r
- pxNewBlockLink = ( void * ) ( ( ( unsigned char * ) pxBlock ) + xWantedSize );\r
-\r
- /* Calculate the sizes of two blocks split from the single\r
- block. */\r
- pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;\r
- pxBlock->xBlockSize = xWantedSize;\r
-\r
- /* Insert the new block into the list of free blocks. */\r
- prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );\r
+ pxPreviousBlock = pxBlock;\r
+ pxBlock = pxBlock->pxNextFreeBlock;\r
}\r
\r
- xFreeBytesRemaining -= pxBlock->xBlockSize;\r
+ /* If the end marker was reached then a block of adequate size \r
+ was not found. */\r
+ if( pxBlock != pxEnd )\r
+ {\r
+ /* Return the memory space pointed to - jumping over the \r
+ xBlockLink structure at its start. */\r
+ pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );\r
+\r
+ /* This block is being returned for use so must be taken out \r
+ of the list of free blocks. */\r
+ pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;\r
+\r
+ /* If the block is larger than required it can be split into \r
+ two. */\r
+ if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )\r
+ {\r
+ /* This block is to be split into two. Create a new \r
+ block following the number of bytes requested. The void \r
+ cast is used to prevent byte alignment warnings from the \r
+ compiler. */\r
+ pxNewBlockLink = ( void * ) ( ( ( unsigned char * ) pxBlock ) + xWantedSize );\r
+\r
+ /* Calculate the sizes of two blocks split from the \r
+ single block. */\r
+ pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;\r
+ pxBlock->xBlockSize = xWantedSize;\r
+\r
+ /* Insert the new block into the list of free blocks. */\r
+ prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );\r
+ }\r
+\r
+ xFreeBytesRemaining -= pxBlock->xBlockSize;\r
+\r
+ /* The block is being returned - it is allocated and owned\r
+ by the application and has no "next" block. */\r
+ pxBlock->xBlockSize |= xBlockAllocatedBit;\r
+ pxBlock->pxNextFreeBlock = NULL;\r
+ }\r
}\r
}\r
}\r
/* This casting is to keep the compiler from issuing warnings. */\r
pxLink = ( void * ) puc;\r
\r
- vTaskSuspendAll();\r
+ /* Check the block is actually allocated. */\r
+ configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );\r
+ configASSERT( pxLink->pxNextFreeBlock == NULL );\r
+ \r
+ if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )\r
{\r
- /* Add this block to the list of free blocks. */\r
- xFreeBytesRemaining += pxLink->xBlockSize;\r
- prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) ); \r
+ if( pxLink->pxNextFreeBlock == NULL )\r
+ {\r
+ /* The block is being returned to the heap - it is no longer\r
+ allocated. */\r
+ pxLink->xBlockSize &= ~xBlockAllocatedBit;\r
+\r
+ vTaskSuspendAll();\r
+ {\r
+ /* Add this block to the list of free blocks. */\r
+ xFreeBytesRemaining += pxLink->xBlockSize;\r
+ prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) );\r
+ }\r
+ xTaskResumeAll();\r
+ }\r
}\r
- xTaskResumeAll();\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
/* The heap now contains pxEnd. */\r
xFreeBytesRemaining -= heapSTRUCT_SIZE;\r
+\r
+ /* Work out the position of the top bit in a size_t variable. */\r
+ xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );\r
}\r
/*-----------------------------------------------------------*/\r
\r
number of bits implemented by the interrupt controller. */\r
#if configUNIQUE_INTERRUPT_PRIORITIES == 16\r
#define portPRIORITY_SHIFT 4\r
+ #define portMAX_BINARY_POINT_VALUE 3\r
#elif configUNIQUE_INTERRUPT_PRIORITIES == 32\r
#define portPRIORITY_SHIFT 3\r
+ #define portMAX_BINARY_POINT_VALUE 2\r
#elif configUNIQUE_INTERRUPT_PRIORITIES == 64\r
#define portPRIORITY_SHIFT 2\r
+ #define portMAX_BINARY_POINT_VALUE 1\r
#elif configUNIQUE_INTERRUPT_PRIORITIES == 128\r
#define portPRIORITY_SHIFT 1\r
+ #define portMAX_BINARY_POINT_VALUE 0\r
#elif configUNIQUE_INTERRUPT_PRIORITIES == 256\r
#define portPRIORITY_SHIFT 0\r
+ #define portMAX_BINARY_POINT_VALUE 0\r
#else\r
#error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware\r
#endif\r
#define portNO_FLOATING_POINT_CONTEXT ( ( portSTACK_TYPE ) 0 )\r
\r
/* Interrupt controller access addresses. */\r
-#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 )\r
+#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 )\r
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C )\r
-#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 )\r
-#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )\r
-#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile unsigned long * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )\r
-#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )\r
-#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET )\r
-#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET )\r
+#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 )\r
+#define portICCBPR_BINARY_POINT_OFFSET ( 0x08 )\r
+#define portICCRPR_RUNNING_PRIORITY_OFFSET ( 0x14 )\r
+#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )\r
+#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile unsigned long * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )\r
+#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )\r
+#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET )\r
+#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET )\r
+#define portICCBPR_BINARY_POINT_REGISTER ( *( ( const volatile unsigned long * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCBPR_BINARY_POINT_OFFSET ) ) )\r
+#define portICCRPR_RUNNING_PRIORITY_REGISTER ( *( ( const volatile unsigned char * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) )\r
+\r
+/* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary\r
+point is zero. */\r
+#define portBINARY_POINT_BITS ( ( unsigned char ) 0x03 )\r
\r
/* Constants required to setup the initial task context. */\r
#define portINITIAL_SPSR ( ( portSTACK_TYPE ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */\r
automatically be set to 0 when the first task is started. */\r
volatile unsigned long ulCriticalNesting = 9999UL;\r
\r
-/* The value to be written to the interrupt controllers priority mask register\r
-to mask interrupts that can use the FreeRTOS API without masking higher priority\r
-interrupts. */\r
-const unsigned long ulPortAPIPriorityMask = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );\r
-\r
/* Used to pass constants into the ASM code. The address at which variables are\r
placed is the constant value so indirect loads in the asm code are not\r
required. */\r
\r
if( ulAPSR != portAPSR_USER_MODE )\r
{\r
- /* Start the timer that generates the tick ISR. */\r
- configSETUP_TICK_INTERRUPT();\r
-\r
- __enable_irq();\r
- vPortRestoreTaskContext();\r
+ /* Only continue if the binary point value is set to its lowest possible\r
+ setting. See the comments in vPortValidateInterruptPriority() below for\r
+ more information. */\r
+ configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );\r
+ \r
+ if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE )\r
+ { \r
+ /* Start the timer that generates the tick ISR. */\r
+ configSETUP_TICK_INTERRUPT();\r
+\r
+ __enable_irq();\r
+ vPortRestoreTaskContext();\r
+ }\r
}\r
\r
/* Will only get here if xTaskStartScheduler() was called with the CPU in\r
- a non-privileged mode. */\r
+ a non-privileged mode or the binary point register was not set to its lowest\r
+ possible value. */\r
return 0;\r
}\r
/*-----------------------------------------------------------*/\r
handler runs at the lowest priority, so interrupts cannot already be masked,\r
so there is no need to save and restore the current mask value. */\r
__disable_irq();\r
- portICCPMR_PRIORITY_MASK_REGISTER = ulPortAPIPriorityMask;\r
+ portICCPMR_PRIORITY_MASK_REGISTER = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );\r
__asm( "DSB \n"\r
"ISB \n" );\r
__enable_irq();\r
unsigned long ulReturn;\r
\r
__disable_irq();\r
- if( portICCPMR_PRIORITY_MASK_REGISTER == ulPortAPIPriorityMask )\r
+ if( portICCPMR_PRIORITY_MASK_REGISTER == ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) )\r
{\r
/* Interrupts were already masked. */\r
ulReturn = pdTRUE;\r
else\r
{\r
ulReturn = pdFALSE;\r
- portICCPMR_PRIORITY_MASK_REGISTER = ulPortAPIPriorityMask;\r
+ portICCPMR_PRIORITY_MASK_REGISTER = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );\r
__asm( "DSB \n"\r
"ISB \n" );\r
}\r
\r
return ulReturn;\r
}\r
+/*-----------------------------------------------------------*/\r
+\r
+#if( configASSERT_DEFINED == 1 )\r
+\r
+ void vPortValidateInterruptPriority( void )\r
+ {\r
+ /* The following assertion will fail if a service routine (ISR) for\r
+ an interrupt that has been assigned a priority above\r
+ configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API\r
+ function. ISR safe FreeRTOS API functions must *only* be called\r
+ from interrupts that have been assigned a priority at or below\r
+ configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
+\r
+ Numerically low interrupt priority numbers represent logically high\r
+ interrupt priorities, therefore the priority of the interrupt must\r
+ be set to a value equal to or numerically *higher* than\r
+ configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
+\r
+ FreeRTOS maintains separate thread and ISR API functions to ensure\r
+ interrupt entry is as fast and simple as possible.\r
+\r
+ The following links provide detailed information:\r
+ http://www.freertos.org/RTOS-Cortex-M3-M4.html\r
+ http://www.freertos.org/FAQHelp.html */\r
+ configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );\r
+\r
+ /* Priority grouping: The interrupt controller (GIC) allows the bits\r
+ that define each interrupt's priority to be split between bits that\r
+ define the interrupt's pre-emption priority bits and bits that define\r
+ the interrupt's sub-priority. For simplicity all bits must be defined\r
+ to be pre-emption priority bits. The following assertion will fail if\r
+ this is not the case (if some bits represent a sub-priority).\r
+\r
+ The priority grouping is configured by the GIC's binary point register\r
+ (ICCBPR). Writting 0 to ICCBPR will ensure it is set to its lowest\r
+ possible value (which may be above 0). */\r
+ configASSERT( portICCBPR_BINARY_POINT_REGISTER <= portMAX_BINARY_POINT_VALUE );\r
+ }\r
+\r
+#endif /* configASSERT_DEFINED */\r
+\r
+\r
\r
\r
\r
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */\r
\r
+#ifdef configASSERT\r
+ void vPortValidateInterruptPriority( void );\r
+ #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()\r
+#else\r
+ #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID()\r
+#endif\r
+\r
#define portNOP() __nop()\r
\r
#ifdef __cplusplus\r