2 FreeRTOS.org V4.7.1 - Copyright (C) 2003-2008 Richard Barry.
\r
4 This file is part of the FreeRTOS.org distribution.
\r
6 FreeRTOS.org is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 FreeRTOS.org is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with FreeRTOS.org; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
20 A special exception to the GPL can be applied should you wish to distribute
\r
21 a combined work that includes FreeRTOS.org, without being obliged to provide
\r
22 the source code for any proprietary components. See the licensing section
\r
23 of http://www.FreeRTOS.org for full details of how and when the exception
\r
26 ***************************************************************************
\r
28 Please ensure to read the configuration and relevant port sections of the
\r
29 online documentation.
\r
31 +++ http://www.FreeRTOS.org +++
\r
32 Documentation, latest information, license and contact details.
\r
34 +++ http://www.SafeRTOS.com +++
\r
35 A version that is certified for use in safety critical systems.
\r
37 +++ http://www.OpenRTOS.com +++
\r
38 Commercial support, development, porting, licensing and training services.
\r
40 ***************************************************************************
\r
43 #include "FreeRTOS.h"
\r
45 #include "mb91467d.h"
\r
47 /*-----------------------------------------------------------*/
\r
49 /* We require the address of the pxCurrentTCB variable, but don't want to know
\r
50 any details of its type. */
\r
51 typedef void tskTCB;
\r
52 extern volatile tskTCB * volatile pxCurrentTCB;
\r
54 /* Constants required to handle critical sections. */
\r
55 #define portNO_CRITICAL_NESTING ( ( unsigned portBASE_TYPE ) 0 )
\r
56 volatile unsigned portLONG ulCriticalNesting = 9999UL;
\r
58 /*-----------------------------------------------------------*/
\r
64 ORCCR #0x20 ;Switch to user stack
\r
65 ST RP,@-R15 ;Store RP
\r
66 STM0 (R7,R6,R5,R4,R3,R2,R1,R0) ;Store R7-R0
\r
67 STM1 (R14,R13,R12,R11,R10,R9,R8) ;Store R14-R8
\r
68 ST MDH, @-R15 ;Store MDH
\r
69 ST MDL, @-R15 ;Store MDL
\r
71 LDI #_ulCriticalNesting, R0 ;Get the address of the critical nesting counter
\r
72 LD @R0, R0 ;Get the value of the critical nesting counter
\r
73 ST R0, @-R15 ;Store the critical nesting value to the user stack.
\r
75 ANDCCR #0xDF ;Switch back to system stack
\r
76 LD @R15+,R0 ;Store PC to R0
\r
77 ORCCR #0x20 ;Switch to user stack
\r
78 ST R0,@-R15 ;Store PC to User stack
\r
80 ANDCCR #0xDF ;Switch back to system stack
\r
81 LD @R15+,R0 ;Store PS to R0
\r
82 ORCCR #0x20 ;Switch to user stack
\r
83 ST R0,@-R15 ;Store PS to User stack
\r
85 LDI #_pxCurrentTCB, R0 ;Get pxCurrentTCB address
\r
86 LD @R0, R0 ;Get the pxCurrentTCB->pxTopOfStack address
\r
87 ST R15,@R0 ;Store USP to pxCurrentTCB->pxTopOfStack
\r
89 ANDCCR #0xDF ;Switch back to system stack for the rest of tick ISR
\r
92 #macro RestoreContext
\r
93 LDI #_pxCurrentTCB, R0 ;Get pxCurrentTCB address
\r
94 LD @R0, R0 ;Get the pxCurrentTCB->pxTopOfStack address
\r
95 ORCCR #0x20 ;Switch to user stack
\r
96 LD @R0, R15 ;Restore USP from pxCurrentTCB->pxTopOfStack
\r
98 LD @R15+,R0 ;Store PS to R0
\r
99 ANDCCR #0xDF ;Switch to system stack
\r
100 ST R0,@-R15 ;Store PS to system stack
\r
102 ORCCR #0x20 ;Switch to user stack
\r
103 LD @R15+,R0 ;Store PC to R0
\r
104 ANDCCR #0xDF ;Switch to system stack
\r
105 ST R0,@-R15 ;Store PC to system stack
\r
107 ORCCR #0x20 ;Switch back to retreive the remaining context
\r
109 LDI #_ulCriticalNesting, R0 ;Get the address of the critical nesting counter
\r
110 LD @R15+, R1 ;Get the saved critical nesting value
\r
111 ST R1, @R0 ;Save the critical nesting value into the ulCriticalNesting variable
\r
113 LD @R15+, MDL ;Restore MDL
\r
114 LD @R15+, MDH ;Restore MDH
\r
115 LDM1 (R14,R13,R12,R11,R10,R9,R8) ;Restore R14-R8
\r
116 LDM0 (R7,R6,R5,R4,R3,R2,R1,R0) ;Restore R7-R0
\r
117 LD @R15+, RP ;Restore RP
\r
119 ANDCCR #0xDF ;Switch back to system stack for the rest of tick ISR
\r
123 /*-----------------------------------------------------------*/
\r
126 * Perform hardware setup to enable ticks from timer 1,
\r
128 static void prvSetupTimerInterrupt( void );
\r
129 /*-----------------------------------------------------------*/
\r
132 * Initialise the stack of a task to look exactly as if a call to
\r
133 * portSAVE_CONTEXT had been called.
\r
135 * See the header file portable.h.
\r
137 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
\r
139 /* Place a few bytes of known values on the bottom of the stack.
\r
140 This is just useful for debugging. */
\r
142 *pxTopOfStack = 0x11111111;
\r
144 *pxTopOfStack = 0x22222222;
\r
146 *pxTopOfStack = 0x33333333;
\r
149 /* This is a redundant push to the stack, it may be required if in some implentation of the compiler
\r
150 the parameter to the task is passed on to the stack rather than in R4 register*/
\r
151 *pxTopOfStack = (portSTACK_TYPE)(pvParameters);
\r
154 *pxTopOfStack = ( portSTACK_TYPE ) 0x00000000; /* RP */
\r
157 *pxTopOfStack = ( portSTACK_TYPE ) 0x00007777; /* R7 */
\r
159 *pxTopOfStack = ( portSTACK_TYPE ) 0x00006666; /* R6 */
\r
161 *pxTopOfStack = ( portSTACK_TYPE ) 0x00005555; /* R5 */
\r
164 /* In the current implemention of the compiler the first
\r
165 parameter to the task(or function) is passed via R4 parameter
\r
166 to the task, hennce the pvParameters pointer is copied in R4
\r
167 regsiter. See compiler manual section 4.6.2 for more information.*/
\r
168 *pxTopOfStack = ( portSTACK_TYPE ) (pvParameters); /* R4 */
\r
170 *pxTopOfStack = ( portSTACK_TYPE ) 0x00003333; /* R3 */
\r
172 *pxTopOfStack = ( portSTACK_TYPE ) 0x00002222; /* R2 */
\r
174 *pxTopOfStack = ( portSTACK_TYPE ) 0x00001111; /* R1 */
\r
176 *pxTopOfStack = ( portSTACK_TYPE ) 0x00000001; /* R0 */
\r
179 *pxTopOfStack = ( portSTACK_TYPE ) 0x0000EEEE; /* R14 */
\r
181 *pxTopOfStack = ( portSTACK_TYPE ) 0x0000DDDD; /* R13 */
\r
183 *pxTopOfStack = ( portSTACK_TYPE ) 0x0000CCCC; /* R12 */
\r
185 *pxTopOfStack = ( portSTACK_TYPE ) 0x0000BBBB; /* R11 */
\r
187 *pxTopOfStack = ( portSTACK_TYPE ) 0x0000AAAA; /* R10 */
\r
189 *pxTopOfStack = ( portSTACK_TYPE ) 0x00009999; /* R9 */
\r
191 *pxTopOfStack = ( portSTACK_TYPE ) 0x00008888; /* R8 */
\r
194 *pxTopOfStack = ( portSTACK_TYPE ) 0x11110000; /* MDH */
\r
196 *pxTopOfStack = ( portSTACK_TYPE ) 0x22220000; /* MDL */
\r
199 /* The task starts with its ulCriticalNesting variable set to 0, interrupts
\r
201 *pxTopOfStack = portNO_CRITICAL_NESTING;
\r
204 /* The start of the task code. */
\r
205 *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */
\r
208 /* PS - User Mode, USP, ILM=31, Interrupts enabled */
\r
209 *pxTopOfStack = ( portSTACK_TYPE ) 0x001F0030; /* PS */
\r
211 return pxTopOfStack;
\r
213 /*-----------------------------------------------------------*/
\r
215 portBASE_TYPE xPortStartScheduler( void )
\r
217 /* Setup the hardware to generate the tick. */
\r
218 prvSetupTimerInterrupt();
\r
220 /* Restore the context of the first task that is going to run. */
\r
225 /* Simulate a function call end as generated by the compiler. We will now
\r
226 jump to the start of the task the context of which we have just restored. */
\r
231 /* Should not get here. */
\r
234 /*-----------------------------------------------------------*/
\r
236 void vPortEndScheduler( void )
\r
238 /* Not implemented - unlikely to ever be required as there is nothing to
\r
241 /*-----------------------------------------------------------*/
\r
244 * Setup RLT0 to generate a tick interrupt.
\r
246 static void prvSetupTimerInterrupt( void )
\r
248 /* The peripheral clock divided by 32 is used by the timer. */
\r
249 const unsigned portSHORT usReloadValue = ( unsigned portSHORT ) ( ( ( configPER_CLOCK_HZ / configTICK_RATE_HZ ) / 32UL ) - 1UL );
\r
251 TMCSR0_CNTE=0; /* Count Disable */
\r
252 TMCSR0_CSL=0x2; /* CLKP/32 */
\r
253 TMCSR0_MOD=0; /* Software trigger */
\r
254 TMCSR0_RELD=1; /* Reload */
\r
256 TMCSR0_UF=0; /* Clear underflow flag */
\r
257 TMRLR0=usReloadValue;
\r
258 TMCSR0_INTE=1; /* Interrupt Enable */
\r
259 TMCSR0_CNTE=1; /* Count Enable */
\r
260 TMCSR0_TRG=1; /* Trigger */
\r
262 PORTEN = 0x3; /* Port Enable */
\r
264 /*-----------------------------------------------------------*/
\r
266 #if configUSE_PREEMPTION == 1
\r
269 * Tick ISR for preemptive scheduler. The tick count is incremented
\r
270 * after the context is saved. Then the context is switched if required,
\r
271 * at last the context of the task which is to be resume is restored.
\r
276 .global _ReloadTimer0_IRQHandler
\r
277 _ReloadTimer0_IRQHandler:
\r
279 ANDCCR #0xEF ;Disable Interrupts
\r
281 SaveContext ;Save context
\r
283 ORCCR #0x10 ;Re-enable Interrupts
\r
287 AND R1,@R0 ;Clear RLT0 interrupt flag
\r
289 CALL32 _vTaskIncrementTick,R12 ;Increment Tick
\r
291 CALL32 _vTaskSwitchContext,R12 ;Switch context if required
\r
293 ANDCCR #0xEF ;Disable Interrupts
\r
295 RestoreContext ;Restore context
\r
297 ORCCR #0x10 ;Re-enable Interrupts
\r
306 * Tick ISR for the cooperative scheduler. All this does is increment the
\r
307 * tick count. We don't need to switch context, this can only be done by
\r
308 * manual calls to taskYIELD();
\r
310 __interrupt void ReloadTimer0_IRQHandler( void )
\r
312 /* Clear RLT0 interrupt flag */
\r
314 vTaskIncrementTick();
\r
320 * Manual context switch. We can use a __nosavereg attribute as the context
\r
321 * would be saved by PortSAVE_CONTEXT(). The context is switched and then
\r
322 * the context of the new task is restored saved.
\r
326 .global _vPortYieldDelayed
\r
327 _vPortYieldDelayed:
\r
329 ANDCCR #0xEF ;Disable Interrupts
\r
331 SaveContext ;Save context
\r
333 ORCCR #0x10 ;Re-enable Interrupts
\r
336 BANDL #0x0E, @R0 ;Clear Delayed interrupt flag
\r
338 CALL32 _vTaskSwitchContext,R12 ;Switch context if required
\r
340 ANDCCR #0xEF ;Disable Interrupts
\r
342 RestoreContext ;Restore context
\r
344 ORCCR #0x10 ;Re-enable Interrupts
\r
351 * Manual context switch. We can use a __nosavereg attribute as the context
\r
352 * would be saved by PortSAVE_CONTEXT(). The context is switched and then
\r
353 * the context of the new task is restored saved.
\r
358 .global _vPortYield
\r
361 SaveContext ;Save context
\r
363 CALL32 _vTaskSwitchContext,R12 ;Switch context if required
\r
365 RestoreContext ;Restore context
\r
371 /*-----------------------------------------------------------*/
\r
373 void vPortEnterCritical( void )
\r
375 /* Disable interrupts */
\r
376 portDISABLE_INTERRUPTS();
\r
378 /* Now interrupts are disabled ulCriticalNesting can be accessed
\r
379 directly. Increment ulCriticalNesting to keep a count of how many times
\r
380 portENTER_CRITICAL() has been called. */
\r
381 ulCriticalNesting++;
\r
383 /*-----------------------------------------------------------*/
\r
385 void vPortExitCritical( void )
\r
387 if( ulCriticalNesting > portNO_CRITICAL_NESTING )
\r
389 ulCriticalNesting--;
\r
390 if( ulCriticalNesting == portNO_CRITICAL_NESTING )
\r
392 /* Enable all interrupt/exception. */
\r
393 portENABLE_INTERRUPTS();
\r
397 /*-----------------------------------------------------------*/
\r