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