2 FreeRTOS V7.4.2 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
4 FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT
\r
5 http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
10 * Complete, revised, and edited pdf reference manuals are also *
\r
13 * Purchasing FreeRTOS documentation will not only help you, by *
\r
14 * ensuring you get running as quickly as possible and with an *
\r
15 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
16 * the FreeRTOS project to continue with its mission of providing *
\r
17 * professional grade, cross platform, de facto standard solutions *
\r
18 * for microcontrollers - completely free of charge! *
\r
20 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
22 * Thank you for using FreeRTOS, and thank you for your support! *
\r
24 ***************************************************************************
\r
27 This file is part of the FreeRTOS distribution.
\r
29 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
30 the terms of the GNU General Public License (version 2) as published by the
\r
31 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
33 >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to
\r
34 distribute a combined work that includes FreeRTOS without being obliged to
\r
35 provide the source code for proprietary components outside of the FreeRTOS
\r
38 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
39 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
40 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
\r
41 details. You should have received a copy of the GNU General Public License
\r
42 and the FreeRTOS license exception along with FreeRTOS; if not it can be
\r
43 viewed here: http://www.freertos.org/a00114.html and also obtained by
\r
44 writing to Real Time Engineers Ltd., contact details for whom are available
\r
45 on the FreeRTOS WEB site.
\r
49 ***************************************************************************
\r
51 * Having a problem? Start by reading the FAQ "My application does *
\r
52 * not run, what could be wrong?" *
\r
54 * http://www.FreeRTOS.org/FAQHelp.html *
\r
56 ***************************************************************************
\r
59 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
60 license and Real Time Engineers Ltd. contact details.
\r
62 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
63 including FreeRTOS+Trace - an indispensable productivity tool, and our new
\r
64 fully thread aware and reentrant UDP/IP stack.
\r
66 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
67 Integrity Systems, who sell the code with commercial support,
\r
68 indemnification and middleware, under the OpenRTOS brand.
\r
70 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
71 engineered and independently SIL3 certified version for use in safety and
\r
72 mission critical applications that require provable dependability.
\r
75 /* Scheduler includes. */
\r
76 #include "FreeRTOS.h"
\r
80 #define portMAX_INTERRUPTS ( ( unsigned long ) sizeof( unsigned long ) * 8UL ) /* The number of bits in an unsigned long. */
\r
81 #define portNO_CRITICAL_NESTING ( ( unsigned long ) 0 )
\r
84 * Created as a high priority thread, this function uses a timer to simulate
\r
85 * a tick interrupt being generated on an embedded target. In this Windows
\r
86 * environment the timer does not achieve anything approaching real time
\r
87 * performance though.
\r
89 static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter );
\r
92 * Process all the simulated interrupts - each represented by a bit in
\r
93 * ulPendingInterrupts variable.
\r
95 static void prvProcessSimulatedInterrupts( void );
\r
98 * Interrupt handlers used by the kernel itself. These are executed from the
\r
99 * simulated interrupt handler thread.
\r
101 static unsigned long prvProcessYieldInterrupt( void );
\r
102 static unsigned long prvProcessTickInterrupt( void );
\r
104 /*-----------------------------------------------------------*/
\r
106 /* The WIN32 simulator runs each task in a thread. The context switching is
\r
107 managed by the threads, so the task stack does not have to be managed directly,
\r
108 although the task stack is still used to hold an xThreadState structure this is
\r
109 the only thing it will ever hold. The structure indirectly maps the task handle
\r
110 to a thread handle. */
\r
113 /* Handle of the thread that executes the task. */
\r
118 /* Simulated interrupts waiting to be processed. This is a bit mask where each
\r
119 bit represents one interrupt, so a maximum of 32 interrupts can be simulated. */
\r
120 static volatile unsigned long ulPendingInterrupts = 0UL;
\r
122 /* An event used to inform the simulated interrupt processing thread (a high
\r
123 priority thread that simulated interrupt processing) that an interrupt is
\r
125 static void *pvInterruptEvent = NULL;
\r
127 /* Mutex used to protect all the simulated interrupt variables that are accessed
\r
128 by multiple threads. */
\r
129 static void *pvInterruptEventMutex = NULL;
\r
131 /* The critical nesting count for the currently executing task. This is
\r
132 initialised to a non-zero value so interrupts do not become enabled during
\r
133 the initialisation phase. As each task has its own critical nesting value
\r
134 ulCriticalNesting will get set to zero when the first task runs. This
\r
135 initialisation is probably not critical in this simulated environment as the
\r
136 simulated interrupt handlers do not get created until the FreeRTOS scheduler is
\r
138 static unsigned long ulCriticalNesting = 9999UL;
\r
140 /* Handlers for all the simulated software interrupts. The first two positions
\r
141 are used for the Yield and Tick interrupts so are handled slightly differently,
\r
142 all the other interrupts can be user defined. */
\r
143 static unsigned long (*ulIsrHandler[ portMAX_INTERRUPTS ])( void ) = { 0 };
\r
145 /* Pointer to the TCB of the currently executing task. */
\r
146 extern void *pxCurrentTCB;
\r
148 /*-----------------------------------------------------------*/
\r
150 static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )
\r
152 portTickType xMinimumWindowsBlockTime = ( portTickType ) 20;
\r
154 /* Just to prevent compiler warnings. */
\r
155 ( void ) lpParameter;
\r
159 /* Wait until the timer expires and we can access the simulated interrupt
\r
160 variables. *NOTE* this is not a 'real time' way of generating tick
\r
161 events as the next wake time should be relative to the previous wake
\r
162 time, not the time that Sleep() is called. It is done this way to
\r
163 prevent overruns in this very non real time simulated/emulated
\r
165 if( portTICK_RATE_MS < xMinimumWindowsBlockTime )
\r
167 Sleep( xMinimumWindowsBlockTime );
\r
171 Sleep( portTICK_RATE_MS );
\r
174 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
176 /* The timer has expired, generate the simulated tick event. */
\r
177 ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
\r
179 /* The interrupt is now pending - notify the simulated interrupt
\r
181 SetEvent( pvInterruptEvent );
\r
183 /* Give back the mutex so the simulated interrupt handler unblocks
\r
184 and can access the interrupt handler variables. */
\r
185 ReleaseMutex( pvInterruptEventMutex );
\r
189 /* Should never reach here - MingW complains if you leave this line out,
\r
190 MSVC complains if you put it in. */
\r
194 /*-----------------------------------------------------------*/
\r
196 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
\r
198 xThreadState *pxThreadState = NULL;
\r
199 char *pcTopOfStack = ( char * ) pxTopOfStack;
\r
201 /* In this simulated case a stack is not initialised, but instead a thread
\r
202 is created that will execute the task being created. The thread handles
\r
203 the context switching itself. The xThreadState object is placed onto
\r
204 the stack that was created for the task - so the stack buffer is still
\r
205 used, just not in the conventional way. It will not be used for anything
\r
206 other than holding this structure. */
\r
207 pxThreadState = ( xThreadState * ) ( pcTopOfStack - sizeof( xThreadState ) );
\r
209 /* Create the thread itself. */
\r
210 pxThreadState->pvThread = CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, NULL );
\r
211 SetThreadAffinityMask( pxThreadState->pvThread, 0x01 );
\r
212 SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
\r
213 SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
\r
215 return ( portSTACK_TYPE * ) pxThreadState;
\r
217 /*-----------------------------------------------------------*/
\r
219 portBASE_TYPE xPortStartScheduler( void )
\r
222 long lSuccess = pdPASS;
\r
223 xThreadState *pxThreadState;
\r
225 /* Install the interrupt handlers used by the scheduler itself. */
\r
226 vPortSetInterruptHandler( portINTERRUPT_YIELD, prvProcessYieldInterrupt );
\r
227 vPortSetInterruptHandler( portINTERRUPT_TICK, prvProcessTickInterrupt );
\r
229 /* Create the events and mutexes that are used to synchronise all the
\r
231 pvInterruptEventMutex = CreateMutex( NULL, FALSE, NULL );
\r
232 pvInterruptEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
\r
234 if( ( pvInterruptEventMutex == NULL ) || ( pvInterruptEvent == NULL ) )
\r
239 /* Set the priority of this thread such that it is above the priority of
\r
240 the threads that run tasks. This higher priority is required to ensure
\r
241 simulated interrupts take priority over tasks. */
\r
242 pvHandle = GetCurrentThread();
\r
243 if( pvHandle == NULL )
\r
248 if( lSuccess == pdPASS )
\r
250 if( SetThreadPriority( pvHandle, THREAD_PRIORITY_NORMAL ) == 0 )
\r
254 SetThreadPriorityBoost( pvHandle, TRUE );
\r
255 SetThreadAffinityMask( pvHandle, 0x01 );
\r
258 if( lSuccess == pdPASS )
\r
260 /* Start the thread that simulates the timer peripheral to generate
\r
261 tick interrupts. The priority is set below that of the simulated
\r
262 interrupt handler so the interrupt event mutex is used for the
\r
263 handshake / overrun protection. */
\r
264 pvHandle = CreateThread( NULL, 0, prvSimulatedPeripheralTimer, NULL, 0, NULL );
\r
265 if( pvHandle != NULL )
\r
267 SetThreadPriority( pvHandle, THREAD_PRIORITY_BELOW_NORMAL );
\r
268 SetThreadPriorityBoost( pvHandle, TRUE );
\r
269 SetThreadAffinityMask( pvHandle, 0x01 );
\r
272 /* Start the highest priority task by obtaining its associated thread
\r
273 state structure, in which is stored the thread handle. */
\r
274 pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
\r
275 ulCriticalNesting = portNO_CRITICAL_NESTING;
\r
277 /* Bump up the priority of the thread that is going to run, in the
\r
278 hope that this will asist in getting the Windows thread scheduler to
\r
279 behave as an embedded engineer might expect. */
\r
280 ResumeThread( pxThreadState->pvThread );
\r
282 /* Handle all simulated interrupts - including yield requests and
\r
283 simulated ticks. */
\r
284 prvProcessSimulatedInterrupts();
\r
287 /* Would not expect to return from prvProcessSimulatedInterrupts(), so should
\r
291 /*-----------------------------------------------------------*/
\r
293 static unsigned long prvProcessYieldInterrupt( void )
\r
297 /*-----------------------------------------------------------*/
\r
299 static unsigned long prvProcessTickInterrupt( void )
\r
301 unsigned long ulSwitchRequired;
\r
303 /* Process the tick itself. */
\r
304 vTaskIncrementTick();
\r
305 #if( configUSE_PREEMPTION != 0 )
\r
307 /* A context switch is only automatically performed from the tick
\r
308 interrupt if the pre-emptive scheduler is being used. */
\r
309 ulSwitchRequired = pdTRUE;
\r
313 ulSwitchRequired = pdFALSE;
\r
317 return ulSwitchRequired;
\r
319 /*-----------------------------------------------------------*/
\r
321 static void prvProcessSimulatedInterrupts( void )
\r
323 unsigned long ulSwitchRequired, i;
\r
324 xThreadState *pxThreadState;
\r
325 void *pvObjectList[ 2 ];
\r
327 /* Going to block on the mutex that ensured exclusive access to the simulated
\r
328 interrupt objects, and the event that signals that a simulated interrupt
\r
329 should be processed. */
\r
330 pvObjectList[ 0 ] = pvInterruptEventMutex;
\r
331 pvObjectList[ 1 ] = pvInterruptEvent;
\r
335 WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );
\r
337 /* Used to indicate whether the simulated interrupt processing has
\r
338 necessitated a context switch to another task/thread. */
\r
339 ulSwitchRequired = pdFALSE;
\r
341 /* For each interrupt we are interested in processing, each of which is
\r
342 represented by a bit in the 32bit ulPendingInterrupts variable. */
\r
343 for( i = 0; i < portMAX_INTERRUPTS; i++ )
\r
345 /* Is the simulated interrupt pending? */
\r
346 if( ulPendingInterrupts & ( 1UL << i ) )
\r
348 /* Is a handler installed? */
\r
349 if( ulIsrHandler[ i ] != NULL )
\r
351 /* Run the actual handler. */
\r
352 if( ulIsrHandler[ i ]() != pdFALSE )
\r
354 ulSwitchRequired |= ( 1 << i );
\r
358 /* Clear the interrupt pending bit. */
\r
359 ulPendingInterrupts &= ~( 1UL << i );
\r
363 if( ulSwitchRequired != pdFALSE )
\r
365 void *pvOldCurrentTCB;
\r
367 pvOldCurrentTCB = pxCurrentTCB;
\r
369 /* Select the next task to run. */
\r
370 vTaskSwitchContext();
\r
372 /* If the task selected to enter the running state is not the task
\r
373 that is already in the running state. */
\r
374 if( pvOldCurrentTCB != pxCurrentTCB )
\r
376 /* Suspend the old thread. */
\r
377 pxThreadState = ( xThreadState *) *( ( unsigned long * ) pvOldCurrentTCB );
\r
378 SuspendThread( pxThreadState->pvThread );
\r
380 /* Obtain the state of the task now selected to enter the
\r
382 pxThreadState = ( xThreadState * ) ( *( unsigned long *) pxCurrentTCB );
\r
383 ResumeThread( pxThreadState->pvThread );
\r
387 ReleaseMutex( pvInterruptEventMutex );
\r
390 /*-----------------------------------------------------------*/
\r
392 void vPortDeleteThread( void *pvTaskToDelete )
\r
394 xThreadState *pxThreadState;
\r
396 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
398 /* Find the handle of the thread being deleted. */
\r
399 pxThreadState = ( xThreadState * ) ( *( unsigned long *) pvTaskToDelete );
\r
400 TerminateThread( pxThreadState->pvThread, 0 );
\r
402 ReleaseMutex( pvInterruptEventMutex );
\r
404 /*-----------------------------------------------------------*/
\r
406 void vPortEndScheduler( void )
\r
408 /* This function IS NOT TESTED! */
\r
409 TerminateProcess( GetCurrentProcess(), 0 );
\r
411 /*-----------------------------------------------------------*/
\r
413 void vPortGenerateSimulatedInterrupt( unsigned long ulInterruptNumber )
\r
415 if( ( ulInterruptNumber < portMAX_INTERRUPTS ) && ( pvInterruptEventMutex != NULL ) )
\r
417 /* Yield interrupts are processed even when critical nesting is non-zero. */
\r
418 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
419 ulPendingInterrupts |= ( 1 << ulInterruptNumber );
\r
421 /* The simulated interrupt is now held pending, but don't actually process it
\r
422 yet if this call is within a critical section. It is possible for this to
\r
423 be in a critical section as calls to wait for mutexes are accumulative. */
\r
424 if( ulCriticalNesting == 0 )
\r
426 SetEvent( pvInterruptEvent );
\r
429 ReleaseMutex( pvInterruptEventMutex );
\r
432 /*-----------------------------------------------------------*/
\r
434 void vPortSetInterruptHandler( unsigned long ulInterruptNumber, unsigned long (*pvHandler)( void ) )
\r
436 if( ulInterruptNumber < portMAX_INTERRUPTS )
\r
438 if( pvInterruptEventMutex != NULL )
\r
440 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
441 ulIsrHandler[ ulInterruptNumber ] = pvHandler;
\r
442 ReleaseMutex( pvInterruptEventMutex );
\r
446 ulIsrHandler[ ulInterruptNumber ] = pvHandler;
\r
450 /*-----------------------------------------------------------*/
\r
452 void vPortEnterCritical( void )
\r
454 if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED )
\r
456 /* The interrupt event mutex is held for the entire critical section,
\r
457 effectively disabling (simulated) interrupts. */
\r
458 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
459 ulCriticalNesting++;
\r
463 ulCriticalNesting++;
\r
466 /*-----------------------------------------------------------*/
\r
468 void vPortExitCritical( void )
\r
470 long lMutexNeedsReleasing;
\r
472 /* The interrupt event mutex should already be held by this thread as it was
\r
473 obtained on entry to the critical section. */
\r
475 lMutexNeedsReleasing = pdTRUE;
\r
477 if( ulCriticalNesting > portNO_CRITICAL_NESTING )
\r
479 if( ulCriticalNesting == ( portNO_CRITICAL_NESTING + 1 ) )
\r
481 ulCriticalNesting--;
\r
483 /* Were any interrupts set to pending while interrupts were
\r
484 (simulated) disabled? */
\r
485 if( ulPendingInterrupts != 0UL )
\r
487 SetEvent( pvInterruptEvent );
\r
489 /* Mutex will be released now, so does not require releasing
\r
490 on function exit. */
\r
491 lMutexNeedsReleasing = pdFALSE;
\r
492 ReleaseMutex( pvInterruptEventMutex );
\r
497 /* Tick interrupts will still not be processed as the critical
\r
498 nesting depth will not be zero. */
\r
499 ulCriticalNesting--;
\r
503 if( lMutexNeedsReleasing == pdTRUE )
\r
505 ReleaseMutex( pvInterruptEventMutex );
\r
508 /*-----------------------------------------------------------*/
\r