]> begriffs open source - freertos/blob - portable/GCC/AVR_AVRDx/port.c
[AUTO][RELEASE]: Bump file header version to "10.4.3 LTS Patch 3"
[freertos] / portable / GCC / AVR_AVRDx / port.c
1 /*
2  * FreeRTOS Kernel V10.4.3 LTS Patch 3
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software. If you wish to use our Amazon
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * https://www.FreeRTOS.org
24  * https://github.com/FreeRTOS
25  *
26  */
27
28 #include <stdlib.h>
29
30 #include <avr/interrupt.h>
31 #include "porthardware.h"
32 #include "FreeRTOS.h"
33 #include "task.h"
34
35 /*-----------------------------------------------------------
36 * Implementation of functions defined in portable.h for the AVR port.
37 *----------------------------------------------------------*/
38
39 /* Start tasks with interrupts enables. */
40 #define portFLAGS_INT_ENABLED    ( ( StackType_t ) 0x80 )
41
42 /*-----------------------------------------------------------*/
43
44 /* We require the address of the pxCurrentTCB variable, but don't want to know
45  * any details of its type. */
46 typedef void RTOS_TCB_t;
47 extern volatile RTOS_TCB_t * volatile pxCurrentTCB;
48
49 /*-----------------------------------------------------------*/
50
51 /*
52  * Macro to save all the general purpose registers, the save the stack pointer
53  * into the TCB.
54  *
55  * The first thing we do is save the flags then disable interrupts.  This is to
56  * guard our stack against having a context switch interrupt after we have already
57  * pushed the registers onto the stack - causing the 32 registers to be on the
58  * stack twice.
59  *
60  * r1 is set to zero as the compiler expects it to be thus, however some
61  * of the math routines make use of R1.
62  *
63  * The interrupts will have been disabled during the call to portSAVE_CONTEXT()
64  * so we need not worry about reading/writing to the stack pointer.
65  */
66
67 #define portSAVE_CONTEXT()                              \
68     asm volatile ( "push  r0                      \n\t" \
69                    "in    r0, __SREG__            \n\t" \
70                    "cli                           \n\t" \
71                    "push  r0                      \n\t" \
72                    "in    r0, __RAMPZ__           \n\t" \
73                    "push  r0                      \n\t" \
74                    "push  r1                      \n\t" \
75                    "clr   r1                      \n\t" \
76                    "push  r2                      \n\t" \
77                    "push  r3                      \n\t" \
78                    "push  r4                      \n\t" \
79                    "push  r5                      \n\t" \
80                    "push  r6                      \n\t" \
81                    "push  r7                      \n\t" \
82                    "push  r8                      \n\t" \
83                    "push  r9                      \n\t" \
84                    "push  r10                     \n\t" \
85                    "push  r11                     \n\t" \
86                    "push  r12                     \n\t" \
87                    "push  r13                     \n\t" \
88                    "push  r14                     \n\t" \
89                    "push  r15                     \n\t" \
90                    "push  r16                     \n\t" \
91                    "push  r17                     \n\t" \
92                    "push  r18                     \n\t" \
93                    "push  r19                     \n\t" \
94                    "push  r20                     \n\t" \
95                    "push  r21                     \n\t" \
96                    "push  r22                     \n\t" \
97                    "push  r23                     \n\t" \
98                    "push  r24                     \n\t" \
99                    "push  r25                     \n\t" \
100                    "push  r26                     \n\t" \
101                    "push  r27                     \n\t" \
102                    "push  r28                     \n\t" \
103                    "push  r29                     \n\t" \
104                    "push  r30                     \n\t" \
105                    "push  r31                     \n\t" \
106                    "lds   r26, pxCurrentTCB       \n\t" \
107                    "lds   r27, pxCurrentTCB + 1   \n\t" \
108                    "in    r0, __SP_L__            \n\t" \
109                    "st    x+, r0                  \n\t" \
110                    "in    r0, __SP_H__            \n\t" \
111                    "st    x+, r0                  \n\t" );
112
113 /*
114  * Opposite to portSAVE_CONTEXT().  Interrupts will have been disabled during
115  * the context save so we can write to the stack pointer.
116  */
117
118 #define portRESTORE_CONTEXT()                           \
119     asm volatile ( "lds   r26, pxCurrentTCB       \n\t" \
120                    "lds   r27, pxCurrentTCB + 1   \n\t" \
121                    "ld    r28, x+                 \n\t" \
122                    "out   __SP_L__, r28           \n\t" \
123                    "ld    r29, x+                 \n\t" \
124                    "out   __SP_H__, r29           \n\t" \
125                    "pop   r31                     \n\t" \
126                    "pop   r30                     \n\t" \
127                    "pop   r29                     \n\t" \
128                    "pop   r28                     \n\t" \
129                    "pop   r27                     \n\t" \
130                    "pop   r26                     \n\t" \
131                    "pop   r25                     \n\t" \
132                    "pop   r24                     \n\t" \
133                    "pop   r23                     \n\t" \
134                    "pop   r22                     \n\t" \
135                    "pop   r21                     \n\t" \
136                    "pop   r20                     \n\t" \
137                    "pop   r19                     \n\t" \
138                    "pop   r18                     \n\t" \
139                    "pop   r17                     \n\t" \
140                    "pop   r16                     \n\t" \
141                    "pop   r15                     \n\t" \
142                    "pop   r14                     \n\t" \
143                    "pop   r13                     \n\t" \
144                    "pop   r12                     \n\t" \
145                    "pop   r11                     \n\t" \
146                    "pop   r10                     \n\t" \
147                    "pop   r9                      \n\t" \
148                    "pop   r8                      \n\t" \
149                    "pop   r7                      \n\t" \
150                    "pop   r6                      \n\t" \
151                    "pop   r5                      \n\t" \
152                    "pop   r4                      \n\t" \
153                    "pop   r3                      \n\t" \
154                    "pop   r2                      \n\t" \
155                    "pop   r1                      \n\t" \
156                    "pop   r0                      \n\t" \
157                    "out   __RAMPZ__, r0           \n\t" \
158                    "pop   r0                      \n\t" \
159                    "out   __SREG__, r0            \n\t" \
160                    "pop   r0                      \n\t" );
161
162 /*-----------------------------------------------------------*/
163
164 /*
165  * Perform hardware setup to enable ticks from timer.
166  */
167 static void prvSetupTimerInterrupt( void );
168 /*-----------------------------------------------------------*/
169
170 /*
171  * See header file for description.
172  */
173 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
174                                      TaskFunction_t pxCode,
175                                      void * pvParameters )
176 {
177     uint16_t usAddress;
178
179     /*lint -e950 -e611 -e923 Lint doesn't like this much - but nothing I can do about it. */
180
181     /* Place a few bytes of known values on the bottom of the stack.
182      * This is just useful for debugging. Uncomment if needed. */
183     /* *pxTopOfStack = 0x11; */
184     /* pxTopOfStack--; */
185     /* *pxTopOfStack = 0x22; */
186     /* pxTopOfStack--; */
187     /* *pxTopOfStack = 0x33; */
188     /* pxTopOfStack--; */
189
190     /* The start of the task code will be popped off the stack last, so place
191      * it on first. */
192     usAddress = ( uint16_t ) pxCode;
193     *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
194     pxTopOfStack--;
195
196     usAddress >>= 8;
197     *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
198     pxTopOfStack--;
199
200     /* Next simulate the stack as if after a call to portSAVE_CONTEXT().
201     *  portSAVE_CONTEXT places the flags on the stack immediately after r0
202     *  to ensure the interrupts get disabled as soon as possible, and so ensuring
203     *  the stack use is minimal should a context switch interrupt occur. */
204     *pxTopOfStack = ( StackType_t ) 0x00; /* R0 */
205     pxTopOfStack--;
206     *pxTopOfStack = portFLAGS_INT_ENABLED;
207     pxTopOfStack--;
208     *pxTopOfStack = ( StackType_t ) 0x00; /* RAMPZ */
209     pxTopOfStack--;
210
211     /* Now the remaining registers.   The compiler expects R1 to be 0. */
212     *pxTopOfStack = ( StackType_t ) 0x00; /* R1 */
213
214     /* Leave R2 - R23 untouched */
215     pxTopOfStack -= 23;
216
217     /* Place the parameter on the stack in the expected location. */
218     usAddress = ( uint16_t ) pvParameters;
219     *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
220     pxTopOfStack--;
221
222     usAddress >>= 8;
223     *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
224
225     /* Leave register R26 - R31 untouched */
226     pxTopOfStack -= 7;
227
228     /*lint +e950 +e611 +e923 */
229
230     return pxTopOfStack;
231 }
232 /*-----------------------------------------------------------*/
233
234 BaseType_t xPortStartScheduler( void )
235 {
236     /* Setup the hardware to generate the tick. */
237     prvSetupTimerInterrupt();
238
239     /* Restore the context of the first task that is going to run. */
240     portRESTORE_CONTEXT();
241
242     /* Simulate a function call end as generated by the compiler.  We will now
243      * jump to the start of the task the context of which we have just restored. */
244     asm volatile ( "ret" );
245
246     /* Should not get here. */
247     return pdTRUE;
248 }
249 /*-----------------------------------------------------------*/
250
251 void vPortEndScheduler( void )
252 {
253     /* vPortEndScheduler is not implemented in this port. */
254 }
255 /*-----------------------------------------------------------*/
256
257 /*
258  * Manual context switch.  The first thing we do is save the registers so we
259  * can use a naked attribute.
260  */
261 void vPortYield( void ) __attribute__( ( naked ) );
262 void vPortYield( void )
263 {
264     portSAVE_CONTEXT();
265     vTaskSwitchContext();
266     portRESTORE_CONTEXT();
267     asm volatile ( "ret" );
268 }
269 /*-----------------------------------------------------------*/
270
271 /*
272  * Manual context switch callable from ISRs. The first thing
273  * we do is save the registers so we can use a naked attribute.
274  */
275 void vPortYieldFromISR( void ) __attribute__( ( naked ) );
276 void vPortYieldFromISR( void )
277 {
278     portSAVE_CONTEXT();
279     vTaskSwitchContext();
280     portRESTORE_CONTEXT();
281     asm volatile ( "reti" );
282 }
283 /*-----------------------------------------------------------*/
284
285 /*
286  * Context switch function used by the tick.  This must be identical to
287  * vPortYield() from the call to vTaskSwitchContext() onwards.  The only
288  * difference from vPortYield() is the tick count is incremented as the
289  * call comes from the tick ISR.
290  */
291 void vPortYieldFromTick( void ) __attribute__( ( naked ) );
292 void vPortYieldFromTick( void )
293 {
294     portSAVE_CONTEXT();
295
296     if( xTaskIncrementTick() != pdFALSE )
297     {
298         vTaskSwitchContext();
299     }
300
301     portRESTORE_CONTEXT();
302
303     asm volatile ( "reti" );
304 }
305 /*-----------------------------------------------------------*/
306
307 /*
308  * Setup timer to generate a tick interrupt.
309  */
310 static void prvSetupTimerInterrupt( void )
311 {
312     TICK_init();
313 }
314 /*-----------------------------------------------------------*/
315
316 #if configUSE_PREEMPTION == 1
317
318 /*
319  * Tick ISR for preemptive scheduler.  We can use a naked attribute as
320  * the context is saved at the start of vPortYieldFromTick().  The tick
321  * count is incremented after the context is saved.
322  */
323     ISR( TICK_INT_vect, ISR_NAKED )
324     {
325         /* Clear tick interrupt flag. */
326         CLR_INT( INT_FLAGS, INT_MASK );
327
328         vPortYieldFromTick();
329
330         asm volatile ( "reti" );
331     }
332 #else  /* if configUSE_PREEMPTION == 1 */
333
334 /*
335  * Tick ISR for the cooperative scheduler.  All this does is increment the
336  * tick count.  We don't need to switch context, this can only be done by
337  * manual calls to taskYIELD();
338  */
339     ISR( TICK_INT_vect )
340     {
341         /* Clear tick interrupt flag. */
342         INT_FLAGS = INT_MASK;
343         xTaskIncrementTick();
344     }
345 #endif /* if configUSE_PREEMPTION == 1 */