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