2006-05-02 17:39:15 +08:00
/*
2015-03-22 05:03:42 +08:00
FreeRTOS V8 .2 .1 - Copyright ( C ) 2015 Real Time Engineers Ltd .
2013-10-15 03:56:47 +08:00
All rights reserved
2012-10-16 20:17:47 +08:00
2013-07-18 02:32:57 +08:00
VISIT http : //www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
2006-05-02 17:39:15 +08:00
2009-10-05 17:46:11 +08:00
This file is part of the FreeRTOS distribution .
2006-05-02 17:39:15 +08:00
2009-10-13 18:54:32 +08:00
FreeRTOS is free software ; you can redistribute it and / or modify it under
2009-10-05 17:46:11 +08:00
the terms of the GNU General Public License ( version 2 ) as published by the
2013-07-18 02:32:57 +08:00
Free Software Foundation > > ! AND MODIFIED BY ! < < the FreeRTOS exception .
2013-02-20 02:36:58 +08:00
2015-03-22 05:03:42 +08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2014-04-24 22:26:36 +08:00
> > ! 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 . ! < <
2015-03-22 05:03:42 +08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2013-02-20 02:36:58 +08:00
FreeRTOS is distributed in the hope that it will be useful , but WITHOUT ANY
WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS
2014-12-22 03:09:18 +08:00
FOR A PARTICULAR PURPOSE . Full license text is available on the following
2013-07-18 02:32:57 +08:00
link : http : //www.freertos.org/a00114.html
2009-03-15 03:20:12 +08:00
2014-12-22 03:09:18 +08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* FreeRTOS provides completely free yet professionally developed , *
* robust , strictly quality controlled , supported , and cross *
* platform software that is more than just the market leader , it *
* is the industry ' s de facto standard . *
* *
* Help yourself get started quickly while simultaneously helping *
* to support the FreeRTOS project by purchasing a FreeRTOS *
* tutorial book , reference manual , or both : *
* http : //www.FreeRTOS.org/Documentation *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2015-01-16 21:20:28 +08:00
http : //www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
2015-03-22 05:03:42 +08:00
the FAQ page " My application does not run, what could be wrong? " . Have you
defined configASSERT ( ) ?
2014-12-22 03:09:18 +08:00
2015-03-22 05:03:42 +08:00
http : //www.FreeRTOS.org/support - In return for receiving this top quality
embedded software for free we request you assist our global community by
participating in the support forum .
2014-12-22 03:09:18 +08:00
2015-03-22 05:03:42 +08:00
http : //www.FreeRTOS.org/training - Investing in training allows your team to
be as productive as possible as early as possible . Now you can receive
FreeRTOS training directly from Richard Barry , CEO of Real Time Engineers
Ltd , and the world ' s leading authority on the world ' s leading RTOS .
2013-02-20 02:36:58 +08:00
2012-05-09 00:36:52 +08:00
http : //www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
2013-07-18 02:32:57 +08:00
including FreeRTOS + Trace - an indispensable productivity tool , a DOS
compatible FAT file system , and our tiny thread aware UDP / IP stack .
2014-12-22 03:09:18 +08:00
http : //www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
Come and try FreeRTOS + TCP , our new open source TCP / IP stack for FreeRTOS .
2015-01-16 21:20:28 +08:00
http : //www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
2014-12-22 03:09:18 +08:00
Integrity Systems ltd . to sell under the OpenRTOS brand . Low cost OpenRTOS
licenses offer ticketed support , indemnification and commercial middleware .
2013-07-18 02:32:57 +08:00
http : //www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
2013-02-20 02:36:58 +08:00
mission critical applications that require provable dependability .
2013-07-18 02:32:57 +08:00
1 tab = = 4 spaces !
2006-05-02 17:39:15 +08:00
*/
/*
Changes from V2 .6 .1
+ Replaced the sUsingPreemption variable with the configUSE_PREEMPTION
macro to be consistent with the later ports .
2006-05-28 16:17:56 +08:00
Changes from V4 .0 .1
+ Add function prvSetTickFrequencyDefault ( ) to set the DOS tick back to
its proper value when the scheduler exits .
2006-05-02 17:39:15 +08:00
*/
# include <stdlib.h>
# include <dos.h>
# include <setjmp.h>
# include "FreeRTOS.h"
# include "task.h"
# include "portasm.h"
/*-----------------------------------------------------------
* Implementation of functions defined in portable . h for the industrial
* PC port .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*lint -e950 Non ANSI reserved words okay in this file only. */
# define portTIMER_INT_NUMBER 0x08
/* Setup hardware for required tick interrupt rate. */
2013-12-29 22:06:04 +08:00
static void prvSetTickFrequency ( uint32_t ulTickRateHz ) ;
2006-05-02 17:39:15 +08:00
/* Restore hardware to as it was prior to starting the scheduler. */
static void prvExitFunction ( void ) ;
/* Either chain to the DOS tick (which itself clears the PIC) or clear the PIC
directly . We chain to the DOS tick as close as possible to the standard DOS
tick rate . */
static void prvPortResetPIC ( void ) ;
/* The ISR used depends on whether the preemptive or cooperative
scheduler is being used . */
# if( configUSE_PREEMPTION == 1 )
/* Tick service routine used by the scheduler when preemptive scheduling is
being used . */
static void __interrupt __far prvPreemptiveTick ( void ) ;
# else
/* Tick service routine used by the scheduler when cooperative scheduling is
being used . */
static void __interrupt __far prvNonPreemptiveTick ( void ) ;
# endif
/* Trap routine used by taskYIELD() to manually cause a context switch. */
static void __interrupt __far prvYieldProcessor ( void ) ;
2006-05-28 16:17:56 +08:00
/* Set the tick frequency back so the floppy drive works correctly when the
scheduler exits . */
static void prvSetTickFrequencyDefault ( void ) ;
2006-05-02 17:39:15 +08:00
/*lint -e956 File scopes necessary here. */
/* Used to signal when to chain to the DOS tick, and when to just clear the PIC ourselves. */
2013-12-29 22:06:04 +08:00
static int16_t sDOSTickCounter ;
2006-05-02 17:39:15 +08:00
/* Set true when the vectors are set so the scheduler will service the tick. */
2013-12-29 22:06:04 +08:00
static BaseType_t xSchedulerRunning = pdFALSE ;
2006-05-02 17:39:15 +08:00
/* Points to the original routine installed on the vector we use for manual context switches. This is then used to restore the original routine during prvExitFunction(). */
static void ( __interrupt __far * pxOldSwitchISR ) ( ) ;
/* Points to the original routine installed on the vector we use to chain to the DOS tick. This is then used to restore the original routine during prvExitFunction(). */
static void ( __interrupt __far * pxOldSwitchISRPlus1 ) ( ) ;
/* Used to restore the original DOS context when the scheduler is ended. */
static jmp_buf xJumpBuf ;
/*lint +e956 */
/*-----------------------------------------------------------*/
2013-12-29 22:06:04 +08:00
BaseType_t xPortStartScheduler ( void )
2006-05-02 17:39:15 +08:00
{
pxISR pxOriginalTickISR ;
/* This is called with interrupts already disabled. */
/* Remember what was on the interrupts we are going to use
so we can put them back later if required . */
pxOldSwitchISR = _dos_getvect ( portSWITCH_INT_NUMBER ) ;
pxOriginalTickISR = _dos_getvect ( portTIMER_INT_NUMBER ) ;
pxOldSwitchISRPlus1 = _dos_getvect ( portSWITCH_INT_NUMBER + 1 ) ;
prvSetTickFrequency ( configTICK_RATE_HZ ) ;
/* Put our manual switch (yield) function on a known
vector . */
_dos_setvect ( portSWITCH_INT_NUMBER , prvYieldProcessor ) ;
/* Put the old tick on a different interrupt number so we can
call it when we want . */
_dos_setvect ( portSWITCH_INT_NUMBER + 1 , pxOriginalTickISR ) ;
/* The ISR used depends on whether the preemptive or cooperative
scheduler is being used . */
# if( configUSE_PREEMPTION == 1 )
{
/* Put our tick switch function on the timer interrupt. */
_dos_setvect ( portTIMER_INT_NUMBER , prvPreemptiveTick ) ;
}
# else
{
/* We want the timer interrupt to just increment the tick count. */
_dos_setvect ( portTIMER_INT_NUMBER , prvNonPreemptiveTick ) ;
}
# endif
/* Setup a counter that is used to call the DOS interrupt as close
to it ' s original frequency as can be achieved given our chosen tick
frequency . */
sDOSTickCounter = portTICKS_PER_DOS_TICK ;
/* Clean up function if we want to return to DOS. */
if ( setjmp ( xJumpBuf ) ! = 0 )
{
prvExitFunction ( ) ;
xSchedulerRunning = pdFALSE ;
}
else
{
xSchedulerRunning = pdTRUE ;
/* Kick off the scheduler by setting up the context of the first task. */
portFIRST_CONTEXT ( ) ;
}
return xSchedulerRunning ;
}
/*-----------------------------------------------------------*/
/* The ISR used depends on whether the preemptive or cooperative
scheduler is being used . */
# if( configUSE_PREEMPTION == 1 )
static void __interrupt __far prvPreemptiveTick ( void )
{
/* Get the scheduler to update the task states following the tick. */
2013-06-06 23:46:40 +08:00
if ( xTaskIncrementTick ( ) ! = pdFALSE )
{
/* Switch in the context of the next task to be run. */
portSWITCH_CONTEXT ( ) ;
}
2006-05-02 17:39:15 +08:00
/* Reset the PIC ready for the next time. */
prvPortResetPIC ( ) ;
}
# else
static void __interrupt __far prvNonPreemptiveTick ( void )
{
/* Same as preemptive tick, but the cooperative scheduler is being used
so we don ' t have to switch in the context of the next task . */
2013-06-06 23:46:40 +08:00
xTaskIncrementTick ( ) ;
2006-05-02 17:39:15 +08:00
prvPortResetPIC ( ) ;
}
# endif
/*-----------------------------------------------------------*/
static void __interrupt __far prvYieldProcessor ( void )
{
/* Switch in the context of the next task to be run. */
portSWITCH_CONTEXT ( ) ;
}
/*-----------------------------------------------------------*/
static void prvPortResetPIC ( void )
{
/* We are going to call the DOS tick interrupt at as close a
frequency to the normal DOS tick as possible . */
/* WE SHOULD NOT DO THIS IF YIELD WAS CALLED. */
- - sDOSTickCounter ;
if ( sDOSTickCounter < = 0 )
{
2013-12-29 22:06:04 +08:00
sDOSTickCounter = ( int16_t ) portTICKS_PER_DOS_TICK ;
2006-05-02 17:39:15 +08:00
__asm { int portSWITCH_INT_NUMBER + 1 } ;
}
else
{
/* Reset the PIC as the DOS tick is not being called to
do it . */
__asm
{
mov al , 20 H
out 20 H , al
} ;
}
}
/*-----------------------------------------------------------*/
void vPortEndScheduler ( void )
{
/* Jump back to the processor state prior to starting the
scheduler . This means we are not going to be using a
task stack frame so the task can be deleted . */
longjmp ( xJumpBuf , 1 ) ;
}
/*-----------------------------------------------------------*/
static void prvExitFunction ( void )
{
void ( __interrupt __far * pxOriginalTickISR ) ( ) ;
/* Interrupts should be disabled here anyway - but no
harm in making sure . */
portDISABLE_INTERRUPTS ( ) ;
if ( xSchedulerRunning = = pdTRUE )
{
/* Set the DOS tick back onto the timer ticker. */
pxOriginalTickISR = _dos_getvect ( portSWITCH_INT_NUMBER + 1 ) ;
_dos_setvect ( portTIMER_INT_NUMBER , pxOriginalTickISR ) ;
2006-05-28 16:17:56 +08:00
prvSetTickFrequencyDefault ( ) ;
2006-05-02 17:39:15 +08:00
/* Put back the switch interrupt routines that was in place
before the scheduler started . */
_dos_setvect ( portSWITCH_INT_NUMBER , pxOldSwitchISR ) ;
_dos_setvect ( portSWITCH_INT_NUMBER + 1 , pxOldSwitchISRPlus1 ) ;
}
/* The tick timer is back how DOS wants it. We can re-enable
interrupts without the scheduler being called . */
portENABLE_INTERRUPTS ( ) ;
}
/*-----------------------------------------------------------*/
2013-12-29 22:06:04 +08:00
static void prvSetTickFrequency ( uint32_t ulTickRateHz )
2006-05-02 17:39:15 +08:00
{
2013-12-29 22:06:04 +08:00
const uint16_t usPIT_MODE = ( uint16_t ) 0x43 ;
const uint16_t usPIT0 = ( uint16_t ) 0x40 ;
const uint32_t ulPIT_CONST = ( uint32_t ) 1193180UL ;
const uint16_t us8254_CTR0_MODE3 = ( uint16_t ) 0x36 ;
uint32_t ulOutput ;
2006-05-02 17:39:15 +08:00
/* Setup the 8245 to tick at the wanted frequency. */
portOUTPUT_BYTE ( usPIT_MODE , us8254_CTR0_MODE3 ) ;
ulOutput = ulPIT_CONST / ulTickRateHz ;
2013-12-29 22:06:04 +08:00
portOUTPUT_BYTE ( usPIT0 , ( uint16_t ) ( ulOutput & ( uint32_t ) 0xff ) ) ;
2006-05-02 17:39:15 +08:00
ulOutput > > = 8 ;
2013-12-29 22:06:04 +08:00
portOUTPUT_BYTE ( usPIT0 , ( uint16_t ) ( ulOutput & ( uint32_t ) 0xff ) ) ;
2006-05-02 17:39:15 +08:00
}
2006-05-28 16:17:56 +08:00
/*-----------------------------------------------------------*/
static void prvSetTickFrequencyDefault ( void )
{
2013-12-29 22:06:04 +08:00
const uint16_t usPIT_MODE = ( uint16_t ) 0x43 ;
const uint16_t usPIT0 = ( uint16_t ) 0x40 ;
const uint16_t us8254_CTR0_MODE3 = ( uint16_t ) 0x36 ;
2006-05-28 16:17:56 +08:00
portOUTPUT_BYTE ( usPIT_MODE , us8254_CTR0_MODE3 ) ;
portOUTPUT_BYTE ( usPIT0 , 0 ) ;
portOUTPUT_BYTE ( usPIT0 , 0 ) ;
}
2006-05-02 17:39:15 +08:00
/*lint +e950 */