00001 /*This file has been prepared for Doxygen automatic documentation generation.*/ 00015 /* 00016 FreeRTOS V6.0.0 - Copyright (C) 2009 Real Time Engineers Ltd. 00017 00018 *************************************************************************** 00019 * * 00020 * If you are: * 00021 * * 00022 * + New to FreeRTOS, * 00023 * + Wanting to learn FreeRTOS or multitasking in general quickly * 00024 * + Looking for basic training, * 00025 * + Wanting to improve your FreeRTOS skills and productivity * 00026 * * 00027 * then take a look at the FreeRTOS eBook * 00028 * * 00029 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * 00030 * http://www.FreeRTOS.org/Documentation * 00031 * * 00032 * A pdf reference manual is also available. Both are usually delivered * 00033 * to your inbox within 20 minutes to two hours when purchased between 8am * 00034 * and 8pm GMT (although please allow up to 24 hours in case of * 00035 * exceptional circumstances). Thank you for your support! * 00036 * * 00037 *************************************************************************** 00038 00039 This file is part of the FreeRTOS distribution. 00040 00041 FreeRTOS is free software; you can redistribute it and/or modify it under 00042 the terms of the GNU General Public License (version 2) as published by the 00043 Free Software Foundation AND MODIFIED BY the FreeRTOS exception. 00044 ***NOTE*** The exception to the GPL is included to allow you to distribute 00045 a combined work that includes FreeRTOS without being obliged to provide the 00046 source code for proprietary components outside of the FreeRTOS kernel. 00047 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT 00048 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00049 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 00050 more details. You should have received a copy of the GNU General Public 00051 License and the FreeRTOS license exception along with FreeRTOS; if not it 00052 can be viewed here: http://www.freertos.org/a00114.html and also obtained 00053 by writing to Richard Barry, contact details for whom are available on the 00054 FreeRTOS WEB site. 00055 00056 1 tab == 4 spaces! 00057 00058 http://www.FreeRTOS.org - Documentation, latest information, license and 00059 contact details. 00060 00061 http://www.SafeRTOS.com - A version that is certified for use in safety 00062 critical systems. 00063 00064 http://www.OpenRTOS.com - Commercial support, development, porting, 00065 licensing and training services. 00066 */ 00067 00068 00069 /* Standard includes. */ 00070 #include <malloc.h> 00071 00072 /* Newlib add-ons includes. */ 00073 #include "nlao_cpu.h" 00074 #include "nlao_usart.h" 00075 00076 /* Scheduler includes. */ 00077 #include "FreeRTOS.h" 00078 #include "task.h" 00079 00080 /* AVR32 UC3 includes. */ 00081 #include <avr32/io.h> 00082 #include "gpio.h" 00083 #if( configTICK_USE_TC==1 ) 00084 #include "tc.h" 00085 #endif 00086 00087 00088 /* Constants required to setup the task context. */ 00089 #define portINITIAL_SR ( ( portSTACK_TYPE ) 0x00400000 ) /* AVR32 : [M2:M0]=001 I1M=0 I0M=0, GM=0 */ 00090 #define portINSTRUCTION_SIZE ( ( portSTACK_TYPE ) 0 ) 00091 00092 /* Each task maintains its own critical nesting variable. */ 00093 #define portNO_CRITICAL_NESTING ( ( unsigned portLONG ) 0 ) 00094 volatile unsigned portLONG ulCriticalNesting = 9999UL; 00095 00096 #if( configTICK_USE_TC==0 ) 00097 static void prvClearCcInt( void ); 00098 #else 00099 static void prvClearTcInt( void ); 00100 #endif 00101 00102 /* Setup the timer to generate the tick interrupts. */ 00103 static void prvSetupTimerInterrupt( void ); 00104 00105 /*-----------------------------------------------------------*/ 00106 00107 /* 00108 * Low-level initialization routine called during startup, before the main 00109 * function. 00110 * This version comes in replacement to the default one provided by the Newlib 00111 * add-ons library. 00112 * Newlib add-ons' _init_startup only calls init_exceptions, but Newlib add-ons' 00113 * exception vectors are not compatible with the SCALL management in the current 00114 * FreeRTOS port. More low-level initializations are besides added here. 00115 */ 00116 int _init_startup(void) 00117 { 00118 /* Import the Exception Vector Base Address. */ 00119 extern void _evba; 00120 00121 #if configHEAP_INIT 00122 extern void __heap_start__; 00123 extern void __heap_end__; 00124 portBASE_TYPE *pxMem; 00125 #endif 00126 00127 /* Load the Exception Vector Base Address in the corresponding system register. */ 00128 Set_system_register( AVR32_EVBA, ( int ) &_evba ); 00129 00130 /* Enable exceptions. */ 00131 ENABLE_ALL_EXCEPTIONS(); 00132 00133 /* Initialize interrupt handling. */ 00134 INTC_init_interrupts(); 00135 00136 #if configHEAP_INIT 00137 00138 /* Initialize the heap used by malloc. */ 00139 for( pxMem = &__heap_start__; pxMem < ( portBASE_TYPE * )&__heap_end__; ) 00140 { 00141 *pxMem++ = 0xA5A5A5A5; 00142 } 00143 00144 #endif 00145 00146 /* Give the used PBA clock frequency to Newlib, so it can work properly. */ 00147 set_cpu_hz( configPBA_CLOCK_HZ ); 00148 00149 /* Code section present if and only if the debug trace is activated. */ 00150 #if configDBG 00151 { 00152 static const gpio_map_t DBG_USART_GPIO_MAP = 00153 { 00154 { configDBG_USART_RX_PIN, configDBG_USART_RX_FUNCTION }, 00155 { configDBG_USART_TX_PIN, configDBG_USART_TX_FUNCTION } 00156 }; 00157 00158 /* Initialize the USART used for the debug trace with the configured parameters. */ 00159 set_usart_base( ( void * ) configDBG_USART ); 00160 gpio_enable_module( DBG_USART_GPIO_MAP, 00161 sizeof( DBG_USART_GPIO_MAP ) / sizeof( DBG_USART_GPIO_MAP[0] ) ); 00162 usart_init( configDBG_USART_BAUDRATE ); 00163 } 00164 #endif 00165 00166 // Don't-care value for GCC. 00167 return 1; 00168 } 00169 /*-----------------------------------------------------------*/ 00170 00171 /* 00172 * malloc, realloc and free are meant to be called through respectively 00173 * pvPortMalloc, pvPortRealloc and vPortFree. 00174 * The latter functions call the former ones from within sections where tasks 00175 * are suspended, so the latter functions are task-safe. __malloc_lock and 00176 * __malloc_unlock use the same mechanism to also keep the former functions 00177 * task-safe as they may be called directly from Newlib's functions. 00178 * However, all these functions are interrupt-unsafe and SHALL THEREFORE NOT BE 00179 * CALLED FROM WITHIN AN INTERRUPT, because __malloc_lock and __malloc_unlock do 00180 * not call portENTER_CRITICAL and portEXIT_CRITICAL in order not to disable 00181 * interrupts during memory allocation management as this may be a very time- 00182 * consuming process. 00183 */ 00184 00185 /* 00186 * Lock routine called by Newlib on malloc / realloc / free entry to guarantee a 00187 * safe section as memory allocation management uses global data. 00188 * See the aforementioned details. 00189 */ 00190 void __malloc_lock(struct _reent *ptr) 00191 { 00192 vTaskSuspendAll(); 00193 } 00194 00195 /* 00196 * Unlock routine called by Newlib on malloc / realloc / free exit to guarantee 00197 * a safe section as memory allocation management uses global data. 00198 * See the aforementioned details. 00199 */ 00200 void __malloc_unlock(struct _reent *ptr) 00201 { 00202 xTaskResumeAll(); 00203 } 00204 /*-----------------------------------------------------------*/ 00205 00206 /* Added as there is no such function in FreeRTOS. */ 00207 void *pvPortRealloc( void *pv, size_t xWantedSize ) 00208 { 00209 void *pvReturn; 00210 00211 vTaskSuspendAll(); 00212 { 00213 pvReturn = realloc( pv, xWantedSize ); 00214 } 00215 xTaskResumeAll(); 00216 00217 return pvReturn; 00218 } 00219 /*-----------------------------------------------------------*/ 00220 00221 /* The cooperative scheduler requires a normal IRQ service routine to 00222 simply increment the system tick. */ 00223 /* The preemptive scheduler is defined as "naked" as the full context is saved 00224 on entry as part of the context switch. */ 00225 __attribute__((__naked__)) static void vTick( void ) 00226 { 00227 /* Save the context of the interrupted task. */ 00228 portSAVE_CONTEXT_OS_INT(); 00229 00230 #if( configTICK_USE_TC==1 ) 00231 /* Clear the interrupt flag. */ 00232 prvClearTcInt(); 00233 #else 00234 /* Clear the interrupt flag. */ 00235 prvClearCcInt(); 00236 #endif 00237 00238 /* Because FreeRTOS is not supposed to run with nested interrupts, put all OS 00239 calls in a critical section . */ 00240 portENTER_CRITICAL(); 00241 vTaskIncrementTick(); 00242 portEXIT_CRITICAL(); 00243 00244 /* Restore the context of the "elected task". */ 00245 portRESTORE_CONTEXT_OS_INT(); 00246 } 00247 /*-----------------------------------------------------------*/ 00248 00249 __attribute__((__naked__)) void SCALLYield( void ) 00250 { 00251 /* Save the context of the interrupted task. */ 00252 portSAVE_CONTEXT_SCALL(); 00253 vTaskSwitchContext(); 00254 portRESTORE_CONTEXT_SCALL(); 00255 } 00256 /*-----------------------------------------------------------*/ 00257 00258 /* The code generated by the GCC compiler uses the stack in different ways at 00259 different optimisation levels. The interrupt flags can therefore not always 00260 be saved to the stack. Instead the critical section nesting level is stored 00261 in a variable, which is then saved as part of the stack context. */ 00262 __attribute__((__noinline__)) void vPortEnterCritical( void ) 00263 { 00264 /* Disable interrupts */ 00265 portDISABLE_INTERRUPTS(); 00266 00267 /* Now interrupts are disabled ulCriticalNesting can be accessed 00268 directly. Increment ulCriticalNesting to keep a count of how many times 00269 portENTER_CRITICAL() has been called. */ 00270 ulCriticalNesting++; 00271 } 00272 /*-----------------------------------------------------------*/ 00273 00274 __attribute__((__noinline__)) void vPortExitCritical( void ) 00275 { 00276 if(ulCriticalNesting > portNO_CRITICAL_NESTING) 00277 { 00278 ulCriticalNesting--; 00279 if( ulCriticalNesting == portNO_CRITICAL_NESTING ) 00280 { 00281 /* Enable all interrupt/exception. */ 00282 portENABLE_INTERRUPTS(); 00283 } 00284 } 00285 } 00286 /*-----------------------------------------------------------*/ 00287 00288 /* 00289 * Initialise the stack of a task to look exactly as if a call to 00290 * portSAVE_CONTEXT had been called. 00291 * 00292 * See header file for description. 00293 */ 00294 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) 00295 { 00296 /* Setup the initial stack of the task. The stack is set exactly as 00297 expected by the portRESTORE_CONTEXT() macro. */ 00298 00299 /* When the task starts, it will expect to find the function parameter in R12. */ 00300 pxTopOfStack--; 00301 *pxTopOfStack-- = ( portSTACK_TYPE ) 0x08080808; /* R8 */ 00302 *pxTopOfStack-- = ( portSTACK_TYPE ) 0x09090909; /* R9 */ 00303 *pxTopOfStack-- = ( portSTACK_TYPE ) 0x0A0A0A0A; /* R10 */ 00304 *pxTopOfStack-- = ( portSTACK_TYPE ) 0x0B0B0B0B; /* R11 */ 00305 *pxTopOfStack-- = ( portSTACK_TYPE ) pvParameters; /* R12 */ 00306 *pxTopOfStack-- = ( portSTACK_TYPE ) 0xDEADBEEF; /* R14/LR */ 00307 *pxTopOfStack-- = ( portSTACK_TYPE ) pxCode + portINSTRUCTION_SIZE; /* R15/PC */ 00308 *pxTopOfStack-- = ( portSTACK_TYPE ) portINITIAL_SR; /* SR */ 00309 *pxTopOfStack-- = ( portSTACK_TYPE ) 0xFF0000FF; /* R0 */ 00310 *pxTopOfStack-- = ( portSTACK_TYPE ) 0x01010101; /* R1 */ 00311 *pxTopOfStack-- = ( portSTACK_TYPE ) 0x02020202; /* R2 */ 00312 *pxTopOfStack-- = ( portSTACK_TYPE ) 0x03030303; /* R3 */ 00313 *pxTopOfStack-- = ( portSTACK_TYPE ) 0x04040404; /* R4 */ 00314 *pxTopOfStack-- = ( portSTACK_TYPE ) 0x05050505; /* R5 */ 00315 *pxTopOfStack-- = ( portSTACK_TYPE ) 0x06060606; /* R6 */ 00316 *pxTopOfStack-- = ( portSTACK_TYPE ) 0x07070707; /* R7 */ 00317 *pxTopOfStack = ( portSTACK_TYPE ) portNO_CRITICAL_NESTING; /* ulCriticalNesting */ 00318 00319 return pxTopOfStack; 00320 } 00321 /*-----------------------------------------------------------*/ 00322 00323 portBASE_TYPE xPortStartScheduler( void ) 00324 { 00325 /* Start the timer that generates the tick ISR. Interrupts are disabled 00326 here already. */ 00327 prvSetupTimerInterrupt(); 00328 00329 /* Start the first task. */ 00330 portRESTORE_CONTEXT(); 00331 00332 /* Should not get here! */ 00333 return 0; 00334 } 00335 /*-----------------------------------------------------------*/ 00336 00337 void vPortEndScheduler( void ) 00338 { 00339 /* It is unlikely that the AVR32 port will require this function as there 00340 is nothing to return to. */ 00341 } 00342 /*-----------------------------------------------------------*/ 00343 00344 /* Schedule the COUNT&COMPARE match interrupt in (configCPU_CLOCK_HZ/configTICK_RATE_HZ) 00345 clock cycles from now. */ 00346 #if( configTICK_USE_TC==0 ) 00347 static void prvScheduleFirstTick(void) 00348 { 00349 Set_system_register(AVR32_COMPARE, configCPU_CLOCK_HZ/configTICK_RATE_HZ); 00350 Set_system_register(AVR32_COUNT, 0); 00351 } 00352 00353 __attribute__((__noinline__)) static void prvClearCcInt(void) 00354 { 00355 Set_system_register(AVR32_COMPARE, Get_system_register(AVR32_COMPARE)); 00356 } 00357 #else 00358 __attribute__((__noinline__)) static void prvClearTcInt(void) 00359 { 00360 AVR32_TC.channel[configTICK_TC_CHANNEL].sr; 00361 } 00362 #endif 00363 /*-----------------------------------------------------------*/ 00364 00365 /* Setup the timer to generate the tick interrupts. */ 00366 static void prvSetupTimerInterrupt(void) 00367 { 00368 #if( configTICK_USE_TC==1 ) 00369 00370 volatile avr32_tc_t *tc = &AVR32_TC; 00371 00372 // Options for waveform genration. 00373 tc_waveform_opt_t waveform_opt = 00374 { 00375 .channel = configTICK_TC_CHANNEL, /* Channel selection. */ 00376 00377 .bswtrg = TC_EVT_EFFECT_NOOP, /* Software trigger effect on TIOB. */ 00378 .beevt = TC_EVT_EFFECT_NOOP, /* External event effect on TIOB. */ 00379 .bcpc = TC_EVT_EFFECT_NOOP, /* RC compare effect on TIOB. */ 00380 .bcpb = TC_EVT_EFFECT_NOOP, /* RB compare effect on TIOB. */ 00381 00382 .aswtrg = TC_EVT_EFFECT_NOOP, /* Software trigger effect on TIOA. */ 00383 .aeevt = TC_EVT_EFFECT_NOOP, /* External event effect on TIOA. */ 00384 .acpc = TC_EVT_EFFECT_NOOP, /* RC compare effect on TIOA: toggle. */ 00385 .acpa = TC_EVT_EFFECT_NOOP, /* RA compare effect on TIOA: toggle (other possibilities are none, set and clear). */ 00386 00387 .wavsel = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,/* Waveform selection: Up mode without automatic trigger on RC compare. */ 00388 .enetrg = FALSE, /* External event trigger enable. */ 00389 .eevt = 0, /* External event selection. */ 00390 .eevtedg = TC_SEL_NO_EDGE, /* External event edge selection. */ 00391 .cpcdis = FALSE, /* Counter disable when RC compare. */ 00392 .cpcstop = FALSE, /* Counter clock stopped with RC compare. */ 00393 00394 .burst = FALSE, /* Burst signal selection. */ 00395 .clki = FALSE, /* Clock inversion. */ 00396 .tcclks = TC_CLOCK_SOURCE_TC3 /* Internal source clock 3. */ 00397 }; 00398 00399 tc_interrupt_t tc_interrupt = 00400 { 00401 .etrgs=0, 00402 .ldrbs=0, 00403 .ldras=0, 00404 .cpcs =1, 00405 .cpbs =0, 00406 .cpas =0, 00407 .lovrs=0, 00408 .covfs=0, 00409 }; 00410 00411 #endif 00412 00413 /* Disable all interrupt/exception. */ 00414 portDISABLE_INTERRUPTS(); 00415 00416 /* Register the compare interrupt handler to the interrupt controller and 00417 enable the compare interrupt. */ 00418 00419 #if( configTICK_USE_TC==1 ) 00420 { 00421 INTC_register_interrupt(&vTick, configTICK_TC_IRQ, AVR32_INTC_INT0); 00422 00423 /* Initialize the timer/counter. */ 00424 tc_init_waveform(tc, &waveform_opt); 00425 00426 /* Set the compare triggers. 00427 Remember TC counter is 16-bits, so counting second is not possible! 00428 That's why we configure it to count ms. Set Rc to the right value with 00429 rounding.*/ 00430 tc_write_rc( tc, configTICK_TC_CHANNEL, ( configPBA_CLOCK_HZ + 4 * configTICK_RATE_HZ ) / 00431 ( 8 * configTICK_RATE_HZ ) ); 00432 00433 tc_configure_interrupts( tc, configTICK_TC_CHANNEL, &tc_interrupt ); 00434 00435 /* Start the timer/counter. */ 00436 tc_start(tc, configTICK_TC_CHANNEL); 00437 } 00438 #else 00439 { 00440 INTC_register_interrupt(&vTick, AVR32_CORE_COMPARE_IRQ, AVR32_INTC_INT0); 00441 prvScheduleFirstTick(); 00442 } 00443 #endif 00444 }