Port of TI's CC3100 Websock camera demo. Using FreeRTOS, mbedTLS, also parts of Arducam for cams ov5642 and 0v2640. Can also use MT9D111. Work in progress. Be warned some parts maybe a bit flacky. This is for Seeed Arch max only, for an M3, see the demo for CM3 using the 0v5642 aducam mini.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers port.c Source File

port.c

00001 /*
00002     FreeRTOS V8.2.1 - Copyright (C) 2015 Real Time Engineers Ltd.
00003     All rights reserved
00004 
00005     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
00006 
00007     This file is part of the FreeRTOS distribution.
00008 
00009     FreeRTOS is free software; you can redistribute it and/or modify it under
00010     the terms of the GNU General Public License (version 2) as published by the
00011     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
00012 
00013     ***************************************************************************
00014     >>!   NOTE: The modification to the GPL is included to allow you to     !<<
00015     >>!   distribute a combined work that includes FreeRTOS without being   !<<
00016     >>!   obliged to provide the source code for proprietary components     !<<
00017     >>!   outside of the FreeRTOS kernel.                                   !<<
00018     ***************************************************************************
00019 
00020     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
00021     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00022     FOR A PARTICULAR PURPOSE.  Full license text is available on the following
00023     link: http://www.freertos.org/a00114.html
00024 
00025     ***************************************************************************
00026      *                                                                       *
00027      *    FreeRTOS provides completely free yet professionally developed,    *
00028      *    robust, strictly quality controlled, supported, and cross          *
00029      *    platform software that is more than just the market leader, it     *
00030      *    is the industry's de facto standard.                               *
00031      *                                                                       *
00032      *    Help yourself get started quickly while simultaneously helping     *
00033      *    to support the FreeRTOS project by purchasing a FreeRTOS           *
00034      *    tutorial book, reference manual, or both:                          *
00035      *    http://www.FreeRTOS.org/Documentation                              *
00036      *                                                                       *
00037     ***************************************************************************
00038 
00039     http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading
00040     the FAQ page "My application does not run, what could be wrong?".  Have you
00041     defined configASSERT()?
00042 
00043     http://www.FreeRTOS.org/support - In return for receiving this top quality
00044     embedded software for free we request you assist our global community by
00045     participating in the support forum.
00046 
00047     http://www.FreeRTOS.org/training - Investing in training allows your team to
00048     be as productive as possible as early as possible.  Now you can receive
00049     FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
00050     Ltd, and the world's leading authority on the world's leading RTOS.
00051 
00052     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
00053     including FreeRTOS+Trace - an indispensable productivity tool, a DOS
00054     compatible FAT file system, and our tiny thread aware UDP/IP stack.
00055 
00056     http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
00057     Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
00058 
00059     http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
00060     Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS
00061     licenses offer ticketed support, indemnification and commercial middleware.
00062 
00063     http://www.SafeRTOS.com - High Integrity Systems also provide a safety
00064     engineered and independently SIL3 certified version for use in safety and
00065     mission critical applications that require provable dependability.
00066 
00067     1 tab == 4 spaces!
00068 */
00069 
00070 /*-----------------------------------------------------------
00071  * Implementation of functions defined in portable.h for the ARM CM4F port.
00072  *----------------------------------------------------------*/
00073 
00074 /* Scheduler includes. */
00075 #include "FreeRTOS.h"
00076 #include "task.h"
00077 
00078 #ifndef __TARGET_FPU_VFP
00079     #error This port can only be used when the project options are configured to enable hardware floating point support.
00080 #endif
00081 
00082 #if configMAX_SYSCALL_INTERRUPT_PRIORITY == 0
00083     #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.  See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
00084 #endif
00085 
00086 #ifndef configSYSTICK_CLOCK_HZ
00087     #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
00088     /* Ensure the SysTick is clocked at the same frequency as the core. */
00089     #define portNVIC_SYSTICK_CLK_BIT    ( 1UL << 2UL )
00090 #else
00091     /* The way the SysTick is clocked is not modified in case it is not the same
00092     as the core. */
00093     #define portNVIC_SYSTICK_CLK_BIT    ( 0 )
00094 #endif
00095 
00096 /* The __weak attribute does not work as you might expect with the Keil tools
00097 so the configOVERRIDE_DEFAULT_TICK_CONFIGURATION constant must be set to 1 if
00098 the application writer wants to provide their own implementation of
00099 vPortSetupTimerInterrupt().  Ensure configOVERRIDE_DEFAULT_TICK_CONFIGURATION
00100 is defined. */
00101 #ifndef configOVERRIDE_DEFAULT_TICK_CONFIGURATION
00102     #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 0
00103 #endif
00104 
00105 /* Constants required to manipulate the core.  Registers first... */
00106 #define portNVIC_SYSTICK_CTRL_REG           ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
00107 #define portNVIC_SYSTICK_LOAD_REG           ( * ( ( volatile uint32_t * ) 0xe000e014 ) )
00108 #define portNVIC_SYSTICK_CURRENT_VALUE_REG  ( * ( ( volatile uint32_t * ) 0xe000e018 ) )
00109 #define portNVIC_SYSPRI2_REG                ( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
00110 /* ...then bits in the registers. */
00111 #define portNVIC_SYSTICK_INT_BIT            ( 1UL << 1UL )
00112 #define portNVIC_SYSTICK_ENABLE_BIT         ( 1UL << 0UL )
00113 #define portNVIC_SYSTICK_COUNT_FLAG_BIT     ( 1UL << 16UL )
00114 #define portNVIC_PENDSVCLEAR_BIT            ( 1UL << 27UL )
00115 #define portNVIC_PEND_SYSTICK_CLEAR_BIT     ( 1UL << 25UL )
00116 
00117 /* Constants used to detect a Cortex-M7 r0p1 core, which should use the ARM_CM7
00118 r0p1 port. */
00119 #define portCPUID                           ( * ( ( volatile uint32_t * ) 0xE000ed00 ) )
00120 #define portCORTEX_M7_r0p1_ID               ( 0x410FC271UL )
00121 #define portCORTEX_M7_r0p0_ID               ( 0x410FC270UL )
00122 
00123 #define portNVIC_PENDSV_PRI                 ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
00124 #define portNVIC_SYSTICK_PRI                ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
00125 
00126 /* Constants required to check the validity of an interrupt priority. */
00127 #define portFIRST_USER_INTERRUPT_NUMBER     ( 16 )
00128 #define portNVIC_IP_REGISTERS_OFFSET_16     ( 0xE000E3F0 )
00129 #define portAIRCR_REG                       ( * ( ( volatile uint32_t * ) 0xE000ED0C ) )
00130 #define portMAX_8_BIT_VALUE                 ( ( uint8_t ) 0xff )
00131 #define portTOP_BIT_OF_BYTE                 ( ( uint8_t ) 0x80 )
00132 #define portMAX_PRIGROUP_BITS               ( ( uint8_t ) 7 )
00133 #define portPRIORITY_GROUP_MASK             ( 0x07UL << 8UL )
00134 #define portPRIGROUP_SHIFT                  ( 8UL )
00135 
00136 /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */
00137 #define portVECTACTIVE_MASK                 ( 0xFFUL )
00138 
00139 /* Constants required to manipulate the VFP. */
00140 #define portFPCCR                   ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */
00141 #define portASPEN_AND_LSPEN_BITS    ( 0x3UL << 30UL )
00142 
00143 /* Constants required to set up the initial stack. */
00144 #define portINITIAL_XPSR            ( 0x01000000 )
00145 #define portINITIAL_EXEC_RETURN     ( 0xfffffffd )
00146 
00147 /* The systick is a 24-bit counter. */
00148 #define portMAX_24_BIT_NUMBER               ( 0xffffffUL )
00149 
00150 /* A fiddle factor to estimate the number of SysTick counts that would have
00151 occurred while the SysTick counter is stopped during tickless idle
00152 calculations. */
00153 #define portMISSED_COUNTS_FACTOR            ( 45UL )
00154 
00155 /* Each task maintains its own interrupt status in the critical nesting
00156 variable. */
00157 static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
00158 
00159 /*
00160  * Setup the timer to generate the tick interrupts.  The implementation in this
00161  * file is weak to allow application writers to change the timer used to
00162  * generate the tick interrupt.
00163  */
00164 void vPortSetupTimerInterrupt( void );
00165 
00166 /*
00167  * Exception handlers.
00168  */
00169 void xPortPendSVHandler( void );
00170 void xPortSysTickHandler( void );
00171 void vPortSVCHandler( void );
00172 
00173 /*
00174  * Start first task is a separate function so it can be tested in isolation.
00175  */
00176 static void prvStartFirstTask( void );
00177 
00178 /*
00179  * Functions defined in portasm.s to enable the VFP.
00180  */
00181 static void prvEnableVFP( void );
00182 
00183 /*
00184  * Used to catch tasks that attempt to return from their implementing function.
00185  */
00186 static void prvTaskExitError( void );
00187 
00188 /*-----------------------------------------------------------*/
00189 
00190 /*
00191  * The number of SysTick increments that make up one tick period.
00192  */
00193 #if configUSE_TICKLESS_IDLE == 1
00194     static uint32_t ulTimerCountsForOneTick = 0;
00195 #endif /* configUSE_TICKLESS_IDLE */
00196 
00197 /*
00198  * The maximum number of tick periods that can be suppressed is limited by the
00199  * 24 bit resolution of the SysTick timer.
00200  */
00201 #if configUSE_TICKLESS_IDLE == 1
00202     static uint32_t xMaximumPossibleSuppressedTicks = 0;
00203 #endif /* configUSE_TICKLESS_IDLE */
00204 
00205 /*
00206  * Compensate for the CPU cycles that pass while the SysTick is stopped (low
00207  * power functionality only.
00208  */
00209 #if configUSE_TICKLESS_IDLE == 1
00210     static uint32_t ulStoppedTimerCompensation = 0;
00211 #endif /* configUSE_TICKLESS_IDLE */
00212 
00213 /*
00214  * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
00215  * FreeRTOS API functions are not called from interrupts that have been assigned
00216  * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
00217  */
00218 #if ( configASSERT_DEFINED == 1 )
00219      static uint8_t ucMaxSysCallPriority = 0;
00220      static uint32_t ulMaxPRIGROUPValue = 0;
00221      static const volatile uint8_t * const pcInterruptPriorityRegisters = ( uint8_t * ) portNVIC_IP_REGISTERS_OFFSET_16;
00222 #endif /* configASSERT_DEFINED */
00223 
00224 /*-----------------------------------------------------------*/
00225 
00226 /*
00227  * See header file for description.
00228  */
00229 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
00230 {
00231     /* Simulate the stack frame as it would be created by a context switch
00232     interrupt. */
00233 
00234     /* Offset added to account for the way the MCU uses the stack on entry/exit
00235     of interrupts, and to ensure alignment. */
00236     pxTopOfStack--;
00237 
00238     *pxTopOfStack = portINITIAL_XPSR;   /* xPSR */
00239     pxTopOfStack--;
00240     *pxTopOfStack = ( StackType_t ) pxCode; /* PC */
00241     pxTopOfStack--;
00242     *pxTopOfStack = ( StackType_t ) prvTaskExitError;   /* LR */
00243 
00244     /* Save code space by skipping register initialisation. */
00245     pxTopOfStack -= 5;  /* R12, R3, R2 and R1. */
00246     *pxTopOfStack = ( StackType_t ) pvParameters;   /* R0 */
00247 
00248     /* A save method is being used that requires each task to maintain its
00249     own exec return value. */
00250     pxTopOfStack--;
00251     *pxTopOfStack = portINITIAL_EXEC_RETURN;
00252 
00253     pxTopOfStack -= 8;  /* R11, R10, R9, R8, R7, R6, R5 and R4. */
00254 
00255     return pxTopOfStack;
00256 }
00257 /*-----------------------------------------------------------*/
00258 
00259 static void prvTaskExitError( void )
00260 {
00261     /* A function that implements a task must not exit or attempt to return to
00262     its caller as there is nothing to return to.  If a task wants to exit it
00263     should instead call vTaskDelete( NULL ).
00264 
00265     Artificially force an assert() to be triggered if configASSERT() is
00266     defined, then stop here so application writers can catch the error. */
00267     configASSERT( uxCriticalNesting == ~0UL );
00268     portDISABLE_INTERRUPTS();
00269     for( ;; );
00270 }
00271 /*-----------------------------------------------------------*/
00272 
00273 __asm void vPortSVCHandler( void )
00274 {
00275     PRESERVE8
00276 
00277     /* Get the location of the current TCB. */
00278     ldr r3, =pxCurrentTCB
00279     ldr r1, [r3]
00280     ldr r0, [r1]
00281     /* Pop the core registers. */
00282     ldmia r0!, {r4-r11, r14}
00283     msr psp, r0
00284     isb
00285     mov r0, #0
00286     msr basepri, r0
00287     bx r14
00288 }
00289 /*-----------------------------------------------------------*/
00290 
00291 __asm void prvStartFirstTask( void )
00292 {
00293     PRESERVE8
00294 
00295     /* Use the NVIC offset register to locate the stack. */
00296     ldr r0, =0xE000ED08
00297     ldr r0, [r0]
00298     ldr r0, [r0]
00299     /* Set the msp back to the start of the stack. */
00300     msr msp, r0
00301     /* Globally enable interrupts. */
00302     cpsie i
00303     cpsie f
00304     dsb
00305     isb
00306     /* Call SVC to start the first task. */
00307     svc 0
00308     nop
00309     nop
00310 }
00311 /*-----------------------------------------------------------*/
00312 
00313 __asm void prvEnableVFP( void )
00314 {
00315     PRESERVE8
00316 
00317     /* The FPU enable bits are in the CPACR. */
00318     ldr.w r0, =0xE000ED88
00319     ldr r1, [r0]
00320 
00321     /* Enable CP10 and CP11 coprocessors, then save back. */
00322     orr r1, r1, #( 0xf << 20 )
00323     str r1, [r0]
00324     bx  r14
00325     nop
00326 }
00327 /*-----------------------------------------------------------*/
00328 
00329 /*
00330  * See header file for description.
00331  */
00332 BaseType_t xPortStartScheduler( void )
00333 {
00334     /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.
00335     See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
00336     configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
00337 
00338     /* This port can be used on all revisions of the Cortex-M7 core other than
00339     the r0p1 parts.  r0p1 parts should use the port from the
00340     /source/portable/GCC/ARM_CM7/r0p1 directory. */
00341     configASSERT( portCPUID != portCORTEX_M7_r0p1_ID );
00342     configASSERT( portCPUID != portCORTEX_M7_r0p0_ID );
00343 
00344     #if( configASSERT_DEFINED == 1 )
00345     {
00346         volatile uint32_t ulOriginalPriority;
00347         volatile uint8_t * const pucFirstUserPriorityRegister = ( uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
00348         volatile uint8_t ucMaxPriorityValue;
00349 
00350         /* Determine the maximum priority from which ISR safe FreeRTOS API
00351         functions can be called.  ISR safe functions are those that end in
00352         "FromISR".  FreeRTOS maintains separate thread and ISR API functions to
00353         ensure interrupt entry is as fast and simple as possible.
00354 
00355         Save the interrupt priority value that is about to be clobbered. */
00356         ulOriginalPriority = *pucFirstUserPriorityRegister;
00357 
00358         /* Determine the number of priority bits available.  First write to all
00359         possible bits. */
00360         *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
00361 
00362         /* Read the value back to see how many bits stuck. */
00363         ucMaxPriorityValue = *pucFirstUserPriorityRegister;
00364 
00365         /* The kernel interrupt priority should be set to the lowest
00366         priority. */
00367         configASSERT( ucMaxPriorityValue == ( configKERNEL_INTERRUPT_PRIORITY & ucMaxPriorityValue ) );
00368 
00369         /* Use the same mask on the maximum system call priority. */
00370         ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
00371 
00372         /* Calculate the maximum acceptable priority group value for the number
00373         of bits read back. */
00374         ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
00375         while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
00376         {
00377             ulMaxPRIGROUPValue--;
00378             ucMaxPriorityValue <<= ( uint8_t ) 0x01;
00379         }
00380 
00381         /* Shift the priority group value back to its position within the AIRCR
00382         register. */
00383         ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
00384         ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
00385 
00386         /* Restore the clobbered interrupt priority register to its original
00387         value. */
00388         *pucFirstUserPriorityRegister = ulOriginalPriority;
00389     }
00390     #endif /* conifgASSERT_DEFINED */
00391 
00392     /* Make PendSV and SysTick the lowest priority interrupts. */
00393     portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
00394     portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
00395 
00396     /* Start the timer that generates the tick ISR.  Interrupts are disabled
00397     here already. */
00398     vPortSetupTimerInterrupt();
00399 
00400     /* Initialise the critical nesting count ready for the first task. */
00401     uxCriticalNesting = 0;
00402 
00403     /* Ensure the VFP is enabled - it should be anyway. */
00404     prvEnableVFP();
00405 
00406     /* Lazy save always. */
00407     *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
00408 
00409     /* Start the first task. */
00410     prvStartFirstTask();
00411 
00412     /* Should not get here! */
00413     return 0;
00414 }
00415 /*-----------------------------------------------------------*/
00416 
00417 void vPortEndScheduler( void )
00418 {
00419     /* Not implemented in ports where there is nothing to return to.
00420     Artificially force an assert. */
00421     configASSERT( uxCriticalNesting == 1000UL );
00422 }
00423 /*-----------------------------------------------------------*/
00424 
00425 void vPortEnterCritical( void )
00426 {
00427     portDISABLE_INTERRUPTS();
00428     uxCriticalNesting++;
00429 
00430     /* This is not the interrupt safe version of the enter critical function so
00431     assert() if it is being called from an interrupt context.  Only API
00432     functions that end in "FromISR" can be used in an interrupt.  Only assert if
00433     the critical nesting count is 1 to protect against recursive calls if the
00434     assert function also uses a critical section. */
00435     if( uxCriticalNesting == 1 )
00436     {
00437         configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
00438     }
00439 }
00440 /*-----------------------------------------------------------*/
00441 
00442 void vPortExitCritical( void )
00443 {
00444     configASSERT( uxCriticalNesting );
00445     uxCriticalNesting--;
00446     if( uxCriticalNesting == 0 )
00447     {
00448         portENABLE_INTERRUPTS();
00449     }
00450 }
00451 /*-----------------------------------------------------------*/
00452 
00453 __asm void xPortPendSVHandler( void )
00454 {
00455     extern uxCriticalNesting;
00456     extern pxCurrentTCB;
00457     extern vTaskSwitchContext;
00458 
00459     PRESERVE8
00460 
00461     mrs r0, psp
00462     isb
00463     /* Get the location of the current TCB. */
00464     ldr r3, =pxCurrentTCB
00465     ldr r2, [r3]
00466 
00467     /* Is the task using the FPU context?  If so, push high vfp registers. */
00468     tst r14, #0x10
00469     it eq
00470     vstmdbeq r0!, {s16-s31}
00471 
00472     /* Save the core registers. */
00473     stmdb r0!, {r4-r11, r14}
00474 
00475     /* Save the new top of stack into the first member of the TCB. */
00476     str r0, [r2]
00477 
00478     stmdb sp!, {r3}
00479     mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
00480     msr basepri, r0
00481     dsb
00482     isb
00483     bl vTaskSwitchContext
00484     mov r0, #0
00485     msr basepri, r0
00486     ldmia sp!, {r3}
00487 
00488     /* The first item in pxCurrentTCB is the task top of stack. */
00489     ldr r1, [r3]
00490     ldr r0, [r1]
00491 
00492     /* Pop the core registers. */
00493     ldmia r0!, {r4-r11, r14}
00494 
00495     /* Is the task using the FPU context?  If so, pop the high vfp registers
00496     too. */
00497     tst r14, #0x10
00498     it eq
00499     vldmiaeq r0!, {s16-s31}
00500 
00501     msr psp, r0
00502     isb
00503     #ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */
00504         #if WORKAROUND_PMU_CM001 == 1
00505             push { r14 }
00506             pop { pc }
00507             nop
00508         #endif
00509     #endif
00510 
00511     bx r14
00512 }
00513 /*-----------------------------------------------------------*/
00514 
00515 void xPortSysTickHandler( void )
00516 {
00517     /* The SysTick runs at the lowest interrupt priority, so when this interrupt
00518     executes all interrupts must be unmasked.  There is therefore no need to
00519     save and then restore the interrupt mask value as its value is already
00520     known. */
00521     ( void ) portSET_INTERRUPT_MASK_FROM_ISR();
00522     {
00523         /* Increment the RTOS tick. */
00524         if( xTaskIncrementTick() != pdFALSE )
00525         {
00526             /* A context switch is required.  Context switching is performed in
00527             the PendSV interrupt.  Pend the PendSV interrupt. */
00528             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
00529         }
00530     }
00531     portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 );
00532 }
00533 /*-----------------------------------------------------------*/
00534 
00535 #if configUSE_TICKLESS_IDLE == 1
00536 
00537     __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
00538     {
00539     uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL;
00540     TickType_t xModifiableIdleTime;
00541 
00542         /* Make sure the SysTick reload value does not overflow the counter. */
00543         if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
00544         {
00545             xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
00546         }
00547 
00548         /* Stop the SysTick momentarily.  The time the SysTick is stopped for
00549         is accounted for as best it can be, but using the tickless mode will
00550         inevitably result in some tiny drift of the time maintained by the
00551         kernel with respect to calendar time. */
00552         portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
00553 
00554         /* Calculate the reload value required to wait xExpectedIdleTime
00555         tick periods.  -1 is used because this code will execute part way
00556         through one of the tick periods. */
00557         ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
00558         if( ulReloadValue > ulStoppedTimerCompensation )
00559         {
00560             ulReloadValue -= ulStoppedTimerCompensation;
00561         }
00562 
00563         /* Enter a critical section but don't use the taskENTER_CRITICAL()
00564         method as that will mask interrupts that should exit sleep mode. */
00565         __disable_irq();
00566 
00567         /* If a context switch is pending or a task is waiting for the scheduler
00568         to be unsuspended then abandon the low power entry. */
00569         if( eTaskConfirmSleepModeStatus() == eAbortSleep )
00570         {
00571             /* Restart from whatever is left in the count register to complete
00572             this tick period. */
00573             portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
00574 
00575             /* Restart SysTick. */
00576             portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
00577 
00578             /* Reset the reload register to the value required for normal tick
00579             periods. */
00580             portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
00581 
00582             /* Re-enable interrupts - see comments above __disable_irq() call
00583             above. */
00584             __enable_irq();
00585         }
00586         else
00587         {
00588             /* Set the new reload value. */
00589             portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
00590 
00591             /* Clear the SysTick count flag and set the count value back to
00592             zero. */
00593             portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
00594 
00595             /* Restart SysTick. */
00596             portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
00597 
00598             /* Sleep until something happens.  configPRE_SLEEP_PROCESSING() can
00599             set its parameter to 0 to indicate that its implementation contains
00600             its own wait for interrupt or wait for event instruction, and so wfi
00601             should not be executed again.  However, the original expected idle
00602             time variable must remain unmodified, so a copy is taken. */
00603             xModifiableIdleTime = xExpectedIdleTime;
00604             configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
00605             if( xModifiableIdleTime > 0 )
00606             {
00607                 __dsb( portSY_FULL_READ_WRITE );
00608                 __wfi();
00609                 __isb( portSY_FULL_READ_WRITE );
00610             }
00611             configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
00612 
00613             /* Stop SysTick.  Again, the time the SysTick is stopped for is
00614             accounted for as best it can be, but using the tickless mode will
00615             inevitably result in some tiny drift of the time maintained by the
00616             kernel with respect to calendar time. */
00617             ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
00618             portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
00619 
00620             /* Re-enable interrupts - see comments above __disable_irq() call
00621             above. */
00622             __enable_irq();
00623 
00624             if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
00625             {
00626                 uint32_t ulCalculatedLoadValue;
00627 
00628                 /* The tick interrupt has already executed, and the SysTick
00629                 count reloaded with ulReloadValue.  Reset the
00630                 portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
00631                 period. */
00632                 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
00633 
00634                 /* Don't allow a tiny value, or values that have somehow
00635                 underflowed because the post sleep hook did something
00636                 that took too long. */
00637                 if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
00638                 {
00639                     ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
00640                 }
00641 
00642                 portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
00643 
00644                 /* The tick interrupt handler will already have pended the tick
00645                 processing in the kernel.  As the pending tick will be
00646                 processed as soon as this function exits, the tick value
00647                 maintained by the tick is stepped forward by one less than the
00648                 time spent waiting. */
00649                 ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
00650             }
00651             else
00652             {
00653                 /* Something other than the tick interrupt ended the sleep.
00654                 Work out how long the sleep lasted rounded to complete tick
00655                 periods (not the ulReload value which accounted for part
00656                 ticks). */
00657                 ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
00658 
00659                 /* How many complete tick periods passed while the processor
00660                 was waiting? */
00661                 ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
00662 
00663                 /* The reload value is set to whatever fraction of a single tick
00664                 period remains. */
00665                 portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1 ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
00666             }
00667 
00668             /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
00669             again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
00670             value.  The critical section is used to ensure the tick interrupt
00671             can only execute once in the case that the reload register is near
00672             zero. */
00673             portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
00674             portENTER_CRITICAL();
00675             {
00676                 portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
00677                 vTaskStepTick( ulCompleteTickPeriods );
00678                 portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
00679             }
00680             portEXIT_CRITICAL();
00681         }
00682     }
00683 
00684 #endif /* #if configUSE_TICKLESS_IDLE */
00685 
00686 /*-----------------------------------------------------------*/
00687 
00688 /*
00689  * Setup the SysTick timer to generate the tick interrupts at the required
00690  * frequency.
00691  */
00692 #if configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0
00693 
00694     void vPortSetupTimerInterrupt( void )
00695     {
00696         /* Calculate the constants required to configure the tick interrupt. */
00697         #if configUSE_TICKLESS_IDLE == 1
00698         {
00699             ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
00700             xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
00701             ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
00702         }
00703         #endif /* configUSE_TICKLESS_IDLE */
00704 
00705         /* Configure SysTick to interrupt at the requested rate. */
00706         portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
00707         portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
00708     }
00709 
00710 #endif /* configOVERRIDE_DEFAULT_TICK_CONFIGURATION */
00711 /*-----------------------------------------------------------*/
00712 
00713 __asm uint32_t vPortGetIPSR( void )
00714 {
00715     PRESERVE8
00716 
00717     mrs r0, ipsr
00718     bx r14
00719 }
00720 /*-----------------------------------------------------------*/
00721 
00722 #if( configASSERT_DEFINED == 1 )
00723 
00724     void vPortValidateInterruptPriority( void )
00725     {
00726     uint32_t ulCurrentInterrupt;
00727     uint8_t ucCurrentPriority;
00728 
00729         /* Obtain the number of the currently executing interrupt. */
00730         ulCurrentInterrupt = vPortGetIPSR();
00731 
00732         /* Is the interrupt number a user defined interrupt? */
00733         if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
00734         {
00735             /* Look up the interrupt's priority. */
00736             ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
00737 
00738             /* The following assertion will fail if a service routine (ISR) for
00739             an interrupt that has been assigned a priority above
00740             configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
00741             function.  ISR safe FreeRTOS API functions must *only* be called
00742             from interrupts that have been assigned a priority at or below
00743             configMAX_SYSCALL_INTERRUPT_PRIORITY.
00744 
00745             Numerically low interrupt priority numbers represent logically high
00746             interrupt priorities, therefore the priority of the interrupt must
00747             be set to a value equal to or numerically *higher* than
00748             configMAX_SYSCALL_INTERRUPT_PRIORITY.
00749 
00750             Interrupts that use the FreeRTOS API must not be left at their
00751             default priority of zero as that is the highest possible priority,
00752             which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
00753             and therefore also guaranteed to be invalid.
00754 
00755             FreeRTOS maintains separate thread and ISR API functions to ensure
00756             interrupt entry is as fast and simple as possible.
00757 
00758             The following links provide detailed information:
00759             http://www.freertos.org/RTOS-Cortex-M3-M4.html
00760             http://www.freertos.org/FAQHelp.html */
00761             configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
00762         }
00763 
00764         /* Priority grouping:  The interrupt controller (NVIC) allows the bits
00765         that define each interrupt's priority to be split between bits that
00766         define the interrupt's pre-emption priority bits and bits that define
00767         the interrupt's sub-priority.  For simplicity all bits must be defined
00768         to be pre-emption priority bits.  The following assertion will fail if
00769         this is not the case (if some bits represent a sub-priority).
00770 
00771         If the application only uses CMSIS libraries for interrupt
00772         configuration then the correct setting can be achieved on all Cortex-M
00773         devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
00774         scheduler.  Note however that some vendor specific peripheral libraries
00775         assume a non-zero priority group setting, in which cases using a value
00776         of zero will result in unpredicable behaviour. */
00777         configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
00778     }
00779 
00780 #endif /* configASSERT_DEFINED */
00781 
00782 
00783