diff --git a/FreeRTOS/Source/portable/MPLAB/PIC32MX/ISR_Support.h b/FreeRTOS/Source/portable/MPLAB/PIC32MX/ISR_Support.h index e2aea528f..990bcf8b2 100644 --- a/FreeRTOS/Source/portable/MPLAB/PIC32MX/ISR_Support.h +++ b/FreeRTOS/Source/portable/MPLAB/PIC32MX/ISR_Support.h @@ -1,5 +1,5 @@ /* - FreeRTOS V7.5.3 - Copyright (C) 2013 Real Time Engineers Ltd. + FreeRTOS V7.5.3 - Copyright (C) 2013 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -69,24 +69,23 @@ #define portEPC_STACK_LOCATION 124 #define portSTATUS_STACK_LOCATION 128 -/******************************************************************/ +/******************************************************************/ .macro portSAVE_CONTEXT - /* Make room for the context. First save the current status so we can - manipulate it, and the cause and EPC registers so we capture their - original values in case of interrupt nesting. */ + /* Make room for the context. First save the current status so it can be + manipulated, and the cause and EPC registers so their original values are + captured. */ mfc0 k0, _CP0_CAUSE addiu sp, sp, -portCONTEXT_SIZE mfc0 k1, _CP0_STATUS - /* Also save s6 and s5 so we can use them during this interrupt. Any - nesting interrupts should maintain the values of these registers - across the ISR. */ + /* Also save s6 and s5 so they can be used. Any nesting interrupts should + maintain the values of these registers across the ISR. */ sw s6, 44(sp) sw s5, 40(sp) sw k1, portSTATUS_STACK_LOCATION(sp) - /* Enable interrupts above the current priority. */ + /* Prepare to enable interrupts above the current priority. */ srl k0, k0, 0xa ins k1, k0, 10, 6 ins k1, zero, 1, 4 @@ -100,7 +99,7 @@ /* If the nesting count is 0 then swap to the the system stack, otherwise the system stack is already being used. */ - bne s6, zero, .+20 + bne s6, zero, 1f nop /* Swap to the system stack. */ @@ -108,7 +107,7 @@ lw sp, (sp) /* Increment and save the nesting count. */ - addiu s6, s6, 1 +1: addiu s6, s6, 1 sw s6, 0(k0) /* s6 holds the EPC value, this is saved after interrupts are re-enabled. */ @@ -120,11 +119,11 @@ /* Save the context into the space just created. s6 is saved again here as it now contains the EPC value. No other s registers need be saved. */ - sw ra, 120(s5) + sw ra, 120(s5) sw s8, 116(s5) sw t9, 112(s5) - sw t8, 108(s5) - sw t7, 104(s5) + sw t8, 108(s5) + sw t7, 104(s5) sw t6, 100(s5) sw t5, 96(s5) sw t4, 92(s5) @@ -151,16 +150,16 @@ la s6, uxInterruptNesting lw s6, (s6) addiu s6, s6, -1 - bne s6, zero, .+20 + bne s6, zero, 1f nop /* Save the stack pointer. */ la s6, uxSavedTaskStackPointer sw s5, (s6) - +1: .endm - -/******************************************************************/ + +/******************************************************************/ .macro portRESTORE_CONTEXT /* Restore the stack pointer from the TCB. This is only done if the @@ -168,13 +167,13 @@ la s6, uxInterruptNesting lw s6, (s6) addiu s6, s6, -1 - bne s6, zero, .+20 + bne s6, zero, 1f nop la s6, uxSavedTaskStackPointer lw s5, (s6) - + /* Restore the context. */ - lw s6, 8(s5) +1: lw s6, 8(s5) mtlo s6 lw s6, 12(s5) mthi s6 @@ -203,6 +202,7 @@ /* Protect access to the k registers, and others. */ di + ehb /* Decrement the nesting count. */ la k0, uxInterruptNesting @@ -213,15 +213,16 @@ lw k0, portSTATUS_STACK_LOCATION(s5) lw k1, portEPC_STACK_LOCATION(s5) - /* Leave the stack how we found it. First load sp from s5, then restore - s5 from the stack. */ + /* Leave the stack in its original state. First load sp from s5, then + restore s5 from the stack. */ add sp, zero, s5 lw s5, 40(sp) - addiu sp, sp, portCONTEXT_SIZE + addiu sp, sp, portCONTEXT_SIZE mtc0 k0, _CP0_STATUS mtc0 k1, _CP0_EPC - eret + ehb + eret nop .endm diff --git a/FreeRTOS/Source/portable/MPLAB/PIC32MX/port.c b/FreeRTOS/Source/portable/MPLAB/PIC32MX/port.c index 29ccc9fc6..c364aca47 100644 --- a/FreeRTOS/Source/portable/MPLAB/PIC32MX/port.c +++ b/FreeRTOS/Source/portable/MPLAB/PIC32MX/port.c @@ -1,5 +1,5 @@ /* - FreeRTOS V7.5.3 - Copyright (C) 2013 Real Time Engineers Ltd. + FreeRTOS V7.5.3 - Copyright (C) 2013 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -91,23 +91,67 @@ the first task is being restored. */ #define portINITIAL_SR ( portIE_BIT | portEXL_BIT ) +/* +By default port.c generates its tick interrupt from TIMER1. The user can +override this behaviour by: + 1: Providing their own implementation of vApplicationSetupTickTimerInterrupt(), + which is the function that configures the timer. The function is defined + as a weak symbol in this file so if the same function name is used in the + application code then the version in the application code will be linked + into the application in preference to the version defined in this file. + 2: Define configTICK_INTERRUPT_VECTOR to the vector number of the timer used + to generate the tick interrupt. For example, when timer 1 is used then + configTICK_INTERRUPT_VECTOR is set to _TIMER_1_VECTOR. + configTICK_INTERRUPT_VECTOR should be defined in FreeRTOSConfig.h. + 3: Define configCLEAR_TICK_TIMER_INTERRUPT() to clear the interrupt in the + timer used to generate the tick interrupt. For example, when timer 1 is + used configCLEAR_TICK_TIMER_INTERRUPT() is defined to + IFS0CLR = _IFS0_T1IF_MASK. +*/ #ifndef configTICK_INTERRUPT_VECTOR #define configTICK_INTERRUPT_VECTOR _TIMER_1_VECTOR + #define configCLEAR_TICK_TIMER_INTERRUPT() IFS0CLR = _IFS0_T1IF_MASK +#else + #ifndef configCLEAR_TICK_TIMER_INTERRUPT + #error If configTICK_INTERRUPT_VECTOR is defined in application code then configCLEAR_TICK_TIMER_INTERRUPT must also be defined in application code. + #endif #endif -/* Records the interrupt nesting depth. This starts at one as it will be -decremented to 0 when the first task starts. */ -volatile unsigned portBASE_TYPE uxInterruptNesting = 0x01; +/* Let the user override the pre-loading of the initial RA with the address of +prvTaskExitError() in case is messes up unwinding of the stack in the +debugger - in which case configTASK_RETURN_ADDRESS can be defined as 0 (NULL). */ +#ifdef configTASK_RETURN_ADDRESS + #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS +#else + #define portTASK_RETURN_ADDRESS prvTaskExitError +#endif -/* Stores the task stack pointer when a switch is made to use the system stack. */ -unsigned portBASE_TYPE uxSavedTaskStackPointer = 0; +/* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task +stack checking. A problem in the ISR stack will trigger an assert, not call the +stack overflow hook function (because the stack overflow hook is specific to a +task stack, not the ISR stack). */ +#if( configCHECK_FOR_STACK_OVERFLOW > 2 ) -/* The stack used by interrupt service routines that cause a context switch. */ -portSTACK_TYPE xISRStack[ configISR_STACK_SIZE ] = { 0 }; + /* Don't use 0xa5 as the stack fill bytes as that is used by the kernerl for + the task stacks, and so will legitimately appear in many positions within + the ISR stack. */ + #define portISR_STACK_FILL_BYTE 0xee + + static const unsigned char ucExpectedStackBytes[] = { + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE }; \ + + #define portCHECK_ISR_STACK() configASSERT( ( memcmp( ( void * ) xISRStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) == 0 ) ) +#else + /* Define the function away. */ + #define portCHECK_ISR_STACK() +#endif /* configCHECK_FOR_STACK_OVERFLOW > 2 */ + +/*-----------------------------------------------------------*/ -/* The top of stack value ensures there is enough space to store 6 registers on -the callers stack, as some functions seem to want to do this. */ -const portSTACK_TYPE * const xISRStackTop = &( xISRStack[ configISR_STACK_SIZE - 7 ] ); /* * Place the prototype here to ensure the interrupt vector is correctly installed. @@ -125,6 +169,27 @@ extern void __attribute__( (interrupt(ipl1), vector( configTICK_INTERRUPT_VECTOR */ void __attribute__( (interrupt(ipl1), vector(_CORE_SOFTWARE_0_VECTOR))) vPortYieldISR( void ); +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + +/*-----------------------------------------------------------*/ + +/* Records the interrupt nesting depth. This is initialised to one as it is +decremented to 0 when the first task starts. */ +volatile unsigned portBASE_TYPE uxInterruptNesting = 0x01; + +/* Stores the task stack pointer when a switch is made to use the system stack. */ +unsigned portBASE_TYPE uxSavedTaskStackPointer = 0; + +/* The stack used by interrupt service routines that cause a context switch. */ +portSTACK_TYPE xISRStack[ configISR_STACK_SIZE ] = { 0 }; + +/* The top of stack value ensures there is enough space to store 6 registers on +the callers stack, as some functions seem to want to do this. */ +const portSTACK_TYPE * const xISRStackTop = &( xISRStack[ configISR_STACK_SIZE - 7 ] ); + /*-----------------------------------------------------------*/ /* @@ -144,25 +209,36 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE *pxTopOfStack = (portSTACK_TYPE) _CP0_GET_CAUSE(); pxTopOfStack--; - *pxTopOfStack = (portSTACK_TYPE) portINITIAL_SR; /* CP0_STATUS */ + *pxTopOfStack = (portSTACK_TYPE) portINITIAL_SR;/* CP0_STATUS */ pxTopOfStack--; *pxTopOfStack = (portSTACK_TYPE) pxCode; /* CP0_EPC */ pxTopOfStack--; - *pxTopOfStack = (portSTACK_TYPE) NULL; /* ra */ + *pxTopOfStack = (portSTACK_TYPE) portTASK_RETURN_ADDRESS; /* ra */ pxTopOfStack -= 15; - *pxTopOfStack = (portSTACK_TYPE) pvParameters; /* Parameters to pass in */ - pxTopOfStack -= 14; - - *pxTopOfStack = (portSTACK_TYPE) 0x00000000; /* critical nesting level - no longer used. */ - pxTopOfStack--; + *pxTopOfStack = (portSTACK_TYPE) pvParameters; /* Parameters to pass in. */ + pxTopOfStack -= 15; return pxTopOfStack; } /*-----------------------------------------------------------*/ +static void prvTaskExitError( void ) +{ + /* A function that implements a task must not exit or attempt to return to + its caller as there is nothing to return to. If a task wants to exit it + should instead call vTaskDelete( NULL ). + + Artificially force an assert() to be triggered if configASSERT() is + defined, then stop here so application writers can catch the error. */ + configASSERT( uxSavedTaskStackPointer == 0UL ); + portDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + /* * Setup a timer for a regular tick. This function uses peripheral timer 1. * The function is declared weak so an application writer can use a different @@ -206,6 +282,13 @@ portBASE_TYPE xPortStartScheduler( void ) extern void vPortStartFirstTask( void ); extern void *pxCurrentTCB; + #if ( configCHECK_FOR_STACK_OVERFLOW > 2 ) + { + /* Fill the ISR stack to make it easy to asses how much is being used. */ + memset( ( void * ) xISRStack, portISR_STACK_FILL_BYTE, sizeof( xISRStack ) ); + } + #endif /* configCHECK_FOR_STACK_OVERFLOW > 2 */ + /* Clear the software interrupt flag. */ IFS0CLR = _IFS0_CS0IF_MASK; @@ -226,7 +309,12 @@ extern void *pxCurrentTCB; uxSavedTaskStackPointer = *( unsigned portBASE_TYPE * ) pxCurrentTCB; vPortStartFirstTask(); - /* Should never get here as the tasks will now be executing. */ + /* Should never get here as the tasks will now be executing! Call the task + exit error function to prevent compiler warnings about a static function + not being called in the case that the application writer overrides this + functionality by defining configTASK_RETURN_ADDRESS. */ + prvTaskExitError(); + return pdFALSE; } /*-----------------------------------------------------------*/ @@ -245,8 +333,11 @@ unsigned portBASE_TYPE uxSavedStatus; } vPortClearInterruptMaskFromISR( uxSavedStatus ); - /* Clear timer 1 interrupt. */ - IFS0CLR = _IFS0_T1IF_MASK; + /* Look for the ISR stack getting near or past its limit. */ + portCHECK_ISR_STACK(); + + /* Clear timer interrupt. */ + configCLEAR_TICK_TIMER_INTERRUPT(); } /*-----------------------------------------------------------*/ @@ -254,7 +345,7 @@ unsigned portBASE_TYPE uxPortSetInterruptMaskFromISR( void ) { unsigned portBASE_TYPE uxSavedStatusRegister; - asm volatile ( "di" ); + __builtin_disable_interrupts(); uxSavedStatusRegister = _CP0_GET_STATUS() | 0x01; /* This clears the IPL bits, then sets them to configMAX_SYSCALL_INTERRUPT_PRIORITY. This function should not be called diff --git a/FreeRTOS/Source/portable/MPLAB/PIC32MX/port_asm.S b/FreeRTOS/Source/portable/MPLAB/PIC32MX/port_asm.S index 97902d3ba..3936aca61 100644 --- a/FreeRTOS/Source/portable/MPLAB/PIC32MX/port_asm.S +++ b/FreeRTOS/Source/portable/MPLAB/PIC32MX/port_asm.S @@ -1,5 +1,5 @@ /* - FreeRTOS V7.5.3 - Copyright (C) 2013 Real Time Engineers Ltd. + FreeRTOS V7.5.3 - Copyright (C) 2013 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -116,29 +116,27 @@ vPortStartFirstTask: /*******************************************************************/ - .set noreorder + .set noreorder .set noat - .ent vPortYieldISR + .ent vPortYieldISR vPortYieldISR: /* Make room for the context. First save the current status so it can be manipulated, and the cause and EPC registers so thier original values are captured. */ - mfc0 k0, _CP0_CAUSE - addiu sp, sp, -portCONTEXT_SIZE + addiu sp, sp, -portCONTEXT_SIZE mfc0 k1, _CP0_STATUS - /* Also save s6 and s5 so we can use them during this interrupt. Any - nesting interrupts should maintain the values of these registers - across the ISR. */ + /* Also save s6 and s5 so they can be used. Any nesting interrupts should + maintain the values of these registers across the ISR. */ sw s6, 44(sp) sw s5, 40(sp) sw k1, portSTATUS_STACK_LOCATION(sp) - /* Interrupts above the kernel priority are going to be re-enabled. */ - srl k0, k0, 0xa - ins k1, k0, 10, 6 + /* Prepare to re-enabled interrupt above the kernel priority. */ + ins k1, zero, 10, 6 + ori k1, k1, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) ins k1, zero, 1, 4 /* s5 is used as the frame pointer. */ @@ -159,16 +157,16 @@ vPortYieldISR: after interrupts are enabled. */ mfc0 s6, _CP0_EPC - /* Re-enable interrupts. */ + /* Re-enable interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY. */ mtc0 k1, _CP0_STATUS /* Save the context into the space just created. s6 is saved again here as it now contains the EPC value. */ - sw ra, 120(s5) + sw ra, 120(s5) sw s8, 116(s5) sw t9, 112(s5) - sw t8, 108(s5) - sw t7, 104(s5) + sw t8, 108(s5) + sw t7, 104(s5) sw t6, 100(s5) sw t5, 96(s5) sw t4, 92(s5) @@ -185,7 +183,7 @@ vPortYieldISR: sw s7, 48(s5) sw s6, portEPC_STACK_LOCATION(s5) /* s5 and s6 has already been saved. */ - sw s4, 36(s5) + sw s4, 36(s5) sw s3, 32(s5) sw s2, 28(s5) sw s1, 24(s5) @@ -209,18 +207,21 @@ vPortYieldISR: is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only ever raise the IPL value and never lower it. */ di + ehb mfc0 s7, _CP0_STATUS - ins s7, $0, 10, 6 + ins s7, zero, 10, 6 ori s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1 /* This mtc0 re-enables interrupts, but only above configMAX_SYSCALL_INTERRUPT_PRIORITY. */ mtc0 s6, _CP0_STATUS + ehb /* Clear the software interrupt in the core. */ mfc0 s6, _CP0_CAUSE ins s6, zero, 8, 1 mtc0 s6, _CP0_CAUSE + ehb /* Clear the interrupt in the interrupt controller. */ la s6, IFS0CLR @@ -232,6 +233,7 @@ vPortYieldISR: /* Clear the interrupt mask again. The saved status value is still in s7. */ mtc0 s7, _CP0_STATUS + ehb /* Restore the stack pointer from the TCB. */ la s0, pxCurrentTCB @@ -273,6 +275,7 @@ vPortYieldISR: /* Protect access to the k registers, and others. */ di + ehb /* Set nesting back to zero. As the lowest priority interrupt this interrupt cannot have nested. */ @@ -290,10 +293,11 @@ vPortYieldISR: lw k0, portEPC_STACK_LOCATION(sp) /* Remove stack frame. */ - addiu sp, sp, portCONTEXT_SIZE + addiu sp, sp, portCONTEXT_SIZE mtc0 k1, _CP0_STATUS mtc0 k0, _CP0_EPC + ehb eret nop diff --git a/FreeRTOS/Source/portable/MPLAB/PIC32MX/portmacro.h b/FreeRTOS/Source/portable/MPLAB/PIC32MX/portmacro.h index 129938f6f..b7be9f2c0 100644 --- a/FreeRTOS/Source/portable/MPLAB/PIC32MX/portmacro.h +++ b/FreeRTOS/Source/portable/MPLAB/PIC32MX/portmacro.h @@ -74,7 +74,7 @@ extern "C" { #endif /*----------------------------------------------------------- - * Port specific definitions. + * Port specific definitions. * * The settings in this file configure FreeRTOS correctly for the * given hardware and compiler. @@ -104,7 +104,7 @@ extern "C" { /* Hardware specifics. */ #define portBYTE_ALIGNMENT 8 #define portSTACK_GROWTH -1 -#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ ) +#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ ) /*-----------------------------------------------------------*/ /* Critical section management. */ @@ -112,11 +112,11 @@ extern "C" { #define portALL_IPL_BITS ( 0x3fUL << portIPL_SHIFT ) #define portSW0_BIT ( 0x01 << 8 ) -/* This clears the IPL bits, then sets them to -configMAX_SYSCALL_INTERRUPT_PRIORITY. An extra check is performed if -configASSERT() is defined to ensure an assertion handler does not inadvertently -attempt to lower the IPL when the call to assert was triggered because the IPL -value was found to be above configMAX_SYSCALL_INTERRUPT_PRIORITY when an ISR +/* This clears the IPL bits, then sets them to +configMAX_SYSCALL_INTERRUPT_PRIORITY. An extra check is performed if +configASSERT() is defined to ensure an assertion handler does not inadvertently +attempt to lower the IPL when the call to assert was triggered because the IPL +value was found to be above configMAX_SYSCALL_INTERRUPT_PRIORITY when an ISR safe FreeRTOS API function was executed. ISR safe FreeRTOS API functions are those that end in FromISR. FreeRTOS maintains a separate interrupt API to ensure API function and interrupt entry is as fast and as simple as possible. */ @@ -129,7 +129,7 @@ ensure API function and interrupt entry is as fast and as simple as possible. */ ulStatus = _CP0_GET_STATUS(); \ \ /* Is the current IPL below configMAX_SYSCALL_INTERRUPT_PRIORITY? */ \ - if( ( ( ulStatus & portALL_IPL_BITS ) >> portIPL_SHIFT ) < configMAX_SYSCALL_INTERRUPT_PRIORITY ) \ + if( ( ( ulStatus & portALL_IPL_BITS ) >> portIPL_SHIFT ) < configMAX_SYSCALL_INTERRUPT_PRIORITY ) \ { \ ulStatus &= ~portALL_IPL_BITS; \ _CP0_SET_STATUS( ( ulStatus | ( configMAX_SYSCALL_INTERRUPT_PRIORITY << portIPL_SHIFT ) ) ); \ @@ -200,13 +200,10 @@ unsigned long ulCause; \ _CP0_SET_CAUSE( ulCause ); \ } -#ifdef configASSERT - #define portCURRENT_INTERRUPT_PRIORITY ( ( _CP0_GET_STATUS() & portALL_IPL_BITS ) >> portIPL_SHIFT ) - #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() configASSERT( portCURRENT_INTERRUPT_PRIORITY <= configMAX_SYSCALL_INTERRUPT_PRIORITY ) -#endif /* configASSERT */ +#define portCURRENT_INTERRUPT_PRIORITY ( ( _CP0_GET_STATUS() & portALL_IPL_BITS ) >> portIPL_SHIFT ) +#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() configASSERT( portCURRENT_INTERRUPT_PRIORITY <= configMAX_SYSCALL_INTERRUPT_PRIORITY ) - -#define portNOP() asm volatile ( "nop" ) +#define portNOP() __asm volatile ( "nop" ) /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/MSVC-MingW/port.c b/FreeRTOS/Source/portable/MSVC-MingW/port.c index 851f4b8bd..77d6efa99 100644 --- a/FreeRTOS/Source/portable/MSVC-MingW/port.c +++ b/FreeRTOS/Source/portable/MSVC-MingW/port.c @@ -68,6 +68,12 @@ #include "task.h" #include +#ifdef __GNUC__ + #include "mmsystem.h" +#else + #pragma comment(lib, "winmm.lib") +#endif + #define portMAX_INTERRUPTS ( ( unsigned long ) sizeof( unsigned long ) * 8UL ) /* The number of bits in an unsigned long. */ #define portNO_CRITICAL_NESTING ( ( unsigned long ) 0 ) @@ -92,6 +98,12 @@ static void prvProcessSimulatedInterrupts( void ); static unsigned long prvProcessYieldInterrupt( void ); static unsigned long prvProcessTickInterrupt( void ); +/* + * Called when the process exits to let Windows know the high timer resolution + * is no longer required. + */ +static BOOL WINAPI prvEndProcess( DWORD dwCtrlType ); + /*-----------------------------------------------------------*/ /* The WIN32 simulator runs each task in a thread. The context switching is @@ -140,7 +152,23 @@ extern void *pxCurrentTCB; static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter ) { -portTickType xMinimumWindowsBlockTime = ( portTickType ) 20; +portTickType xMinimumWindowsBlockTime; +TIMECAPS xTimeCaps; + + /* Set the timer resolution to the maximum possible. */ + if( timeGetDevCaps( &xTimeCaps, sizeof( xTimeCaps ) ) == MMSYSERR_NOERROR ) + { + xMinimumWindowsBlockTime = ( portTickType ) xTimeCaps.wPeriodMin; + timeBeginPeriod( xTimeCaps.wPeriodMin ); + + /* Register an exit handler so the timeBeginPeriod() function can be + matched with a timeEndPeriod() when the application exits. */ + SetConsoleCtrlHandler( prvEndProcess, TRUE ); + } + else + { + xMinimumWindowsBlockTime = ( portTickType ) 20; + } /* Just to prevent compiler warnings. */ ( void ) lpParameter; @@ -184,6 +212,23 @@ portTickType xMinimumWindowsBlockTime = ( portTickType ) 20; } /*-----------------------------------------------------------*/ +static BOOL WINAPI prvEndProcess( DWORD dwCtrlType ) +{ +TIMECAPS xTimeCaps; + + ( void ) dwCtrlType; + + if( timeGetDevCaps( &xTimeCaps, sizeof( xTimeCaps ) ) == MMSYSERR_NOERROR ) + { + /* Match the call to timeBeginPeriod( xTimeCaps.wPeriodMin ) made when + the process started with a timeEndPeriod() as the process exits. */ + timeEndPeriod( xTimeCaps.wPeriodMin ); + } + + return pdPASS; +} +/*-----------------------------------------------------------*/ + portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) { xThreadState *pxThreadState = NULL;