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: GNU GCC for AVR32
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 /* Standard includes. */
74 #include <sys/cpu.h>
75 #include <sys/usart.h>
76 #include <malloc.h>
77
78 /* Scheduler includes. */
79 #include "FreeRTOS.h"
80 #include "task.h"
81
82 /* AVR32 UC3 includes. */
83 #include <avr32/io.h>
84 #include "gpio.h"
85 #if ( configTICK_USE_TC == 1 )
86 #include "tc.h"
87 #endif
88
89
90 /* Constants required to setup the task context. */
91 #define portINITIAL_SR ( ( StackType_t ) 0x00400000 ) /* AVR32 : [M2:M0]=001 I1M=0 I0M=0, GM=0 */
92 #define portINSTRUCTION_SIZE ( ( StackType_t ) 0 )
93
94 /* Each task maintains its own critical nesting variable. */
95 #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
96 volatile uint32_t ulCriticalNesting = 9999UL;
97
98 #if ( configTICK_USE_TC == 0 )
99 static void prvScheduleNextTick( void );
100 #else
101 static void prvClearTcInt( void );
102 #endif
103
104 /* Setup the timer to generate the tick interrupts. */
105 static void prvSetupTimerInterrupt( void );
106
107 /*-----------------------------------------------------------*/
108
109 /*
110 * Low-level initialization routine called during startup, before the main
111 * function.
112 * This version comes in replacement to the default one provided by Newlib.
113 * Newlib's _init_startup only calls init_exceptions, but Newlib's exception
114 * vectors are not compatible with the SCALL management in the current FreeRTOS
115 * port. More low-level initializations are besides added here.
116 */
_init_startup(void)117 void _init_startup( void )
118 {
119 /* Import the Exception Vector Base Address. */
120 extern void _evba;
121
122 #if configHEAP_INIT
123 extern void __heap_start__;
124 extern void __heap_end__;
125 BaseType_t * pxMem;
126 #endif
127
128 /* Load the Exception Vector Base Address in the corresponding system register. */
129 Set_system_register( AVR32_EVBA, ( int ) &_evba );
130
131 /* Enable exceptions. */
132 ENABLE_ALL_EXCEPTIONS();
133
134 /* Initialize interrupt handling. */
135 INTC_init_interrupts();
136
137 #if configHEAP_INIT
138 /* Initialize the heap used by malloc. */
139 for( pxMem = &__heap_start__; pxMem < ( BaseType_t * ) &__heap_end__; )
140 {
141 *pxMem++ = 0xA5A5A5A5;
142 }
143 #endif
144
145 /* Give the used CPU clock frequency to Newlib, so it can work properly. */
146 set_cpu_hz( configCPU_CLOCK_HZ );
147
148 /* Code section present if and only if the debug trace is activated. */
149 #if configDBG
150 {
151 static const gpio_map_t DBG_USART_GPIO_MAP =
152 {
153 { configDBG_USART_RX_PIN, configDBG_USART_RX_FUNCTION },
154 { configDBG_USART_TX_PIN, configDBG_USART_TX_FUNCTION }
155 };
156
157 /* Initialize the USART used for the debug trace with the configured parameters. */
158 set_usart_base( ( void * ) configDBG_USART );
159 gpio_enable_module( DBG_USART_GPIO_MAP,
160 sizeof( DBG_USART_GPIO_MAP ) / sizeof( DBG_USART_GPIO_MAP[ 0 ] ) );
161 usart_init( configDBG_USART_BAUDRATE );
162 }
163 #endif /* if configDBG */
164 }
165 /*-----------------------------------------------------------*/
166
167 /*
168 * malloc, realloc and free are meant to be called through respectively
169 * pvPortMalloc, pvPortRealloc and vPortFree.
170 * The latter functions call the former ones from within sections where tasks
171 * are suspended, so the latter functions are task-safe. __malloc_lock and
172 * __malloc_unlock use the same mechanism to also keep the former functions
173 * task-safe as they may be called directly from Newlib's functions.
174 * However, all these functions are interrupt-unsafe and SHALL THEREFORE NOT BE
175 * CALLED FROM WITHIN AN INTERRUPT, because __malloc_lock and __malloc_unlock do
176 * not call portENTER_CRITICAL and portEXIT_CRITICAL in order not to disable
177 * interrupts during memory allocation management as this may be a very time-
178 * consuming process.
179 */
180
181 /*
182 * Lock routine called by Newlib on malloc / realloc / free entry to guarantee a
183 * safe section as memory allocation management uses global data.
184 * See the aforementioned details.
185 */
__malloc_lock(struct _reent * ptr)186 void __malloc_lock( struct _reent * ptr )
187 {
188 vTaskSuspendAll();
189 }
190
191 /*
192 * Unlock routine called by Newlib on malloc / realloc / free exit to guarantee
193 * a safe section as memory allocation management uses global data.
194 * See the aforementioned details.
195 */
__malloc_unlock(struct _reent * ptr)196 void __malloc_unlock( struct _reent * ptr )
197 {
198 xTaskResumeAll();
199 }
200 /*-----------------------------------------------------------*/
201
202 /* Added as there is no such function in FreeRTOS. */
pvPortRealloc(void * pv,size_t xWantedSize)203 void * pvPortRealloc( void * pv,
204 size_t xWantedSize )
205 {
206 void * pvReturn;
207
208 vTaskSuspendAll();
209 {
210 pvReturn = realloc( pv, xWantedSize );
211 }
212 xTaskResumeAll();
213
214 return pvReturn;
215 }
216 /*-----------------------------------------------------------*/
217
218 /* The cooperative scheduler requires a normal IRQ service routine to
219 * simply increment the system tick. */
220
221 /* The preemptive scheduler is defined as "naked" as the full context is saved
222 * on entry as part of the context switch. */
vTick(void)223 __attribute__( ( __naked__ ) ) static void vTick( void )
224 {
225 /* Save the context of the interrupted task. */
226 portSAVE_CONTEXT_OS_INT();
227
228 #if ( configTICK_USE_TC == 1 )
229 /* Clear the interrupt flag. */
230 prvClearTcInt();
231 #else
232
233 /* Schedule the COUNT&COMPARE match interrupt in (configCPU_CLOCK_HZ/configTICK_RATE_HZ)
234 * clock cycles from now. */
235 prvScheduleNextTick();
236 #endif
237
238 /* Because FreeRTOS is not supposed to run with nested interrupts, put all OS
239 * calls in a critical section . */
240 portENTER_CRITICAL();
241 xTaskIncrementTick();
242 portEXIT_CRITICAL();
243
244 /* Restore the context of the "elected task". */
245 portRESTORE_CONTEXT_OS_INT();
246 }
247 /*-----------------------------------------------------------*/
248
SCALLYield(void)249 __attribute__( ( __naked__ ) ) void SCALLYield( void )
250 {
251 /* Save the context of the interrupted task. */
252 portSAVE_CONTEXT_SCALL();
253 vTaskSwitchContext();
254 portRESTORE_CONTEXT_SCALL();
255 }
256 /*-----------------------------------------------------------*/
257
258 /* The code generated by the GCC compiler uses the stack in different ways at
259 * different optimisation levels. The interrupt flags can therefore not always
260 * be saved to the stack. Instead the critical section nesting level is stored
261 * in a variable, which is then saved as part of the stack context. */
vPortEnterCritical(void)262 __attribute__( ( __noinline__ ) ) void vPortEnterCritical( void )
263 {
264 /* Disable interrupts */
265 portDISABLE_INTERRUPTS();
266
267 /* Now that interrupts are disabled, ulCriticalNesting can be accessed
268 * directly. Increment ulCriticalNesting to keep a count of how many times
269 * portENTER_CRITICAL() has been called. */
270 ulCriticalNesting++;
271 }
272 /*-----------------------------------------------------------*/
273
vPortExitCritical(void)274 __attribute__( ( __noinline__ ) ) void vPortExitCritical( void )
275 {
276 if( ulCriticalNesting > portNO_CRITICAL_NESTING )
277 {
278 ulCriticalNesting--;
279
280 if( ulCriticalNesting == portNO_CRITICAL_NESTING )
281 {
282 /* Enable all interrupt/exception. */
283 portENABLE_INTERRUPTS();
284 }
285 }
286 }
287 /*-----------------------------------------------------------*/
288
289 /*
290 * Initialise the stack of a task to look exactly as if a call to
291 * portSAVE_CONTEXT had been called.
292 *
293 * See header file for description.
294 */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters)295 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
296 TaskFunction_t pxCode,
297 void * pvParameters )
298 {
299 /* Setup the initial stack of the task. The stack is set exactly as
300 * expected by the portRESTORE_CONTEXT() macro. */
301
302 /* When the task starts, it will expect to find the function parameter in R12. */
303 pxTopOfStack--;
304 *pxTopOfStack-- = ( StackType_t ) 0x08080808; /* R8 */
305 *pxTopOfStack-- = ( StackType_t ) 0x09090909; /* R9 */
306 *pxTopOfStack-- = ( StackType_t ) 0x0A0A0A0A; /* R10 */
307 *pxTopOfStack-- = ( StackType_t ) 0x0B0B0B0B; /* R11 */
308 *pxTopOfStack-- = ( StackType_t ) pvParameters; /* R12 */
309 *pxTopOfStack-- = ( StackType_t ) 0xDEADBEEF; /* R14/LR */
310 *pxTopOfStack-- = ( StackType_t ) pxCode + portINSTRUCTION_SIZE; /* R15/PC */
311 *pxTopOfStack-- = ( StackType_t ) portINITIAL_SR; /* SR */
312 *pxTopOfStack-- = ( StackType_t ) 0xFF0000FF; /* R0 */
313 *pxTopOfStack-- = ( StackType_t ) 0x01010101; /* R1 */
314 *pxTopOfStack-- = ( StackType_t ) 0x02020202; /* R2 */
315 *pxTopOfStack-- = ( StackType_t ) 0x03030303; /* R3 */
316 *pxTopOfStack-- = ( StackType_t ) 0x04040404; /* R4 */
317 *pxTopOfStack-- = ( StackType_t ) 0x05050505; /* R5 */
318 *pxTopOfStack-- = ( StackType_t ) 0x06060606; /* R6 */
319 *pxTopOfStack-- = ( StackType_t ) 0x07070707; /* R7 */
320 *pxTopOfStack = ( StackType_t ) portNO_CRITICAL_NESTING; /* ulCriticalNesting */
321
322 return pxTopOfStack;
323 }
324 /*-----------------------------------------------------------*/
325
xPortStartScheduler(void)326 BaseType_t xPortStartScheduler( void )
327 {
328 /* Start the timer that generates the tick ISR. Interrupts are disabled
329 * here already. */
330 prvSetupTimerInterrupt();
331
332 /* Start the first task. */
333 portRESTORE_CONTEXT();
334
335 /* Should not get here! */
336 return 0;
337 }
338 /*-----------------------------------------------------------*/
339
vPortEndScheduler(void)340 void vPortEndScheduler( void )
341 {
342 /* It is unlikely that the AVR32 port will require this function as there
343 * is nothing to return to. */
344 }
345 /*-----------------------------------------------------------*/
346
347 /* Schedule the COUNT&COMPARE match interrupt in (configCPU_CLOCK_HZ/configTICK_RATE_HZ)
348 * clock cycles from now. */
349 #if ( configTICK_USE_TC == 0 )
prvScheduleFirstTick(void)350 static void prvScheduleFirstTick( void )
351 {
352 uint32_t lCycles;
353
354 lCycles = Get_system_register( AVR32_COUNT );
355 lCycles += ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );
356
357 /* If lCycles ends up to be 0, make it 1 so that the COMPARE and exception */
358 /* generation feature does not get disabled. */
359 if( 0 == lCycles )
360 {
361 lCycles++;
362 }
363
364 Set_system_register( AVR32_COMPARE, lCycles );
365 }
366
prvScheduleNextTick(void)367 __attribute__( ( __noinline__ ) ) static void prvScheduleNextTick( void )
368 {
369 uint32_t lCycles, lCount;
370
371 lCycles = Get_system_register( AVR32_COMPARE );
372 lCycles += ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );
373
374 /* If lCycles ends up to be 0, make it 1 so that the COMPARE and exception */
375 /* generation feature does not get disabled. */
376 if( 0 == lCycles )
377 {
378 lCycles++;
379 }
380
381 lCount = Get_system_register( AVR32_COUNT );
382
383 if( lCycles < lCount )
384 { /* We missed a tick, recover for the next. */
385 lCycles += ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );
386 }
387
388 Set_system_register( AVR32_COMPARE, lCycles );
389 }
390 #else /* if ( configTICK_USE_TC == 0 ) */
prvClearTcInt(void)391 __attribute__( ( __noinline__ ) ) static void prvClearTcInt( void )
392 {
393 AVR32_TC.channel[ configTICK_TC_CHANNEL ].sr;
394 }
395 #endif /* if ( configTICK_USE_TC == 0 ) */
396 /*-----------------------------------------------------------*/
397
398 /* Setup the timer to generate the tick interrupts. */
prvSetupTimerInterrupt(void)399 static void prvSetupTimerInterrupt( void )
400 {
401 #if ( configTICK_USE_TC == 1 )
402 volatile avr32_tc_t * tc = &AVR32_TC;
403
404 /* Options for waveform genration. */
405 tc_waveform_opt_t waveform_opt =
406 {
407 .channel = configTICK_TC_CHANNEL, /* Channel selection. */
408
409 .bswtrg = TC_EVT_EFFECT_NOOP, /* Software trigger effect on TIOB. */
410 .beevt = TC_EVT_EFFECT_NOOP, /* External event effect on TIOB. */
411 .bcpc = TC_EVT_EFFECT_NOOP, /* RC compare effect on TIOB. */
412 .bcpb = TC_EVT_EFFECT_NOOP, /* RB compare effect on TIOB. */
413
414 .aswtrg = TC_EVT_EFFECT_NOOP, /* Software trigger effect on TIOA. */
415 .aeevt = TC_EVT_EFFECT_NOOP, /* External event effect on TIOA. */
416 .acpc = TC_EVT_EFFECT_NOOP, /* RC compare effect on TIOA: toggle. */
417 .acpa = TC_EVT_EFFECT_NOOP, /* RA compare effect on TIOA: toggle (other possibilities are none, set and clear). */
418
419 .wavsel = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER, /* Waveform selection: Up mode without automatic trigger on RC compare. */
420 .enetrg = FALSE, /* External event trigger enable. */
421 .eevt = 0, /* External event selection. */
422 .eevtedg = TC_SEL_NO_EDGE, /* External event edge selection. */
423 .cpcdis = FALSE, /* Counter disable when RC compare. */
424 .cpcstop = FALSE, /* Counter clock stopped with RC compare. */
425
426 .burst = FALSE, /* Burst signal selection. */
427 .clki = FALSE, /* Clock inversion. */
428 .tcclks = TC_CLOCK_SOURCE_TC2 /* Internal source clock 2. */
429 };
430
431 tc_interrupt_t tc_interrupt =
432 {
433 .etrgs = 0,
434 .ldrbs = 0,
435 .ldras = 0,
436 .cpcs = 1,
437 .cpbs = 0,
438 .cpas = 0,
439 .lovrs = 0,
440 .covfs = 0,
441 };
442 #endif /* if ( configTICK_USE_TC == 1 ) */
443
444 /* Disable all interrupt/exception. */
445 portDISABLE_INTERRUPTS();
446
447 /* Register the compare interrupt handler to the interrupt controller and
448 * enable the compare interrupt. */
449
450 #if ( configTICK_USE_TC == 1 )
451 {
452 INTC_register_interrupt( &vTick, configTICK_TC_IRQ, INT0 );
453
454 /* Initialize the timer/counter. */
455 tc_init_waveform( tc, &waveform_opt );
456
457 /* Set the compare triggers.
458 * Remember TC counter is 16-bits, so counting second is not possible!
459 * That's why we configure it to count ms. */
460 tc_write_rc( tc, configTICK_TC_CHANNEL, ( configPBA_CLOCK_HZ / 4 ) / configTICK_RATE_HZ );
461
462 tc_configure_interrupts( tc, configTICK_TC_CHANNEL, &tc_interrupt );
463
464 /* Start the timer/counter. */
465 tc_start( tc, configTICK_TC_CHANNEL );
466 }
467 #else /* if ( configTICK_USE_TC == 1 ) */
468 {
469 INTC_register_interrupt( &vTick, AVR32_CORE_COMPARE_IRQ, INT0 );
470 prvScheduleFirstTick();
471 }
472 #endif /* if ( configTICK_USE_TC == 1 ) */
473 }
474