- Main Page
- Data Structures
- Files

# port.c

Go to the documentation of this file.

    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 }