FreeRTOS Real Time Operating System, Modified from Kenji Arai's initial port. See freertos.org for full documentation.

Fork of FreeRTOS_on_mbed_v1 by Kenji Arai

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers port.c Source File

port.c

00001 /*
00002     FreeRTOS V6.0.3 - Copyright (C) 2010 Real Time Engineers Ltd.
00003 
00004     ***************************************************************************
00005     *                                                                         *
00006     * If you are:                                                             *
00007     *                                                                         *
00008     *    + New to FreeRTOS,                                                   *
00009     *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
00010     *    + Looking for basic training,                                        *
00011     *    + Wanting to improve your FreeRTOS skills and productivity           *
00012     *                                                                         *
00013     * then take a look at the FreeRTOS eBook                                  *
00014     *                                                                         *
00015     *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
00016     *                  http://www.FreeRTOS.org/Documentation                  *
00017     *                                                                         *
00018     * A pdf reference manual is also available.  Both are usually delivered   *
00019     * to your inbox within 20 minutes to two hours when purchased between 8am *
00020     * and 8pm GMT (although please allow up to 24 hours in case of            *
00021     * exceptional circumstances).  Thank you for your support!                *
00022     *                                                                         *
00023     ***************************************************************************
00024 
00025     This file is part of the FreeRTOS distribution.
00026 
00027     FreeRTOS is free software; you can redistribute it and/or modify it under
00028     the terms of the GNU General Public License (version 2) as published by the
00029     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
00030     ***NOTE*** The exception to the GPL is included to allow you to distribute
00031     a combined work that includes FreeRTOS without being obliged to provide the
00032     source code for proprietary components outside of the FreeRTOS kernel.
00033     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
00034     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00035     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00036     more details. You should have received a copy of the GNU General Public 
00037     License and the FreeRTOS license exception along with FreeRTOS; if not it 
00038     can be viewed here: http://www.freertos.org/a00114.html and also obtained 
00039     by writing to Richard Barry, contact details for whom are available on the
00040     FreeRTOS WEB site.
00041 
00042     1 tab == 4 spaces!
00043 
00044     http://www.FreeRTOS.org - Documentation, latest information, license and
00045     contact details.
00046 
00047     http://www.SafeRTOS.com - A version that is certified for use in safety
00048     critical systems.
00049 
00050     http://www.OpenRTOS.com - Commercial support, development, porting,
00051     licensing and training services.
00052 */
00053 
00054 /*-----------------------------------------------------------
00055  * Implementation of functions defined in portable.h for the ARM CM3 port.
00056  *----------------------------------------------------------*/
00057 
00058 // Modified by  Kenji Arai / JH1PJL, October 30th,2010
00059 // Some functions go to port_asm.c
00060 
00061 /* Scheduler includes. */
00062 #include "FreeRTOS.h"
00063 #include "task.h"
00064 
00065 /* For backward compatibility, ensure configKERNEL_INTERRUPT_PRIORITY is
00066 defined.  The value should also ensure backward compatibility.
00067 FreeRTOS.org versions prior to V4.4.0 did not include this definition. */
00068 #ifndef configKERNEL_INTERRUPT_PRIORITY
00069     #define configKERNEL_INTERRUPT_PRIORITY 255
00070 #endif
00071 
00072 /* Constants required to manipulate the NVIC. */
00073 #define portNVIC_SYSTICK_CTRL        ( ( volatile unsigned long *) 0xe000e010 )
00074 #define portNVIC_SYSTICK_LOAD        ( ( volatile unsigned long *) 0xe000e014 )
00075 #define portNVIC_INT_CTRL            ( ( volatile unsigned long *) 0xe000ed04 )
00076 #define portNVIC_SYSPRI2            ( ( volatile unsigned long *) 0xe000ed20 )
00077 #define portNVIC_SYSTICK_CLK        0x00000004
00078 #define portNVIC_SYSTICK_INT        0x00000002
00079 #define portNVIC_SYSTICK_ENABLE        0x00000001
00080 #define portNVIC_PENDSVSET            0x10000000
00081 #define portNVIC_PENDSV_PRI            ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 )
00082 #define portNVIC_SYSTICK_PRI        ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 )
00083 
00084 /* Constants required to set up the initial stack. */
00085 #define portINITIAL_XPSR            ( 0x01000000 )
00086 
00087 /* The priority used by the kernel is assigned to a variable to make access
00088 from inline assembler easier. */
00089 //const unsigned long ulKernelPriority = configKERNEL_INTERRUPT_PRIORITY;
00090 
00091 /* Each task maintains its own interrupt status in the critical nesting
00092 variable. */
00093 #if 0
00094 static unsigned portBASE_TYPE uxCriticalNesting = 0xaaaaaaaa;
00095 #else
00096 unsigned portBASE_TYPE uxCriticalNesting = 0xaaaaaaaa;
00097 #endif
00098 /*
00099  * Setup the timer to generate the tick interrupts.
00100  */
00101 static void prvSetupTimerInterrupt( void );
00102 
00103 /*
00104  * Exception handlers.
00105  */
00106 #if 0
00107 void xPortPendSVHandler( void ) __attribute__ (( naked ));
00108 #else
00109 extern void xPortPendSVHandler( void );
00110 #endif
00111 void xPortSysTickHandler( void );
00112 #if 0
00113 void vPortSVCHandler( void ) __attribute__ (( naked ));
00114 #else
00115 extern void vPortSVCHandler( void );
00116 #endif
00117 
00118 /*
00119  * Start first task is a separate function so it can be tested in isolation.
00120  */
00121 #ifdef __cplusplus
00122 extern "C" {
00123 #endif
00124 #if 0
00125 void vPortStartFirstTask( void ) __attribute__ (( naked ));
00126 #else
00127 extern void vPortStartFirstTask( void );
00128 #endif
00129 #ifdef __cplusplus
00130 }
00131 #endif
00132 /*-----------------------------------------------------------*/
00133 
00134 /*
00135  * See header file for description.
00136  */
00137 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
00138 {
00139     /* Simulate the stack frame as it would be created by a context switch
00140     interrupt. */
00141     pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
00142     *pxTopOfStack = portINITIAL_XPSR;    /* xPSR */
00143     pxTopOfStack--;
00144     *pxTopOfStack = ( portSTACK_TYPE ) pxCode;    /* PC */
00145     pxTopOfStack--;
00146     *pxTopOfStack = 0;    /* LR */
00147     pxTopOfStack -= 5;    /* R12, R3, R2 and R1. */
00148     *pxTopOfStack = ( portSTACK_TYPE ) pvParameters;    /* R0 */
00149     pxTopOfStack -= 8;    /* R11, R10, R9, R8, R7, R6, R5 and R4. */
00150 
00151     return pxTopOfStack;
00152 }
00153 /*-----------------------------------------------------------*/
00154 
00155 #if 0
00156 void vPortSVCHandler( void )
00157 {
00158     __asm volatile (
00159                     "    ldr    r3, pxCurrentTCBConst2        \n" /* Restore the context. */
00160                     "    ldr r1, [r3]                    \n" /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */
00161                     "    ldr r0, [r1]                    \n" /* The first item in pxCurrentTCB is the task top of stack. */
00162                     "    ldmia r0!, {r4-r11}                \n" /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */
00163                     "    msr psp, r0                        \n" /* Restore the task stack pointer. */
00164                     "    mov r0, #0                         \n"
00165                     "    msr    basepri, r0                    \n"
00166                     "    orr r14, #0xd                    \n"
00167                     "    bx r14                            \n"
00168                     "                                    \n"
00169                     "    .align 2                        \n"
00170                     "pxCurrentTCBConst2: .word pxCurrentTCB                \n"
00171                 );
00172 }
00173 /*-----------------------------------------------------------*/
00174 #endif
00175 
00176 #if 0
00177 void vPortStartFirstTask( void )
00178 {
00179     __asm volatile(
00180                     " ldr r0, =0xE000ED08     \n" /* Use the NVIC offset register to locate the stack. */
00181                     " ldr r0, [r0]             \n"
00182                     " ldr r0, [r0]             \n"
00183                     " msr msp, r0            \n" /* Set the msp back to the start of the stack. */
00184                     " svc 0                    \n" /* System call to start first task. */
00185                 );
00186 }
00187 /*-----------------------------------------------------------*/
00188 #endif
00189 
00190 /*
00191  * See header file for description.
00192  */
00193 portBASE_TYPE xPortStartScheduler( void )
00194 {
00195     /* Make PendSV, CallSV and SysTick the same priroity as the kernel. */
00196     *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;
00197     *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;
00198 
00199     /* Start the timer that generates the tick ISR.  Interrupts are disabled
00200     here already. */
00201     prvSetupTimerInterrupt();
00202 
00203     /* Initialise the critical nesting count ready for the first task. */
00204     uxCriticalNesting = 0;
00205 
00206     /* Start the first task. */
00207     vPortStartFirstTask();
00208 
00209     /* Should not get here! */
00210     return 0;
00211 }
00212 /*-----------------------------------------------------------*/
00213 
00214 void vPortEndScheduler( void )
00215 {
00216     /* It is unlikely that the CM3 port will require this function as there
00217     is nothing to return to.  */
00218 }
00219 /*-----------------------------------------------------------*/
00220 
00221 void vPortYieldFromISR( void )
00222 {
00223     /* Set a PendSV to request a context switch. */
00224     *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
00225 }
00226 /*-----------------------------------------------------------*/
00227 
00228 #if 0
00229 void vPortEnterCritical( void )
00230 {
00231     portDISABLE_INTERRUPTS();
00232     uxCriticalNesting++;
00233 }
00234 /*-----------------------------------------------------------*/
00235 
00236 void vPortExitCritical( void )
00237 {
00238     uxCriticalNesting--;
00239     if( uxCriticalNesting == 0 )
00240     {
00241         portENABLE_INTERRUPTS();
00242     }
00243 }
00244 /*-----------------------------------------------------------*/
00245 
00246 
00247 void xPortPendSVHandler( void )
00248 {
00249     /* This is a naked function. */
00250 
00251     __asm volatile
00252     (
00253     "    mrs r0, psp                            \n"
00254     "                                        \n"
00255     "    ldr    r3, pxCurrentTCBConst            \n" /* Get the location of the current TCB. */
00256     "    ldr    r2, [r3]                        \n"
00257     "                                        \n"
00258     "    stmdb r0!, {r4-r11}                    \n" /* Save the remaining registers. */
00259     "    str r0, [r2]                        \n" /* Save the new top of stack into the first member of the TCB. */
00260     "                                        \n"
00261     "    stmdb sp!, {r3, r14}                \n"
00262     "    mov r0, %0                            \n"
00263     "    msr basepri, r0                        \n"
00264     "    bl vTaskSwitchContext                \n"
00265     "    mov r0, #0                            \n"
00266     "    msr basepri, r0                        \n"
00267     "    ldmia sp!, {r3, r14}                \n"
00268     "                                        \n"    /* Restore the context, including the critical nesting count. */
00269     "    ldr r1, [r3]                        \n"
00270     "    ldr r0, [r1]                        \n" /* The first item in pxCurrentTCB is the task top of stack. */
00271     "    ldmia r0!, {r4-r11}                    \n" /* Pop the registers. */
00272     "    msr psp, r0                            \n"
00273     "    bx r14                                \n"
00274     "                                        \n"
00275     "    .align 2                            \n"
00276     "pxCurrentTCBConst: .word pxCurrentTCB    \n"
00277     ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY)
00278     );
00279 }
00280 /*-----------------------------------------------------------*/
00281 
00282 void xPortSysTickHandler( void )
00283 {
00284 unsigned long ulDummy;
00285 
00286     /* If using preemption, also force a context switch. */
00287     #if configUSE_PREEMPTION == 1
00288         *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
00289     #endif
00290 
00291     // Modified by  Kenji Arai / JH1PJL, October 30th,2010
00292     ulDummy = 0;
00293     portSET_INTERRUPT_MASK_FROM_ISR();
00294     {
00295         vTaskIncrementTick();
00296     }
00297     portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );
00298 }
00299 /*-----------------------------------------------------------*/
00300 #endif
00301 
00302 /*
00303  * Setup the systick timer to generate the tick interrupts at the required
00304  * frequency.
00305  */
00306 void prvSetupTimerInterrupt( void )
00307 {
00308     /* Configure SysTick to interrupt at the requested rate. */
00309     *(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
00310     *(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE;
00311 }
00312 /*-----------------------------------------------------------*/
00313