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
62 ORCCR #0x20 ;Switch to user stack
\r
63 ST RP,@-R15 ;Store RP
\r
64 STM0 (R7,R6,R5,R4,R3,R2,R1,R0) ;Store R7-R0
\r
65 STM1 (R14,R13,R12,R11,R10,R9,R8) ;Store R14-R8
\r
66 ST MDH, @-R15 ;Store MDH
\r
67 ST MDL, @-R15 ;Store MDL
\r
69 LDI #_ulCriticalNesting, R0 ;Get the address of the critical nesting counter
\r
70 LD @R0, R0 ;Get the value of the critical nesting counter
\r
71 ST R0, @-R15 ;Store the critical nesting value to the user stack.
\r
73 ANDCCR #0xDF ;Switch back to system stack
\r
74 LD @R15+,R0 ;Store PC to R0
\r
75 ORCCR #0x20 ;Switch to user stack
\r
76 ST R0,@-R15 ;Store PC to User stack
\r
78 ANDCCR #0xDF ;Switch back to system stack
\r
79 LD @R15+,R0 ;Store PS to R0
\r
80 ORCCR #0x20 ;Switch to user stack
\r
81 ST R0,@-R15 ;Store PS to User stack
\r
83 LDI #_pxCurrentTCB, R0 ;Get pxCurrentTCB address
\r
84 LD @R0, R0 ;Get the pxCurrentTCB->pxTopOfStack address
\r
85 ST R15,@R0 ;Store USP to pxCurrentTCB->pxTopOfStack
\r
87 ANDCCR #0xDF ;Switch back to system stack for the rest of tick ISR
\r
90 #macro RestoreContext
\r
91 LDI #_pxCurrentTCB, R0 ;Get pxCurrentTCB address
\r
92 LD @R0, R0 ;Get the pxCurrentTCB->pxTopOfStack address
\r
93 ORCCR #0x20 ;Switch to user stack
\r
94 LD @R0, R15 ;Restore USP from pxCurrentTCB->pxTopOfStack
\r
96 LD @R15+,R0 ;Store PS to R0
\r
97 ANDCCR #0xDF ;Switch to system stack
\r
98 ST R0,@-R15 ;Store PS to system stack
\r
100 ORCCR #0x20 ;Switch to user stack
\r
101 LD @R15+,R0 ;Store PC to R0
\r
102 ANDCCR #0xDF ;Switch to system stack
\r
103 ST R0,@-R15 ;Store PC to system stack
\r
105 ORCCR #0x20 ;Switch back to retrieve the remaining context
\r
107 LDI #_ulCriticalNesting, R0 ;Get the address of the critical nesting counter
\r
108 LD @R15+, R1 ;Get the saved critical nesting value
\r
109 ST R1, @R0 ;Save the critical nesting value into the ulCriticalNesting variable
\r
111 LD @R15+, MDL ;Restore MDL
\r
112 LD @R15+, MDH ;Restore MDH
\r
113 LDM1 (R14,R13,R12,R11,R10,R9,R8) ;Restore R14-R8
\r
114 LDM0 (R7,R6,R5,R4,R3,R2,R1,R0) ;Restore R7-R0
\r
115 LD @R15+, RP ;Restore RP
\r
117 ANDCCR #0xDF ;Switch back to system stack for the rest of tick ISR
\r
121 /*-----------------------------------------------------------*/
\r
124 * Perform hardware setup to enable ticks from timer 1,
\r
126 static void prvSetupTimerInterrupt( void );
\r
127 /*-----------------------------------------------------------*/
\r
130 * Initialise the stack of a task to look exactly as if a call to
\r
131 * portSAVE_CONTEXT had been called.
\r
133 * See the header file portable.h.
\r
135 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
\r
137 /* Place a few bytes of known values on the bottom of the stack.
\r
138 This is just useful for debugging. */
\r
140 *pxTopOfStack = 0x11111111;
\r
142 *pxTopOfStack = 0x22222222;
\r
144 *pxTopOfStack = 0x33333333;
\r
147 /* This is a redundant push to the stack, it may be required if
\r
148 in some implementations of the compiler the parameter to the task
\r
149 is passed on to the stack rather than in R4 register. */
\r
150 *pxTopOfStack = (portSTACK_TYPE)(pvParameters);
\r
153 *pxTopOfStack = ( portSTACK_TYPE ) 0x00000000; /* RP */
\r
155 *pxTopOfStack = ( portSTACK_TYPE ) 0x00007777; /* R7 */
\r
157 *pxTopOfStack = ( portSTACK_TYPE ) 0x00006666; /* R6 */
\r
159 *pxTopOfStack = ( portSTACK_TYPE ) 0x00005555; /* R5 */
\r
162 /* In the current implementation of the compiler the first
\r
163 parameter to the task (or function) is passed via R4 parameter
\r
164 to the task, hence the pvParameters pointer is copied into the R4
\r
165 register. See compiler manual section 4.6.2 for more information. */
\r
166 *pxTopOfStack = ( portSTACK_TYPE ) (pvParameters); /* R4 */
\r
168 *pxTopOfStack = ( portSTACK_TYPE ) 0x00003333; /* R3 */
\r
170 *pxTopOfStack = ( portSTACK_TYPE ) 0x00002222; /* R2 */
\r
172 *pxTopOfStack = ( portSTACK_TYPE ) 0x00001111; /* R1 */
\r
174 *pxTopOfStack = ( portSTACK_TYPE ) 0x00000001; /* R0 */
\r
176 *pxTopOfStack = ( portSTACK_TYPE ) 0x0000EEEE; /* R14 */
\r
178 *pxTopOfStack = ( portSTACK_TYPE ) 0x0000DDDD; /* R13 */
\r
180 *pxTopOfStack = ( portSTACK_TYPE ) 0x0000CCCC; /* R12 */
\r
182 *pxTopOfStack = ( portSTACK_TYPE ) 0x0000BBBB; /* R11 */
\r
184 *pxTopOfStack = ( portSTACK_TYPE ) 0x0000AAAA; /* R10 */
\r
186 *pxTopOfStack = ( portSTACK_TYPE ) 0x00009999; /* R9 */
\r
188 *pxTopOfStack = ( portSTACK_TYPE ) 0x00008888; /* R8 */
\r
190 *pxTopOfStack = ( portSTACK_TYPE ) 0x11110000; /* MDH */
\r
192 *pxTopOfStack = ( portSTACK_TYPE ) 0x22220000; /* MDL */
\r
195 /* The task starts with its ulCriticalNesting variable set to 0,
\r
196 interrupts being enabled. */
\r
197 *pxTopOfStack = portNO_CRITICAL_NESTING;
\r
200 /* The start of the task code. */
\r
201 *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */
\r
204 /* PS - User Mode, USP, ILM=31, Interrupts enabled */
\r
205 *pxTopOfStack = ( portSTACK_TYPE ) 0x001F0030; /* PS */
\r
207 return pxTopOfStack;
\r
209 /*-----------------------------------------------------------*/
\r
211 portBASE_TYPE xPortStartScheduler( void )
\r
213 /* Setup the hardware to generate the tick. */
\r
214 prvSetupTimerInterrupt();
\r
216 /* Restore the context of the first task that is going to run. */
\r
221 /* Simulate a function call end as generated by the compiler. We will now
\r
222 jump to the start of the task the context of which we have just restored. */
\r
225 /* Should not get here. */
\r
228 /*-----------------------------------------------------------*/
\r
230 void vPortEndScheduler( void )
\r
232 /* Not implemented - unlikely to ever be required as there is nothing to
\r
235 /*-----------------------------------------------------------*/
\r
237 static void prvSetupTimerInterrupt( void )
\r
239 /* The peripheral clock divided by 32 is used by the timer. */
\r
240 const unsigned portSHORT usReloadValue = ( unsigned portSHORT ) ( ( ( configPER_CLOCK_HZ / configTICK_RATE_HZ ) / 32UL ) - 1UL );
\r
242 /* Setup RLT0 to generate a tick interrupt. */
\r
244 TMCSR0_CNTE = 0; /* Count Disable */
\r
245 TMCSR0_CSL = 0x2; /* CLKP/32 */
\r
246 TMCSR0_MOD = 0; /* Software trigger */
\r
247 TMCSR0_RELD = 1; /* Reload */
\r
249 TMCSR0_UF = 0; /* Clear underflow flag */
\r
250 TMRLR0 = usReloadValue;
\r
251 TMCSR0_INTE = 1; /* Interrupt Enable */
\r
252 TMCSR0_CNTE = 1; /* Count Enable */
\r
253 TMCSR0_TRG = 1; /* Trigger */
\r
255 PORTEN = 0x3; /* Port Enable */
\r
257 /*-----------------------------------------------------------*/
\r
259 #if configUSE_PREEMPTION == 1
\r
262 * Tick ISR for preemptive scheduler. The tick count is incremented
\r
263 * after the context is saved. Then the context is switched if required,
\r
264 * and last the context of the task which is to be resumed is restored.
\r
269 .global _ReloadTimer0_IRQHandler
\r
270 _ReloadTimer0_IRQHandler:
\r
272 ANDCCR #0xEF ;Disable Interrupts
\r
273 SaveContext ;Save context
\r
274 ORCCR #0x10 ;Re-enable Interrupts
\r
278 AND R1,@R0 ;Clear RLT0 interrupt flag
\r
280 CALL32 _vTaskIncrementTick,R12 ;Increment Tick
\r
281 CALL32 _vTaskSwitchContext,R12 ;Switch context if required
\r
283 ANDCCR #0xEF ;Disable Interrupts
\r
284 RestoreContext ;Restore context
\r
285 ORCCR #0x10 ;Re-enable Interrupts
\r
294 * Tick ISR for the cooperative scheduler. All this does is increment the
\r
295 * tick count. We don't need to switch context, this can only be done by
\r
296 * manual calls to taskYIELD();
\r
298 __interrupt void ReloadTimer0_IRQHandler( void )
\r
300 /* Clear RLT0 interrupt flag */
\r
302 vTaskIncrementTick();
\r
308 * Manual context switch. We can use a __nosavereg attribute as the context
\r
309 * would be saved by PortSAVE_CONTEXT(). The context is switched and then
\r
310 * the context of the new task is restored saved.
\r
314 .global _vPortYieldDelayed
\r
315 _vPortYieldDelayed:
\r
317 ANDCCR #0xEF ;Disable Interrupts
\r
318 SaveContext ;Save context
\r
319 ORCCR #0x10 ;Re-enable Interrupts
\r
322 BANDL #0x0E, @R0 ;Clear Delayed interrupt flag
\r
324 CALL32 _vTaskSwitchContext,R12 ;Switch context if required
\r
326 ANDCCR #0xEF ;Disable Interrupts
\r
327 RestoreContext ;Restore context
\r
328 ORCCR #0x10 ;Re-enable Interrupts
\r
333 /*-----------------------------------------------------------*/
\r
336 * Manual context switch. We can use a __nosavereg attribute as the context
\r
337 * would be saved by PortSAVE_CONTEXT(). The context is switched and then
\r
338 * the context of the new task is restored saved.
\r
342 .global _vPortYield
\r
345 SaveContext ;Save context
\r
346 CALL32 _vTaskSwitchContext,R12 ;Switch context if required
\r
347 RestoreContext ;Restore context
\r
352 /*-----------------------------------------------------------*/
\r
354 void vPortEnterCritical( void )
\r
356 /* Disable interrupts */
\r
357 portDISABLE_INTERRUPTS();
\r
359 /* Now interrupts are disabled ulCriticalNesting can be accessed
\r
360 directly. Increment ulCriticalNesting to keep a count of how many times
\r
361 portENTER_CRITICAL() has been called. */
\r
362 ulCriticalNesting++;
\r
364 /*-----------------------------------------------------------*/
\r
366 void vPortExitCritical( void )
\r
368 if( ulCriticalNesting > portNO_CRITICAL_NESTING )
\r
370 ulCriticalNesting--;
\r
371 if( ulCriticalNesting == portNO_CRITICAL_NESTING )
\r
373 /* Enable all interrupt/exception. */
\r
374 portENABLE_INTERRUPTS();
\r
378 /*-----------------------------------------------------------*/
\r