- Main Page
- Related Pages
- 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 #include "gpio.h" // Have to include gpio.h before FreeRTOS.h as long as FreeRTOS
    00058                   // redefines the inline keyword to empty.
    00059
    00060 /* Scheduler includes. */
    00061 #include "FreeRTOS.h"
    00062 #include "task.h"
    00063
    00064 /* AVR32 UC3 includes. */
    00065 #include <avr32/io.h>
    00066 #include <intrinsics.h>
    00067
    00068 #if configDBG
    00069     #include "usart.h"
    00070 #endif
    00071
    00072 #if( configTICK_USE_TC==1 )
    00073     #include "tc.h"
    00074 #endif
    00075
    00076 extern void local_start_pll(void);
    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  */
    00100 int __low_level_init(void)
    00101 {
    00102     #if configHEAP_INIT
    00103         #pragma segment = "HEAP"
    00104         portBASE_TYPE *pxMem;
    00105     #endif
    00106
    00107     /* Enable exceptions. */
    00108     ENABLE_ALL_EXCEPTIONS();
    00109
    00110     /* Initialize interrupt handling. */
    00111     INTC_init_interrupts();
    00112
    00113     #if configHEAP_INIT
    00114     {
    00115         /* Initialize the heap used by malloc. */
    00116         for( pxMem = __segment_begin( "HEAP" ); pxMem < ( portBASE_TYPE * ) __segment_end( "HEAP" ); )
    00117         {
    00118             *pxMem++ = 0xA5A5A5A5;
    00119         }
    00120     }
    00121     #endif
    00122
    00123     /* Code section present if and only if the debug trace is activated. */
    00124     #if configDBG
    00125     {
    00126         static const gpio_map_t DBG_USART_GPIO_MAP =
    00127         {
    00128             { configDBG_USART_RX_PIN, configDBG_USART_RX_FUNCTION },
    00129             { configDBG_USART_TX_PIN, configDBG_USART_TX_FUNCTION }
    00130         };
    00131
    00132         static const usart_options_t DBG_USART_OPTIONS =
    00133         {
    00134             .baudrate = configDBG_USART_BAUDRATE,
    00135             .charlength = 8,
    00136             .paritytype = USART_NO_PARITY,
    00137             .stopbits = USART_1_STOPBIT,
    00138             .channelmode = USART_NORMAL_CHMODE
    00139         };
    00140
    00141         /* Initialize the USART used for the debug trace with the configured parameters. */
    00142         extern volatile avr32_usart_t *volatile stdio_usart_base;
    00143         stdio_usart_base = configDBG_USART;
    00144         gpio_enable_module( DBG_USART_GPIO_MAP,
    00145                             sizeof( DBG_USART_GPIO_MAP ) / sizeof( DBG_USART_GPIO_MAP[0] ) );
    00146         usart_init_rs232(configDBG_USART, &DBG_USART_OPTIONS, configCPU_CLOCK_HZ);
    00147     }
    00148     #endif
    00149
    00150     local_start_pll();
    00151
    00152     /* Request initialization of data segments. */
    00153     return 1;
    00154 }
    00155 /*-----------------------------------------------------------*/
    00156
    00157 /* Added as there is no such function in FreeRTOS. */
    00158 void *pvPortRealloc( void *pv, size_t xWantedSize )
    00159 {
    00160 void *pvReturn;
    00161
    00162     vTaskSuspendAll();
    00163     {
    00164         pvReturn = realloc( pv, xWantedSize );
    00165     }
    00166     xTaskResumeAll();
    00167
    00168     return pvReturn;
    00169 }
    00170 /*-----------------------------------------------------------*/
    00171
    00172 /* The cooperative scheduler requires a normal IRQ service routine to
    00173 simply increment the system tick. */
    00174 /* The preemptive scheduler is defined as "naked" as the full context is saved
    00175 on entry as part of the context switch. */
    00176 #pragma shadow_registers = full   // Naked.
    00177 static void vTick( void )
    00178 {
    00179     /* Save the context of the interrupted task. */
    00180     portSAVE_CONTEXT_OS_INT();
    00181
    00182     #if( configTICK_USE_TC==1 )
    00183         /* Clear the interrupt flag. */
    00184         prvClearTcInt();
    00185     #else
    00186         /* Clear the interrupt flag. */
    00187         prvClearCcInt();
    00188     #endif
    00189
    00190     /* Because FreeRTOS is not supposed to run with nested interrupts, put all OS
    00191     calls in a critical section . */
    00192     portENTER_CRITICAL();
    00193         vTaskIncrementTick();
    00194     portEXIT_CRITICAL();
    00195
    00196     /* Restore the context of the "elected task". */
    00197     portRESTORE_CONTEXT_OS_INT();
    00198 }
    00199 /*-----------------------------------------------------------*/
    00200
    00201 #pragma shadow_registers = full   // Naked.
    00202 void SCALLYield( void )
    00203 {
    00204     /* Save the context of the interrupted task. */
    00205     portSAVE_CONTEXT_SCALL();
    00206     vTaskSwitchContext();
    00207     portRESTORE_CONTEXT_SCALL();
    00208 }
    00209 /*-----------------------------------------------------------*/
    00210
    00211 /* The code generated by the GCC compiler uses the stack in different ways at
    00212 different optimisation levels.  The interrupt flags can therefore not always
    00213 be saved to the stack.  Instead the critical section nesting level is stored
    00214 in a variable, which is then saved as part of the stack context. */
    00215 #pragma optimize = no_inline
    00216 void vPortEnterCritical( void )
    00217 {
    00218     /* Disable interrupts */
    00219     portDISABLE_INTERRUPTS();
    00220
    00221     /* Now interrupts are disabled ulCriticalNesting can be accessed
    00222      directly.  Increment ulCriticalNesting to keep a count of how many times
    00223      portENTER_CRITICAL() has been called. */
    00224     ulCriticalNesting++;
    00225 }
    00226 /*-----------------------------------------------------------*/
    00227
    00228 #pragma optimize = no_inline
    00229 void vPortExitCritical( void )
    00230 {
    00231     if(ulCriticalNesting > portNO_CRITICAL_NESTING)
    00232     {
    00233         ulCriticalNesting--;
    00234         if( ulCriticalNesting == portNO_CRITICAL_NESTING )
    00235         {
    00236             /* Enable all interrupt/exception. */
    00237             portENABLE_INTERRUPTS();
    00238         }
    00239     }
    00240 }
    00241 /*-----------------------------------------------------------*/
    00242
    00243 /*
    00244  * Initialise the stack of a task to look exactly as if a call to
    00245  * portSAVE_CONTEXT had been called.
    00246  *
    00247  * See header file for description.
    00248  */
    00249 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
    00250 {
    00251     /* Setup the initial stack of the task.  The stack is set exactly as
    00252     expected by the portRESTORE_CONTEXT() macro. */
    00253
    00254     /* When the task starts, it will expect to find the function parameter in R12. */
    00255     pxTopOfStack--;
    00256     *pxTopOfStack-- = ( portSTACK_TYPE ) 0x08080808;                    /* R8 */
    00257     *pxTopOfStack-- = ( portSTACK_TYPE ) 0x09090909;                    /* R9 */
    00258     *pxTopOfStack-- = ( portSTACK_TYPE ) 0x0A0A0A0A;                    /* R10 */
    00259     *pxTopOfStack-- = ( portSTACK_TYPE ) 0x0B0B0B0B;                    /* R11 */
    00260     *pxTopOfStack-- = ( portSTACK_TYPE ) pvParameters;                  /* R12 */
    00261     *pxTopOfStack-- = ( portSTACK_TYPE ) 0xDEADBEEF;                    /* R14/LR */
    00262     *pxTopOfStack-- = ( portSTACK_TYPE ) pxCode + portINSTRUCTION_SIZE; /* R15/PC */
    00263     *pxTopOfStack-- = ( portSTACK_TYPE ) portINITIAL_SR;                /* SR */
    00264     *pxTopOfStack-- = ( portSTACK_TYPE ) 0xFF0000FF;                    /* R0 */
    00265     *pxTopOfStack-- = ( portSTACK_TYPE ) 0x01010101;                    /* R1 */
    00266     *pxTopOfStack-- = ( portSTACK_TYPE ) 0x02020202;                    /* R2 */
    00267     *pxTopOfStack-- = ( portSTACK_TYPE ) 0x03030303;                    /* R3 */
    00268     *pxTopOfStack-- = ( portSTACK_TYPE ) 0x04040404;                    /* R4 */
    00269     *pxTopOfStack-- = ( portSTACK_TYPE ) 0x05050505;                    /* R5 */
    00270     *pxTopOfStack-- = ( portSTACK_TYPE ) 0x06060606;                    /* R6 */
    00271     *pxTopOfStack-- = ( portSTACK_TYPE ) 0x07070707;                    /* R7 */
    00272     *pxTopOfStack = ( portSTACK_TYPE ) portNO_CRITICAL_NESTING;         /* ulCriticalNesting */
    00273
    00274     return pxTopOfStack;
    00275 }
    00276 /*-----------------------------------------------------------*/
    00277
    00278 portBASE_TYPE xPortStartScheduler( void )
    00279 {
    00280     /* Start the timer that generates the tick ISR.  Interrupts are disabled
    00281     here already. */
    00282     prvSetupTimerInterrupt();
    00283
    00284     /* Start the first task. */
    00285     portRESTORE_CONTEXT();
    00286
    00287     /* Should not get here! */
    00288     return 0;
    00289 }
    00290 /*-----------------------------------------------------------*/
    00291
    00292 void vPortEndScheduler( void )
    00293 {
    00294     /* It is unlikely that the AVR32 port will require this function as there
    00295     is nothing to return to.  */
    00296 }
    00297 /*-----------------------------------------------------------*/
    00298
    00299 /* Schedule the COUNT&COMPARE match interrupt in (configCPU_CLOCK_HZ/configTICK_RATE_HZ)
    00300 clock cycles from now. */
    00301 #if( configTICK_USE_TC==0 )
    00302     static void prvScheduleFirstTick(void)
    00303     {
    00304         Set_system_register(AVR32_COMPARE, configCPU_CLOCK_HZ/configTICK_RATE_HZ);
    00305         Set_system_register(AVR32_COUNT, 0);
    00306     }
    00307
    00308     #pragma optimize = no_inline
    00309     static void prvClearCcInt(void)
    00310     {
    00311         Set_system_register(AVR32_COMPARE, Get_system_register(AVR32_COMPARE));
    00312     }
    00313 #else
    00314     #pragma optimize = no_inline
    00315     static void prvClearTcInt(void)
    00316     {
    00317         AVR32_TC.channel[configTICK_TC_CHANNEL].sr;
    00318     }
    00319 #endif
    00320 /*-----------------------------------------------------------*/
    00321
    00322 /* Setup the timer to generate the tick interrupts. */
    00323 static void prvSetupTimerInterrupt(void)
    00324 {
    00325     #if( configTICK_USE_TC==1 )
    00326
    00327         volatile avr32_tc_t *tc = &AVR32_TC;
    00328
    00329         // Options for waveform genration.
    00330         tc_waveform_opt_t waveform_opt =
    00331         {
    00332         .channel  = configTICK_TC_CHANNEL,             /* Channel selection. */
    00333
    00334         .bswtrg   = TC_EVT_EFFECT_NOOP,                /* Software trigger effect on TIOB. */
    00335         .beevt    = TC_EVT_EFFECT_NOOP,                /* External event effect on TIOB. */
    00336         .bcpc     = TC_EVT_EFFECT_NOOP,                /* RC compare effect on TIOB. */
    00337         .bcpb     = TC_EVT_EFFECT_NOOP,                /* RB compare effect on TIOB. */
    00338
    00339         .aswtrg   = TC_EVT_EFFECT_NOOP,                /* Software trigger effect on TIOA. */
    00340         .aeevt    = TC_EVT_EFFECT_NOOP,                /* External event effect on TIOA. */
    00341         .acpc     = TC_EVT_EFFECT_NOOP,                /* RC compare effect on TIOA: toggle. */
    00342         .acpa     = TC_EVT_EFFECT_NOOP,                /* RA compare effect on TIOA: toggle (other possibilities are none, set and clear). */
    00343
    00344         .wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,/* Waveform selection: Up mode without automatic trigger on RC compare. */
    00345         .enetrg   = FALSE,                             /* External event trigger enable. */
    00346         .eevt     = 0,                                 /* External event selection. */
    00347         .eevtedg  = TC_SEL_NO_EDGE,                    /* External event edge selection. */
    00348         .cpcdis   = FALSE,                             /* Counter disable when RC compare. */
    00349         .cpcstop  = FALSE,                             /* Counter clock stopped with RC compare. */
    00350
    00351         .burst    = FALSE,                             /* Burst signal selection. */
    00352         .clki     = FALSE,                             /* Clock inversion. */
    00353         .tcclks   = TC_CLOCK_SOURCE_TC3                /* Internal source clock 3. */
    00354         };
    00355
    00356         tc_interrupt_t tc_interrupt =
    00357         {
    00358             .etrgs=0,
    00359             .ldrbs=0,
    00360             .ldras=0,
    00361             .cpcs =1,
    00362             .cpbs =0,
    00363             .cpas =0,
    00364             .lovrs=0,
    00365             .covfs=0,
    00366         };
    00367
    00368     #endif
    00369
    00370     /* Disable all interrupt/exception. */
    00371     portDISABLE_INTERRUPTS();
    00372
    00373     /* Register the compare interrupt handler to the interrupt controller and
    00374     enable the compare interrupt. */
    00375
    00376     #if( configTICK_USE_TC==1 )
    00377     {
    00378         INTC_register_interrupt((__int_handler)&vTick, configTICK_TC_IRQ, AVR32_INTC_INT0);
    00379
    00380         /* Initialize the timer/counter. */
    00381         tc_init_waveform(tc, &waveform_opt);
    00382
    00383         /* Set the compare triggers.
    00384         Remember TC counter is 16-bits, so counting second is not possible!
    00385         That's why we configure it to count ms. Set Rc to the right value with
    00386         rounding. */
    00387         tc_write_rc( tc, configTICK_TC_CHANNEL, ( configPBA_CLOCK_HZ + 4 * configTICK_RATE_HZ ) /
    00388                                                 ( 8 * configTICK_RATE_HZ ) );
    00389
    00390         tc_configure_interrupts( tc, configTICK_TC_CHANNEL, &tc_interrupt );
    00391
    00392         /* Start the timer/counter. */
    00393         tc_start(tc, configTICK_TC_CHANNEL);
    00394     }
    00395     #else
    00396     {
    00397         INTC_register_interrupt((__int_handler)&vTick, AVR32_CORE_COMPARE_IRQ, AVR32_INTC_INT0);
    00398         prvScheduleFirstTick();
    00399     }
    00400     #endif
    00401 }