This file is part of SimpleRTOS2
/*============================================================================*/
/*
SimpleRTOS - Very simple RTOS for Microcontrollers - PIC32 port
v2.00 (2014-01-21)
isaacbavaresco@yahoo.com.br
*/
/*============================================================================*/
/*
Copyright (c) 2007-2014, Isaac Marino Bavaresco
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Neither the name of the author nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*============================================================================*/
#include <string.h>
#include "PortPIC24.h"
/*============================================================================*/
void TickHook( void );
/*============================================================================*/
static void Switch( void )
{
IFS0bits.T1IF = 0; /* clear the interrupt flag */
SystemTick++;
CheckDelayList();
/* The current task ran for at least one full time slice... */
if( AlreadySwitched == 0 && CurrentTask->Priority == HighestReadyPriority )
/* ... it doesn't deserve an additional time slice. */
ReadyTasks[HighestReadyPriority]
= ReadyTasks[HighestReadyPriority]->Next;
CurrentTask = ReadyTasks[HighestReadyPriority];
/*
The upcoming task will run from the very beginning of its time slice,
at the end of this slice it will be switched off.
*/
AlreadySwitched = 0;
TickHook();
}
/*============================================================================*/
void ContextInit( context_t *Context, unsigned char *Stack, unsigned long StackSize, void *Parameter, void (*TaskFunc)( void* ), unsigned int Priority )
{
memset( Context, 0x00, sizeof( context_t ));
unsigned long FuncAddress = (unsigned short)TaskFunc;
Context->W0 = (unsigned short)Parameter;
Context->W15 = (unsigned short)Stack;
Context->SR = 0x0000;
/*
The IPL bits must be zero for the interrupts to be enabled when the
task starts.
*/
Context->SR_IPL3_PC = (( 0 /*SR*/ << 8 ) & 0xff00 ) |
(( CORCON << 4 ) & 0x0080 ) |
(( FuncAddress >> 16 ) & 0x007f );
/*
The SFA bit must be zero on function entry because a call instrustion always
clears it.
*/
Context->PC_SFA = ( FuncAddress & 0xfffe ) | (( 0 /*CORCON*/ >> 2 ) & 0x0001 );
Context->SPLIM = (unsigned short)Stack + StackSize - 2;
Context->TBLPAG = TBLPAG;
/*
The RCOUNT register must be zero on function entry.
*/
Context->RCOUNT = 0;
Context->CORCON = CORCON;
#if defined __PIC24H__ || defined __PIC24F__ || defined __PIC24FK__
Context->PSVPAG = PSVPAG;
#elif defined __PIC24E__
Context->DSRPAG = DSRPAG;
Context->DSWPAG = DSWPAG;
#endif /* defined __PIC24H__ || defined __PIC24F__ || defined __PIC24FK__ */
Context->Priority = Priority;
Context->TDelay = 0;
Context->PreviousDelayedTask = 0;
Context->NextDelayedTask = 0;
Context->DelayList = 0;
#ifdef USE_SLICE_LENGTH
Context->SliceLength = 0;
#endif /* USE_SLICE_LENGTH */
#ifdef USE_PRIORITIES
Context->Priority = 0;
#endif /* USE_PRIORITIES */
Context->Previous = 0;
Context->Next = 0;
Context->List = 0;
}
/*============================================================================*/
void InitRTOS( context_t *ctxts, int Number )
{
unsigned int i;
/* No contexts to be initialized... The RTOS is useless.*/
if( ctxts == NULL || Number == 0 )
{
FreeContexts = NULL;
return;
}
CurrentTask = ctxts;
for( i = 0; i < MAX_PRIORITIES; i++ )
ReadyTasks[i] = NULL;
/*------------------------------------------------------------------------*/
/* Initialize all contexts and link them to the free contexts list.*/
FreeContexts = ctxts;
for( i = 0; i < Number - 1; i++, ctxts++ )
{
ctxts->Next = ctxts + 1;
ctxts->List = &FreeContexts;
}
ctxts->Next = NULL;
ctxts->List = &FreeContexts;
/*------------------------------------------------------------------------*/
}
/*============================================================================*/
static void __attribute__((naked)) SaveContext( void )
{
//--------------------------------------------------------------------------
asm volatile(
"push.w W1 \n"
"mov.w _CurrentTask,W1 \n"
"mov.w W0,[W1+0] \n"
"pop.w W0 \n"
"mov.w W0,[W1+2] \n"
"mov.w W2,[W1+4] \n"
"mov.w W3,[W1+6] \n"
"mov.w W4,[W1+8] \n"
"mov.w W5,[W1+10] \n"
"mov.w W6,[W1+12] \n"
"mov.w W7,[W1+14] \n"
"mov.w W8,[W1+16] \n"
"mov.w W9,[W1+18] \n"
"mov.w W10,[W1+20] \n"
"mov.w W11,[W1+22] \n"
"mov.w W12,[W1+24] \n"
"mov.w W13,[W1+26] \n"
"mov.w W14,[W1+28] \n"
"mov.w SR,W0 \n"
"mov.w W0,[W1+32] \n"
"mov.w [W15-6],W0 \n"
"mov.w W0,[W1+34] \n"
"mov.w [W15-8],W0 \n"
"mov.w W0,[W1+36] \n"
"sub.w W15,#8,W0 \n"
"mov.w W0,[W1+30] \n"
"mov.w SPLIM,W0 \n"
"mov.w W0,[W1+38] \n"
"mov.w TBLPAG,W0 \n"
"mov.w W0,[W1+40] \n"
"mov.w RCOUNT,W0 \n"
"mov.w W0,[W1+42] \n"
"mov.w CORCON,W0 \n"
"mov.w W0,[W1+44] \n"
#if defined __PIC24H__ || defined __PIC24F__ || defined __PIC24FK__
"mov.w PSVPAG,W0 \n"
"mov.w W0,[W1+46] \n"
#elif defined __PIC24E__
"mov.w DSRPAG,W0 \n"
"mov.w W0,[W1+46] \n"
"mov.w DSWPAG,W0 \n"
"mov.w W0,[W1+48] \n"
#endif /* defined __PIC24H__ || defined __PIC24F__ || defined __PIC24FK__ */
);
}
/*============================================================================*/
static void __attribute__((naked)) RestoreContext( void )
{
asm volatile(
"mov.w _CurrentTask,W1 \n"
"mov.w [W1+4],W2 \n"
"mov.w [W1+6],W3 \n"
"mov.w [W1+8],W4 \n"
"mov.w [W1+10],W5 \n"
"mov.w [W1+12],W6 \n"
"mov.w [W1+14],W7 \n"
"mov.w [W1+16],W8 \n"
"mov.w [W1+18],W9 \n"
"mov.w [W1+20],W10 \n"
"mov.w [W1+22],W11 \n"
"mov.w [W1+24],W12 \n"
"mov.w [W1+26],W13 \n"
"mov.w [W1+28],W14 \n"
"mov.w [W1+30],W15 \n"
"mov.w [W1+38],W0 \n"
"mov.w W0,SPLIM \n"
"mov.w [W1+36],W0 \n"
"push.w W0 \n"
"mov.w [W1+34],W0 \n"
"push.w W0 \n"
"mov.b [W1+33],W0 \n"
"mov.b WREG,0x0043 \n"
"mov.w [W1+40],W0 \n"
"mov.w W0,TBLPAG \n"
"mov.w [W1+42],W0 \n"
"mov.w W0,RCOUNT \n"
"mov.w [W1+44],W0 \n"
"mov.w W0,CORCON \n"
#if defined __PIC24H__ || defined __PIC24F__ || defined __PIC24FK__
"mov.w [W1+46],W0 \n"
"mov.w W0,PSVPAG \n"
#elif defined __PIC24E__
"mov.w [W1+46],W0 \n"
"mov.w W0,DSRPAG \n"
"mov.w [W1+48],W0 \n"
"mov.w W0,DSWPAG \n"
#endif /* defined __PIC24H__ || defined __PIC24F__ || defined __PIC24FK__ */
"mov.w [W1+0],W0 \n"
"mov.w [W1+2],W1 \n"
"retfie \n"
);
}
/*============================================================================*/
void __attribute__((noreturn)) StartRTOS( tickcount_t TickPeriod )
{
SystemTick = 0;
CurrentTask = ReadyTasks[HighestReadyPriority];
PR1 = TickPeriod;
TMR1 = 0;
T1CON = 0x8000;
IFS0bits.T1IF = 0;
IEC0bits.T1IE = 1;
SR |= 0x00e0;
INTCON1 = 0x0000;
INTCON2 = 0x8000;
RestoreContext();
while( 1 )
{}
}
/*============================================================================*/
void __attribute__((interrupt,naked,auto_psv)) _T1Interrupt( void )
{
//--------------------------------------------------------------------------
SaveContext();
Switch();
/*
Doing it this way to save stack and also because some dsPICs and PIC24 execute
'bra' and 'goto' faster than 'call' or 'rcall'. We are not returnig from here
anyway.
*/
asm volatile(
"bra _RestoreContext \n"
);
//--------------------------------------------------------------------------
}
/*============================================================================*/
#if defined __DEBUG
void T2Handler( void );
void __attribute__((interrupt,naked,auto_psv)) _T2Interrupt( void )
{
//--------------------------------------------------------------------------
SaveContext();
T2Handler();
/*
Doing it this way to save stack and also because some dsPICs and PIC24 execute
'bra' and 'goto' faster than 'call' or 'rcall'. We are not returnig from here
anyway.
*/
asm volatile(
"bra _RestoreContext \n"
);
//--------------------------------------------------------------------------
}
#endif /* defined __DEBUG */
/*============================================================================*/
void __attribute__((naked)) ForceYield( void )
{
//--------------------------------------------------------------------------
/*
Transform the return address to a form suitable for
a 'retfie' instruction.
*/
asm volatile(
"mov.b SR,WREG \n"
"mov.b W0,[W15-1] \n"
);
SaveContext();
CurrentTask = ReadyTasks[HighestReadyPriority];
/*
Doing it this way to save stack and also because some dsPICs and PIC24 execute
'bra' and 'goto' faster than 'call' or 'rcall'. We are not returnig from here
anyway.
*/
asm volatile(
"bra _RestoreContext \n"
);
//--------------------------------------------------------------------------
}
/*============================================================================*/
void __attribute__((naked)) HigherPriorityAwakened( void )
{
CurrentTask = ReadyTasks[HighestReadyPriority];
/*
Doing it this way to save stack and also because some dsPICs and PIC24 execute
'bra' and 'goto' faster than 'call' or 'rcall'. We are not returnig from here
anyway.
*/
asm volatile(
"bra _RestoreContext \n"
);
}
/*============================================================================*/