1
|
/*
|
2
|
FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.
|
3
|
|
4
|
This file is part of the FreeRTOS.org distribution.
|
5
|
|
6
|
FreeRTOS.org is free software; you can redistribute it and/or modify
|
7
|
it under the terms of the GNU General Public License as published by
|
8
|
the Free Software Foundation; either version 2 of the License, or
|
9
|
(at your option) any later version.
|
10
|
|
11
|
FreeRTOS.org is distributed in the hope that it will be useful,
|
12
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
GNU General Public License for more details.
|
15
|
|
16
|
You should have received a copy of the GNU General Public License
|
17
|
along with FreeRTOS.org; if not, write to the Free Software
|
18
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
|
20
|
A special exception to the GPL can be applied should you wish to distribute
|
21
|
a combined work that includes FreeRTOS.org, without being obliged to provide
|
22
|
the source code for any proprietary components. See the licensing section
|
23
|
of http://www.FreeRTOS.org for full details of how and when the exception
|
24
|
can be applied.
|
25
|
|
26
|
***************************************************************************
|
27
|
See http://www.FreeRTOS.org for documentation, latest information, license
|
28
|
and contact details. Please ensure to read the configuration and relevant
|
29
|
port sections of the online documentation.
|
30
|
|
31
|
Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
|
32
|
with commercial development and support options.
|
33
|
***************************************************************************
|
34
|
*/
|
35
|
|
36
|
|
37
|
/*-----------------------------------------------------------
|
38
|
* Components that can be compiled to either ARM or THUMB mode are
|
39
|
* contained in port.c The ISR routines, which can only be compiled
|
40
|
* to ARM mode, are contained in this file.
|
41
|
*----------------------------------------------------------*/
|
42
|
|
43
|
/*
|
44
|
Changes from V3.2.4
|
45
|
|
46
|
+ The assembler statements are now included in a single asm block rather
|
47
|
than each line having its own asm block.
|
48
|
*/
|
49
|
|
50
|
/* Scheduler includes. */
|
51
|
#include "FreeRTOS.h"
|
52
|
#include "task.h"
|
53
|
|
54
|
#include "AT91SAM7.h"
|
55
|
|
56
|
/* Constants required to handle interrupts. */
|
57
|
#define portTIMER_MATCH_ISR_BIT ( ( unsigned portCHAR ) 0x01 )
|
58
|
#define portCLEAR_VIC_INTERRUPT ( ( unsigned portLONG ) 0 )
|
59
|
|
60
|
/* Constants required to handle critical sections. */
|
61
|
#define portNO_CRITICAL_NESTING ( ( unsigned portLONG ) 0 )
|
62
|
volatile unsigned portLONG ulCriticalNesting = 9999UL;
|
63
|
|
64
|
/*-----------------------------------------------------------*/
|
65
|
|
66
|
/* ISR to handle manual context switches (from a call to taskYIELD()). */
|
67
|
void vPortYieldProcessor (void) __attribute__ ((interrupt ("SWI"), naked));
|
68
|
|
69
|
/*
|
70
|
* The scheduler can only be started from ARM mode, hence the inclusion of this
|
71
|
* function here.
|
72
|
*/
|
73
|
void vPortISRStartFirstTask (void);
|
74
|
/*-----------------------------------------------------------*/
|
75
|
|
76
|
void
|
77
|
vPortISRStartFirstTask (void)
|
78
|
{
|
79
|
/* Simply start the scheduler. This is included here as it can only be
|
80
|
called from ARM mode. */
|
81
|
portRESTORE_CONTEXT ();
|
82
|
}
|
83
|
|
84
|
/*-----------------------------------------------------------*/
|
85
|
|
86
|
/*
|
87
|
* Called by portYIELD() or taskYIELD() to manually force a context switch.
|
88
|
*
|
89
|
* When a context switch is performed from the task level the saved task
|
90
|
* context is made to look as if it occurred from within the tick ISR. This
|
91
|
* way the same restore context function can be used when restoring the context
|
92
|
* saved from the ISR or that saved from a call to vPortYieldProcessor.
|
93
|
*/
|
94
|
void
|
95
|
vPortYieldProcessor (void)
|
96
|
{
|
97
|
/* Within an IRQ ISR the link register has an offset from the true return
|
98
|
address, but an SWI ISR does not. Add the offset manually so the same
|
99
|
ISR return code can be used in both cases. */
|
100
|
asm volatile ("ADD LR, LR, #4");
|
101
|
|
102
|
/* Perform the context switch. First save the context of the current task. */
|
103
|
portSAVE_CONTEXT ();
|
104
|
|
105
|
/* Find the highest priority task that is ready to run. */
|
106
|
vTaskSwitchContext ();
|
107
|
|
108
|
/* Restore the context of the new task. */
|
109
|
portRESTORE_CONTEXT ();
|
110
|
}
|
111
|
|
112
|
/*-----------------------------------------------------------*/
|
113
|
|
114
|
/*
|
115
|
* The ISR used for the scheduler tick depends on whether the cooperative or
|
116
|
* the preemptive scheduler is being used.
|
117
|
*/
|
118
|
|
119
|
#if configUSE_PREEMPTION == 0
|
120
|
|
121
|
/* The cooperative scheduler requires a normal IRQ service routine to
|
122
|
simply increment the system tick. */
|
123
|
void vNonPreemptiveTick (void) __attribute__ ((interrupt ("IRQ")));
|
124
|
void
|
125
|
vNonPreemptiveTick (void)
|
126
|
{
|
127
|
unsigned portLONG ulDummy;
|
128
|
|
129
|
/* Increment the tick count - which may wake some tasks but as the
|
130
|
preemptive scheduler is not being used any woken task is not given
|
131
|
processor time no matter what its priority. */
|
132
|
vTaskIncrementTick ();
|
133
|
|
134
|
/* Clear the PIT interrupt. */
|
135
|
ulDummy = AT91C_BASE_PITC->PITC_PIVR;
|
136
|
|
137
|
/* End the interrupt in the AIC. */
|
138
|
AT91C_BASE_AIC->AIC_EOICR = ulDummy;
|
139
|
}
|
140
|
|
141
|
#else
|
142
|
|
143
|
/* The preemptive scheduler is defined as "naked" as the full context is
|
144
|
saved on entry as part of the context switch. */
|
145
|
void vPreemptiveTick (void) __attribute__ ((naked));
|
146
|
void
|
147
|
vPreemptiveTick (void)
|
148
|
{
|
149
|
/* Save the context of the current task. */
|
150
|
portSAVE_CONTEXT ();
|
151
|
|
152
|
/* Increment the tick count - this may wake a task. */
|
153
|
vTaskIncrementTick ();
|
154
|
|
155
|
/* Find the highest priority task that is ready to run. */
|
156
|
vTaskSwitchContext ();
|
157
|
|
158
|
/* End the interrupt in the AIC. */
|
159
|
AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_PITC->PITC_PIVR;;
|
160
|
|
161
|
portRESTORE_CONTEXT ();
|
162
|
}
|
163
|
|
164
|
#endif
|
165
|
/*-----------------------------------------------------------*/
|
166
|
|
167
|
/*
|
168
|
* The interrupt management utilities can only be called from ARM mode. When
|
169
|
* THUMB_INTERWORK is defined the utilities are defined as functions here to
|
170
|
* ensure a switch to ARM mode. When THUMB_INTERWORK is not defined then
|
171
|
* the utilities are defined as macros in portmacro.h - as per other ports.
|
172
|
*/
|
173
|
void vPortDisableInterruptsFromThumb (void) __attribute__ ((naked));
|
174
|
void vPortEnableInterruptsFromThumb (void) __attribute__ ((naked));
|
175
|
|
176
|
void
|
177
|
vPortDisableInterruptsFromThumb (void)
|
178
|
{
|
179
|
asm volatile ("STMDB SP!, {R0} \n\t" /* Push R0. */
|
180
|
"MRS R0, CPSR \n\t" /* Get CPSR. */
|
181
|
"ORR R0, R0, #0x80 \n\t" /* Disable IRQ, don't disable FIQ. */
|
182
|
"MSR CPSR, R0 \n\t" /* Write back modified value. */
|
183
|
"LDMIA SP!, {R0} \n\t" /* Pop R0. */
|
184
|
"BX R14"); /* Return back to thumb. */
|
185
|
}
|
186
|
|
187
|
void
|
188
|
vPortEnableInterruptsFromThumb (void)
|
189
|
{
|
190
|
asm volatile ("STMDB SP!, {R0} \n\t" /* Push R0. */
|
191
|
"MRS R0, CPSR \n\t" /* Get CPSR. */
|
192
|
"BIC R0, R0, #0xC0 \n\t" /* Enable IRQ, FIQ. */
|
193
|
"MSR CPSR, R0 \n\t" /* Write back modified value. */
|
194
|
"LDMIA SP!, {R0} \n\t" /* Pop R0. */
|
195
|
"BX R14"); /* Return back to thumb. */
|
196
|
}
|
197
|
|
198
|
|
199
|
/* The code generated by the GCC compiler uses the stack in different ways at
|
200
|
different optimisation levels. The interrupt flags can therefore not always
|
201
|
be saved to the stack. Instead the critical section nesting level is stored
|
202
|
in a variable, which is then saved as part of the stack context. */
|
203
|
void
|
204
|
vPortEnterCritical (void)
|
205
|
{
|
206
|
/* Disable interrupts as per portDISABLE_INTERRUPTS(); */
|
207
|
asm volatile ("STMDB SP!, {R0} \n\t" /* Push R0. */
|
208
|
"MRS R0, CPSR \n\t" /* Get CPSR. */
|
209
|
"ORR R0, R0, #0x80 \n\t" /* Disable IRQ, don't disable FIQ. */
|
210
|
"MSR CPSR, R0 \n\t" /* Write back modified value. */
|
211
|
"LDMIA SP!, {R0}"); /* Pop R0. */
|
212
|
#ifdef configDEBUG_CRITICAL_TIMING
|
213
|
*AT91C_PIOA_CODR = configDEBUG_CRITICAL_TIMING;
|
214
|
#endif
|
215
|
/* Now interrupts are disabled ulCriticalNesting can be accessed
|
216
|
directly. Increment ulCriticalNesting to keep a count of how many times
|
217
|
portENTER_CRITICAL() has been called. */
|
218
|
ulCriticalNesting++;
|
219
|
}
|
220
|
|
221
|
void
|
222
|
vPortExitCritical (void)
|
223
|
{
|
224
|
if (ulCriticalNesting > portNO_CRITICAL_NESTING)
|
225
|
{
|
226
|
/* Decrement the nesting count as we are leaving a critical section. */
|
227
|
ulCriticalNesting--;
|
228
|
|
229
|
/* If the nesting level has reached zero then interrupts should be
|
230
|
re-enabled. */
|
231
|
if (ulCriticalNesting == portNO_CRITICAL_NESTING)
|
232
|
{
|
233
|
#ifdef configDEBUG_CRITICAL_TIMING
|
234
|
*AT91C_PIOA_SODR = configDEBUG_CRITICAL_TIMING;
|
235
|
#endif
|
236
|
/* Enable interrupts as per portEXIT_CRITICAL(). */
|
237
|
asm volatile ("STMDB SP!, {R0} \n\t" /* Push R0. */
|
238
|
"MRS R0, CPSR \n\t" /* Get CPSR. */
|
239
|
"BIC R0, R0, #0xC0 \n\t" /* Enable IRQ, FIQ. */
|
240
|
"MSR CPSR, R0 \n\t" /* Write back modified value. */
|
241
|
"LDMIA SP!, {R0}"); /* Pop R0. */
|
242
|
}
|
243
|
}
|
244
|
}
|