|
|
|
/*
|
|
|
|
FreeRTOS V7.5.0 - Copyright (C) 2013 Real Time Engineers Ltd.
|
|
|
|
|
|
|
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
|
|
|
|
|
|
|
***************************************************************************
|
|
|
|
* *
|
|
|
|
* FreeRTOS provides completely free yet professionally developed, *
|
|
|
|
* robust, strictly quality controlled, supported, and cross *
|
|
|
|
* platform software that has become a de facto standard. *
|
|
|
|
* *
|
|
|
|
* Help yourself get started quickly and support the FreeRTOS *
|
|
|
|
* project by purchasing a FreeRTOS tutorial book, reference *
|
|
|
|
* manual, or both from: http://www.FreeRTOS.org/Documentation *
|
|
|
|
* *
|
|
|
|
* Thank you! *
|
|
|
|
* *
|
|
|
|
***************************************************************************
|
|
|
|
|
|
|
|
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. Full license text is available from the following
|
|
|
|
link: http://www.freertos.org/a00114.html
|
|
|
|
|
|
|
|
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, books, training, latest versions,
|
|
|
|
license and Real Time Engineers Ltd. contact details.
|
|
|
|
|
|
|
|
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
|
|
|
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
|
|
|
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
|
|
|
|
|
|
|
http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
|
|
|
|
Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
|
|
|
|
licenses offer ticketed support, indemnification and middleware.
|
|
|
|
|
|
|
|
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
|
|
|
engineered and independently SIL3 certified version for use in safety and
|
|
|
|
mission critical applications that require provable dependability.
|
|
|
|
|
|
|
|
1 tab == 4 spaces!
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------
|
|
|
|
* Implementation of functions defined in portable.h for the PIC32MX port.
|
|
|
|
*----------------------------------------------------------*/
|
|
|
|
|
|
|
|
#ifndef __XC
|
|
|
|
#error This port is designed to work with XC32. Please update your C compiler version.
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Scheduler include files. */
|
|
|
|
#include "FreeRTOS.h"
|
|
|
|
#include "task.h"
|
|
|
|
|
|
|
|
/* Hardware specifics. */
|
|
|
|
#define portTIMER_PRESCALE 8
|
|
|
|
#define portPRESCALE_BITS 1
|
|
|
|
|
|
|
|
/* Bits within various registers. */
|
|
|
|
#define portIE_BIT ( 0x00000001 )
|
|
|
|
#define portEXL_BIT ( 0x00000002 )
|
|
|
|
|
|
|
|
/* Bits within the CAUSE register. */
|
|
|
|
#define portCORE_SW_0 ( 0x00000100 )
|
|
|
|
#define portCORE_SW_1 ( 0x00000200 )
|
|
|
|
|
|
|
|
/* The EXL bit is set to ensure interrupts do not occur while the context of
|
|
|
|
the first task is being restored. */
|
|
|
|
#define portINITIAL_SR ( portIE_BIT | portEXL_BIT )
|
|
|
|
|
|
|
|
#ifndef configTICK_INTERRUPT_VECTOR
|
|
|
|
#define configTICK_INTERRUPT_VECTOR _TIMER_1_VECTOR
|
|
|
|
#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;
|
|
|
|
|
|
|
|
/* 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 ] );
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Place the prototype here to ensure the interrupt vector is correctly installed.
|
|
|
|
* Note that because the interrupt is written in assembly, the IPL setting in the
|
|
|
|
* following line of code has no effect. The interrupt priority is set by the
|
|
|
|
* call to ConfigIntTimer1() in vApplicationSetupTickTimerInterrupt().
|
|
|
|
*/
|
|
|
|
extern void __attribute__( (interrupt(ipl1), vector( configTICK_INTERRUPT_VECTOR ))) vPortTickInterruptHandler( void );
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The software interrupt handler that performs the yield. Note that, because
|
|
|
|
* the interrupt is written in assembly, the IPL setting in the following line of
|
|
|
|
* code has no effect. The interrupt priority is set by the call to
|
|
|
|
* mConfigIntCoreSW0() in xPortStartScheduler().
|
|
|
|
*/
|
|
|
|
void __attribute__( (interrupt(ipl1), vector(_CORE_SOFTWARE_0_VECTOR))) vPortYieldISR( void );
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See header file for description.
|
|
|
|
*/
|
|
|
|
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
|
|
|
|
{
|
|
|
|
/* Ensure byte alignment is maintained when leaving this function. */
|
|
|
|
pxTopOfStack--;
|
|
|
|
|
|
|
|
*pxTopOfStack = (portSTACK_TYPE) 0xDEADBEEF;
|
|
|
|
pxTopOfStack--;
|
|
|
|
|
|
|
|
*pxTopOfStack = (portSTACK_TYPE) 0x12345678; /* Word to which the stack pointer will be left pointing after context restore. */
|
|
|
|
pxTopOfStack--;
|
|
|
|
|
|
|
|
*pxTopOfStack = (portSTACK_TYPE) _CP0_GET_CAUSE();
|
|
|
|
pxTopOfStack--;
|
|
|
|
|
|
|
|
*pxTopOfStack = (portSTACK_TYPE) portINITIAL_SR; /* CP0_STATUS */
|
|
|
|
pxTopOfStack--;
|
|
|
|
|
|
|
|
*pxTopOfStack = (portSTACK_TYPE) pxCode; /* CP0_EPC */
|
|
|
|
pxTopOfStack--;
|
|
|
|
|
|
|
|
*pxTopOfStack = (portSTACK_TYPE) NULL; /* ra */
|
|
|
|
pxTopOfStack -= 15;
|
|
|
|
|
|
|
|
*pxTopOfStack = (portSTACK_TYPE) pvParameters; /* Parameters to pass in */
|
|
|
|
pxTopOfStack -= 14;
|
|
|
|
|
|
|
|
*pxTopOfStack = (portSTACK_TYPE) 0x00000000; /* critical nesting level - no longer used. */
|
|
|
|
pxTopOfStack--;
|
|
|
|
|
|
|
|
return pxTopOfStack;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* timer by redefining this implementation. If a different timer is used then
|
|
|
|
* configTICK_INTERRUPT_VECTOR must also be defined in FreeRTOSConfig.h to
|
|
|
|
* ensure the RTOS provided tick interrupt handler is installed on the correct
|
|
|
|
* vector number. When Timer 1 is used the vector number is defined as
|
|
|
|
* _TIMER_1_VECTOR.
|
|
|
|
*/
|
|
|
|
__attribute__(( weak )) void vApplicationSetupTickTimerInterrupt( void )
|
|
|
|
{
|
|
|
|
const unsigned long ulCompareMatch = ( (configPERIPHERAL_CLOCK_HZ / portTIMER_PRESCALE) / configTICK_RATE_HZ ) - 1;
|
|
|
|
|
|
|
|
T1CON = 0x0000;
|
|
|
|
T1CONbits.TCKPS = portPRESCALE_BITS;
|
|
|
|
PR1 = ulCompareMatch;
|
|
|
|
IPC1bits.T1IP = configKERNEL_INTERRUPT_PRIORITY;
|
|
|
|
|
|
|
|
/* Clear the interrupt as a starting condition. */
|
|
|
|
IFS0bits.T1IF = 0;
|
|
|
|
|
|
|
|
/* Enable the interrupt. */
|
|
|
|
IEC0bits.T1IE = 1;
|
|
|
|
|
|
|
|
/* Start the timer. */
|
|
|
|
T1CONbits.TON = 1;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
void vPortEndScheduler(void)
|
|
|
|
{
|
|
|
|
/* It is unlikely that the scheduler for the PIC port will get stopped
|
|
|
|
once running. If required disable the tick interrupt here, then return
|
|
|
|
to xPortStartScheduler(). */
|
|
|
|
for( ;; );
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
portBASE_TYPE xPortStartScheduler( void )
|
|
|
|
{
|
|
|
|
extern void vPortStartFirstTask( void );
|
|
|
|
extern void *pxCurrentTCB;
|
|
|
|
|
|
|
|
/* Clear the software interrupt flag. */
|
|
|
|
IFS0CLR = _IFS0_CS0IF_MASK;
|
|
|
|
|
|
|
|
/* Set software timer priority. */
|
|
|
|
IPC0CLR = _IPC0_CS0IP_MASK;
|
|
|
|
IPC0SET = ( configKERNEL_INTERRUPT_PRIORITY << _IPC0_CS0IP_POSITION );
|
|
|
|
|
|
|
|
/* Enable software interrupt. */
|
|
|
|
IEC0CLR = _IEC0_CS0IE_MASK;
|
|
|
|
IEC0SET = 1 << _IEC0_CS0IE_POSITION;
|
|
|
|
|
|
|
|
/* Setup the timer to generate the tick. Interrupts will have been
|
|
|
|
disabled by the time we get here. */
|
|
|
|
vApplicationSetupTickTimerInterrupt();
|
|
|
|
|
|
|
|
/* Kick off the highest priority task that has been created so far.
|
|
|
|
Its stack location is loaded into uxSavedTaskStackPointer. */
|
|
|
|
uxSavedTaskStackPointer = *( unsigned portBASE_TYPE * ) pxCurrentTCB;
|
|
|
|
vPortStartFirstTask();
|
|
|
|
|
|
|
|
/* Should never get here as the tasks will now be executing. */
|
|
|
|
return pdFALSE;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
void vPortIncrementTick( void )
|
|
|
|
{
|
|
|
|
unsigned portBASE_TYPE uxSavedStatus;
|
|
|
|
|
|
|
|
uxSavedStatus = uxPortSetInterruptMaskFromISR();
|
|
|
|
{
|
|
|
|
if( xTaskIncrementTick() != pdFALSE )
|
|
|
|
{
|
|
|
|
/* Pend a context switch. */
|
|
|
|
_CP0_BIS_CAUSE( portCORE_SW_0 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vPortClearInterruptMaskFromISR( uxSavedStatus );
|
|
|
|
|
|
|
|
/* Clear timer 1 interrupt. */
|
|
|
|
IFS0CLR = _IFS0_T1IF_MASK;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
unsigned portBASE_TYPE uxPortSetInterruptMaskFromISR( void )
|
|
|
|
{
|
|
|
|
unsigned portBASE_TYPE uxSavedStatusRegister;
|
|
|
|
|
|
|
|
asm volatile ( "di" );
|
|
|
|
uxSavedStatusRegister = _CP0_GET_STATUS() | 0x01;
|
|
|
|
/* This clears the IPL bits, then sets them to
|
|
|
|
configMAX_SYSCALL_INTERRUPT_PRIORITY. This function should not be called
|
|
|
|
from an interrupt that has a priority above
|
|
|
|
configMAX_SYSCALL_INTERRUPT_PRIORITY so, when used correctly, the action
|
|
|
|
can only result in the IPL being unchanged or raised, and therefore never
|
|
|
|
lowered. */
|
|
|
|
_CP0_SET_STATUS( ( ( uxSavedStatusRegister & ( ~portALL_IPL_BITS ) ) ) | ( configMAX_SYSCALL_INTERRUPT_PRIORITY << portIPL_SHIFT ) );
|
|
|
|
|
|
|
|
return uxSavedStatusRegister;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
void vPortClearInterruptMaskFromISR( unsigned portBASE_TYPE uxSavedStatusRegister )
|
|
|
|
{
|
|
|
|
_CP0_SET_STATUS( uxSavedStatusRegister );
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|