]> begriffs open source - freertos/blob - portable/GCC/AVR32_UC3/port.c
Style: uncrustify
[freertos] / portable / GCC / AVR32_UC3 / port.c
1 /*This file has been prepared for Doxygen automatic documentation generation.*/\r
2 \r
3 /*! \file *********************************************************************\r
4  *\r
5  * \brief FreeRTOS port source for AVR32 UC3.\r
6  *\r
7  * - Compiler:           GNU GCC for AVR32\r
8  * - Supported devices:  All AVR32 devices can be used.\r
9  * - AppNote:\r
10  *\r
11  * \author               Atmel Corporation: http://www.atmel.com \n\r
12  *                       Support and FAQ: http://support.atmel.no/\r
13  *\r
14  *****************************************************************************/\r
15 \r
16 /*\r
17  * FreeRTOS Kernel V10.3.1\r
18  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
19  *\r
20  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
21  * this software and associated documentation files (the "Software"), to deal in\r
22  * the Software without restriction, including without limitation the rights to\r
23  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
24  * the Software, and to permit persons to whom the Software is furnished to do so,\r
25  * subject to the following conditions:\r
26  *\r
27  * The above copyright notice and this permission notice shall be included in all\r
28  * copies or substantial portions of the Software.\r
29  *\r
30  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
31  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
32  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
33  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
34  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
35  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
36  *\r
37  * http://www.FreeRTOS.org\r
38  * http://aws.amazon.com/freertos\r
39  *\r
40  */\r
41 \r
42 \r
43 /* Standard includes. */\r
44 #include <sys/cpu.h>\r
45 #include <sys/usart.h>\r
46 #include <malloc.h>\r
47 \r
48 /* Scheduler includes. */\r
49 #include "FreeRTOS.h"\r
50 #include "task.h"\r
51 \r
52 /* AVR32 UC3 includes. */\r
53 #include <avr32/io.h>\r
54 #include "gpio.h"\r
55 #if ( configTICK_USE_TC == 1 )\r
56     #include "tc.h"\r
57 #endif\r
58 \r
59 \r
60 /* Constants required to setup the task context. */\r
61 #define portINITIAL_SR             ( ( StackType_t ) 0x00400000 ) /* AVR32 : [M2:M0]=001 I1M=0 I0M=0, GM=0 */\r
62 #define portINSTRUCTION_SIZE       ( ( StackType_t ) 0 )\r
63 \r
64 /* Each task maintains its own critical nesting variable. */\r
65 #define portNO_CRITICAL_NESTING    ( ( uint32_t ) 0 )\r
66 volatile uint32_t ulCriticalNesting = 9999UL;\r
67 \r
68 #if ( configTICK_USE_TC == 0 )\r
69     static void prvScheduleNextTick( void );\r
70 #else\r
71     static void prvClearTcInt( void );\r
72 #endif\r
73 \r
74 /* Setup the timer to generate the tick interrupts. */\r
75 static void prvSetupTimerInterrupt( void );\r
76 \r
77 /*-----------------------------------------------------------*/\r
78 \r
79 /*\r
80  * Low-level initialization routine called during startup, before the main\r
81  * function.\r
82  * This version comes in replacement to the default one provided by Newlib.\r
83  * Newlib's _init_startup only calls init_exceptions, but Newlib's exception\r
84  * vectors are not compatible with the SCALL management in the current FreeRTOS\r
85  * port. More low-level initializations are besides added here.\r
86  */\r
87 void _init_startup( void )\r
88 {\r
89     /* Import the Exception Vector Base Address. */\r
90     extern void      _evba;\r
91 \r
92     #if configHEAP_INIT\r
93         extern void  __heap_start__;\r
94         extern void  __heap_end__;\r
95         BaseType_t * pxMem;\r
96     #endif\r
97 \r
98     /* Load the Exception Vector Base Address in the corresponding system register. */\r
99     Set_system_register( AVR32_EVBA, ( int ) &_evba );\r
100 \r
101     /* Enable exceptions. */\r
102     ENABLE_ALL_EXCEPTIONS();\r
103 \r
104     /* Initialize interrupt handling. */\r
105     INTC_init_interrupts();\r
106 \r
107     #if configHEAP_INIT\r
108         /* Initialize the heap used by malloc. */\r
109         for( pxMem = &__heap_start__; pxMem < ( BaseType_t * ) &__heap_end__; )\r
110         {\r
111             *pxMem++ = 0xA5A5A5A5;\r
112         }\r
113     #endif\r
114 \r
115     /* Give the used CPU clock frequency to Newlib, so it can work properly. */\r
116     set_cpu_hz( configCPU_CLOCK_HZ );\r
117 \r
118     /* Code section present if and only if the debug trace is activated. */\r
119     #if configDBG\r
120         {\r
121             static const gpio_map_t DBG_USART_GPIO_MAP =\r
122             {\r
123                 { configDBG_USART_RX_PIN, configDBG_USART_RX_FUNCTION },\r
124                 { configDBG_USART_TX_PIN, configDBG_USART_TX_FUNCTION }\r
125             };\r
126 \r
127             /* Initialize the USART used for the debug trace with the configured parameters. */\r
128             set_usart_base( ( void * ) configDBG_USART );\r
129             gpio_enable_module( DBG_USART_GPIO_MAP,\r
130                                 sizeof( DBG_USART_GPIO_MAP ) / sizeof( DBG_USART_GPIO_MAP[ 0 ] ) );\r
131             usart_init( configDBG_USART_BAUDRATE );\r
132         }\r
133     #endif /* if configDBG */\r
134 }\r
135 /*-----------------------------------------------------------*/\r
136 \r
137 /*\r
138  * malloc, realloc and free are meant to be called through respectively\r
139  * pvPortMalloc, pvPortRealloc and vPortFree.\r
140  * The latter functions call the former ones from within sections where tasks\r
141  * are suspended, so the latter functions are task-safe. __malloc_lock and\r
142  * __malloc_unlock use the same mechanism to also keep the former functions\r
143  * task-safe as they may be called directly from Newlib's functions.\r
144  * However, all these functions are interrupt-unsafe and SHALL THEREFORE NOT BE\r
145  * CALLED FROM WITHIN AN INTERRUPT, because __malloc_lock and __malloc_unlock do\r
146  * not call portENTER_CRITICAL and portEXIT_CRITICAL in order not to disable\r
147  * interrupts during memory allocation management as this may be a very time-\r
148  * consuming process.\r
149  */\r
150 \r
151 /*\r
152  * Lock routine called by Newlib on malloc / realloc / free entry to guarantee a\r
153  * safe section as memory allocation management uses global data.\r
154  * See the aforementioned details.\r
155  */\r
156 void __malloc_lock( struct _reent * ptr )\r
157 {\r
158     vTaskSuspendAll();\r
159 }\r
160 \r
161 /*\r
162  * Unlock routine called by Newlib on malloc / realloc / free exit to guarantee\r
163  * a safe section as memory allocation management uses global data.\r
164  * See the aforementioned details.\r
165  */\r
166 void __malloc_unlock( struct _reent * ptr )\r
167 {\r
168     xTaskResumeAll();\r
169 }\r
170 /*-----------------------------------------------------------*/\r
171 \r
172 /* Added as there is no such function in FreeRTOS. */\r
173 void * pvPortRealloc( void * pv,\r
174                       size_t xWantedSize )\r
175 {\r
176     void * pvReturn;\r
177 \r
178     vTaskSuspendAll();\r
179     {\r
180         pvReturn = realloc( pv, xWantedSize );\r
181     }\r
182     xTaskResumeAll();\r
183 \r
184     return pvReturn;\r
185 }\r
186 /*-----------------------------------------------------------*/\r
187 \r
188 /* The cooperative scheduler requires a normal IRQ service routine to\r
189  * simply increment the system tick. */\r
190 \r
191 /* The preemptive scheduler is defined as "naked" as the full context is saved\r
192  * on entry as part of the context switch. */\r
193 __attribute__( ( __naked__ ) ) static void vTick( void )\r
194 {\r
195     /* Save the context of the interrupted task. */\r
196     portSAVE_CONTEXT_OS_INT();\r
197 \r
198     #if ( configTICK_USE_TC == 1 )\r
199         /* Clear the interrupt flag. */\r
200         prvClearTcInt();\r
201     #else\r
202 \r
203         /* Schedule the COUNT&COMPARE match interrupt in (configCPU_CLOCK_HZ/configTICK_RATE_HZ)\r
204          * clock cycles from now. */\r
205         prvScheduleNextTick();\r
206     #endif\r
207 \r
208     /* Because FreeRTOS is not supposed to run with nested interrupts, put all OS\r
209      * calls in a critical section . */\r
210     portENTER_CRITICAL();\r
211     xTaskIncrementTick();\r
212     portEXIT_CRITICAL();\r
213 \r
214     /* Restore the context of the "elected task". */\r
215     portRESTORE_CONTEXT_OS_INT();\r
216 }\r
217 /*-----------------------------------------------------------*/\r
218 \r
219 __attribute__( ( __naked__ ) ) void SCALLYield( void )\r
220 {\r
221     /* Save the context of the interrupted task. */\r
222     portSAVE_CONTEXT_SCALL();\r
223     vTaskSwitchContext();\r
224     portRESTORE_CONTEXT_SCALL();\r
225 }\r
226 /*-----------------------------------------------------------*/\r
227 \r
228 /* The code generated by the GCC compiler uses the stack in different ways at\r
229  * different optimisation levels.  The interrupt flags can therefore not always\r
230  * be saved to the stack.  Instead the critical section nesting level is stored\r
231  * in a variable, which is then saved as part of the stack context. */\r
232 __attribute__( ( __noinline__ ) ) void vPortEnterCritical( void )\r
233 {\r
234     /* Disable interrupts */\r
235     portDISABLE_INTERRUPTS();\r
236 \r
237     /* Now interrupts are disabled ulCriticalNesting can be accessed\r
238      * directly.  Increment ulCriticalNesting to keep a count of how many times\r
239      * portENTER_CRITICAL() has been called. */\r
240     ulCriticalNesting++;\r
241 }\r
242 /*-----------------------------------------------------------*/\r
243 \r
244 __attribute__( ( __noinline__ ) ) void vPortExitCritical( void )\r
245 {\r
246     if( ulCriticalNesting > portNO_CRITICAL_NESTING )\r
247     {\r
248         ulCriticalNesting--;\r
249 \r
250         if( ulCriticalNesting == portNO_CRITICAL_NESTING )\r
251         {\r
252             /* Enable all interrupt/exception. */\r
253             portENABLE_INTERRUPTS();\r
254         }\r
255     }\r
256 }\r
257 /*-----------------------------------------------------------*/\r
258 \r
259 /*\r
260  * Initialise the stack of a task to look exactly as if a call to\r
261  * portSAVE_CONTEXT had been called.\r
262  *\r
263  * See header file for description.\r
264  */\r
265 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,\r
266                                      TaskFunction_t pxCode,\r
267                                      void * pvParameters )\r
268 {\r
269     /* Setup the initial stack of the task.  The stack is set exactly as\r
270      * expected by the portRESTORE_CONTEXT() macro. */\r
271 \r
272     /* When the task starts, it will expect to find the function parameter in R12. */\r
273     pxTopOfStack--;\r
274     *pxTopOfStack-- = ( StackType_t ) 0x08080808;                    /* R8 */\r
275     *pxTopOfStack-- = ( StackType_t ) 0x09090909;                    /* R9 */\r
276     *pxTopOfStack-- = ( StackType_t ) 0x0A0A0A0A;                    /* R10 */\r
277     *pxTopOfStack-- = ( StackType_t ) 0x0B0B0B0B;                    /* R11 */\r
278     *pxTopOfStack-- = ( StackType_t ) pvParameters;                  /* R12 */\r
279     *pxTopOfStack-- = ( StackType_t ) 0xDEADBEEF;                    /* R14/LR */\r
280     *pxTopOfStack-- = ( StackType_t ) pxCode + portINSTRUCTION_SIZE; /* R15/PC */\r
281     *pxTopOfStack-- = ( StackType_t ) portINITIAL_SR;                /* SR */\r
282     *pxTopOfStack-- = ( StackType_t ) 0xFF0000FF;                    /* R0 */\r
283     *pxTopOfStack-- = ( StackType_t ) 0x01010101;                    /* R1 */\r
284     *pxTopOfStack-- = ( StackType_t ) 0x02020202;                    /* R2 */\r
285     *pxTopOfStack-- = ( StackType_t ) 0x03030303;                    /* R3 */\r
286     *pxTopOfStack-- = ( StackType_t ) 0x04040404;                    /* R4 */\r
287     *pxTopOfStack-- = ( StackType_t ) 0x05050505;                    /* R5 */\r
288     *pxTopOfStack-- = ( StackType_t ) 0x06060606;                    /* R6 */\r
289     *pxTopOfStack-- = ( StackType_t ) 0x07070707;                    /* R7 */\r
290     *pxTopOfStack   = ( StackType_t ) portNO_CRITICAL_NESTING;       /* ulCriticalNesting */\r
291 \r
292     return pxTopOfStack;\r
293 }\r
294 /*-----------------------------------------------------------*/\r
295 \r
296 BaseType_t xPortStartScheduler( void )\r
297 {\r
298     /* Start the timer that generates the tick ISR.  Interrupts are disabled\r
299      * here already. */\r
300     prvSetupTimerInterrupt();\r
301 \r
302     /* Start the first task. */\r
303     portRESTORE_CONTEXT();\r
304 \r
305     /* Should not get here! */\r
306     return 0;\r
307 }\r
308 /*-----------------------------------------------------------*/\r
309 \r
310 void vPortEndScheduler( void )\r
311 {\r
312     /* It is unlikely that the AVR32 port will require this function as there\r
313      * is nothing to return to.  */\r
314 }\r
315 /*-----------------------------------------------------------*/\r
316 \r
317 /* Schedule the COUNT&COMPARE match interrupt in (configCPU_CLOCK_HZ/configTICK_RATE_HZ)\r
318  * clock cycles from now. */\r
319 #if ( configTICK_USE_TC == 0 )\r
320     static void prvScheduleFirstTick( void )\r
321     {\r
322         uint32_t lCycles;\r
323 \r
324         lCycles  = Get_system_register( AVR32_COUNT );\r
325         lCycles += ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );\r
326 \r
327         /* If lCycles ends up to be 0, make it 1 so that the COMPARE and exception */\r
328         /* generation feature does not get disabled. */\r
329         if( 0 == lCycles )\r
330         {\r
331             lCycles++;\r
332         }\r
333 \r
334         Set_system_register( AVR32_COMPARE, lCycles );\r
335     }\r
336 \r
337     __attribute__( ( __noinline__ ) ) static void prvScheduleNextTick( void )\r
338     {\r
339         uint32_t lCycles, lCount;\r
340 \r
341         lCycles  = Get_system_register( AVR32_COMPARE );\r
342         lCycles += ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );\r
343 \r
344         /* If lCycles ends up to be 0, make it 1 so that the COMPARE and exception */\r
345         /* generation feature does not get disabled. */\r
346         if( 0 == lCycles )\r
347         {\r
348             lCycles++;\r
349         }\r
350 \r
351         lCount   = Get_system_register( AVR32_COUNT );\r
352 \r
353         if( lCycles < lCount )\r
354         { /* We missed a tick, recover for the next. */\r
355             lCycles += ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );\r
356         }\r
357 \r
358         Set_system_register( AVR32_COMPARE, lCycles );\r
359     }\r
360 #else /* if ( configTICK_USE_TC == 0 ) */\r
361     __attribute__( ( __noinline__ ) ) static void prvClearTcInt( void )\r
362     {\r
363         AVR32_TC.channel[ configTICK_TC_CHANNEL ].sr;\r
364     }\r
365 #endif /* if ( configTICK_USE_TC == 0 ) */\r
366 /*-----------------------------------------------------------*/\r
367 \r
368 /* Setup the timer to generate the tick interrupts. */\r
369 static void prvSetupTimerInterrupt( void )\r
370 {\r
371     #if ( configTICK_USE_TC == 1 )\r
372         volatile avr32_tc_t * tc           = &AVR32_TC;\r
373 \r
374         /* Options for waveform genration. */\r
375         tc_waveform_opt_t     waveform_opt =\r
376         {\r
377             .channel = configTICK_TC_CHANNEL,              /* Channel selection. */\r
378 \r
379             .bswtrg  = TC_EVT_EFFECT_NOOP,                 /* Software trigger effect on TIOB. */\r
380             .beevt   = TC_EVT_EFFECT_NOOP,                 /* External event effect on TIOB. */\r
381             .bcpc    = TC_EVT_EFFECT_NOOP,                 /* RC compare effect on TIOB. */\r
382             .bcpb    = TC_EVT_EFFECT_NOOP,                 /* RB compare effect on TIOB. */\r
383 \r
384             .aswtrg  = TC_EVT_EFFECT_NOOP,                 /* Software trigger effect on TIOA. */\r
385             .aeevt   = TC_EVT_EFFECT_NOOP,                 /* External event effect on TIOA. */\r
386             .acpc    = TC_EVT_EFFECT_NOOP,                 /* RC compare effect on TIOA: toggle. */\r
387             .acpa    = TC_EVT_EFFECT_NOOP,                 /* RA compare effect on TIOA: toggle (other possibilities are none, set and clear). */\r
388 \r
389             .wavsel  = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER, /* Waveform selection: Up mode without automatic trigger on RC compare. */\r
390             .enetrg  = FALSE,                              /* External event trigger enable. */\r
391             .eevt    = 0,                                  /* External event selection. */\r
392             .eevtedg = TC_SEL_NO_EDGE,                     /* External event edge selection. */\r
393             .cpcdis  = FALSE,                              /* Counter disable when RC compare. */\r
394             .cpcstop = FALSE,                              /* Counter clock stopped with RC compare. */\r
395 \r
396             .burst   = FALSE,                              /* Burst signal selection. */\r
397             .clki    = FALSE,                              /* Clock inversion. */\r
398             .tcclks  = TC_CLOCK_SOURCE_TC2                 /* Internal source clock 2. */\r
399         };\r
400 \r
401         tc_interrupt_t        tc_interrupt =\r
402         {\r
403             .etrgs = 0,\r
404             .ldrbs = 0,\r
405             .ldras = 0,\r
406             .cpcs  = 1,\r
407             .cpbs  = 0,\r
408             .cpas  = 0,\r
409             .lovrs = 0,\r
410             .covfs = 0,\r
411         };\r
412     #endif /* if ( configTICK_USE_TC == 1 ) */\r
413 \r
414     /* Disable all interrupt/exception. */\r
415     portDISABLE_INTERRUPTS();\r
416 \r
417     /* Register the compare interrupt handler to the interrupt controller and\r
418      * enable the compare interrupt. */\r
419 \r
420     #if ( configTICK_USE_TC == 1 )\r
421         {\r
422             INTC_register_interrupt( &vTick, configTICK_TC_IRQ, INT0 );\r
423 \r
424             /* Initialize the timer/counter. */\r
425             tc_init_waveform( tc, &waveform_opt );\r
426 \r
427             /* Set the compare triggers.\r
428              * Remember TC counter is 16-bits, so counting second is not possible!\r
429              * That's why we configure it to count ms. */\r
430             tc_write_rc( tc, configTICK_TC_CHANNEL, ( configPBA_CLOCK_HZ / 4 ) / configTICK_RATE_HZ );\r
431 \r
432             tc_configure_interrupts( tc, configTICK_TC_CHANNEL, &tc_interrupt );\r
433 \r
434             /* Start the timer/counter. */\r
435             tc_start( tc, configTICK_TC_CHANNEL );\r
436         }\r
437     #else /* if ( configTICK_USE_TC == 1 ) */\r
438         {\r
439             INTC_register_interrupt( &vTick, AVR32_CORE_COMPARE_IRQ, INT0 );\r
440             prvScheduleFirstTick();\r
441         }\r
442     #endif /* if ( configTICK_USE_TC == 1 ) */\r
443 }\r