]> begriffs open source - freertos/blob - portable/RVDS/ARM_CM7/r0p1/port.c
Style: Revert uncrustify for portable directories (#122)
[freertos] / portable / RVDS / ARM_CM7 / r0p1 / port.c
1 /*\r
2  * FreeRTOS Kernel V10.3.1\r
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 /*-----------------------------------------------------------\r
29 * Implementation of functions defined in portable.h for the ARM CM7 port.\r
30 *----------------------------------------------------------*/\r
31 \r
32 /* Scheduler includes. */\r
33 #include "FreeRTOS.h"\r
34 #include "task.h"\r
35 \r
36 #ifndef __TARGET_FPU_VFP\r
37     #error This port can only be used when the project options are configured to enable hardware floating point support.\r
38 #endif\r
39 \r
40 #if configMAX_SYSCALL_INTERRUPT_PRIORITY == 0\r
41     #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.  See http: /*www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */\r
42 #endif\r
43 \r
44 #ifndef configSYSTICK_CLOCK_HZ\r
45     #define configSYSTICK_CLOCK_HZ      configCPU_CLOCK_HZ\r
46     /* Ensure the SysTick is clocked at the same frequency as the core. */\r
47     #define portNVIC_SYSTICK_CLK_BIT    ( 1UL << 2UL )\r
48 #else\r
49 \r
50 /* The way the SysTick is clocked is not modified in case it is not the same\r
51  * as the core. */\r
52     #define portNVIC_SYSTICK_CLK_BIT    ( 0 )\r
53 #endif\r
54 \r
55 /* The __weak attribute does not work as you might expect with the Keil tools\r
56  * so the configOVERRIDE_DEFAULT_TICK_CONFIGURATION constant must be set to 1 if\r
57  * the application writer wants to provide their own implementation of\r
58  * vPortSetupTimerInterrupt().  Ensure configOVERRIDE_DEFAULT_TICK_CONFIGURATION\r
59  * is defined. */\r
60 #ifndef configOVERRIDE_DEFAULT_TICK_CONFIGURATION\r
61     #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION    0\r
62 #endif\r
63 \r
64 /* Constants required to manipulate the core.  Registers first... */\r
65 #define portNVIC_SYSTICK_CTRL_REG             ( *( ( volatile uint32_t * ) 0xe000e010 ) )\r
66 #define portNVIC_SYSTICK_LOAD_REG             ( *( ( volatile uint32_t * ) 0xe000e014 ) )\r
67 #define portNVIC_SYSTICK_CURRENT_VALUE_REG    ( *( ( volatile uint32_t * ) 0xe000e018 ) )\r
68 #define portNVIC_SHPR3_REG                    ( *( ( volatile uint32_t * ) 0xe000ed20 ) )\r
69 /* ...then bits in the registers. */\r
70 #define portNVIC_SYSTICK_INT_BIT              ( 1UL << 1UL )\r
71 #define portNVIC_SYSTICK_ENABLE_BIT           ( 1UL << 0UL )\r
72 #define portNVIC_SYSTICK_COUNT_FLAG_BIT       ( 1UL << 16UL )\r
73 #define portNVIC_PENDSVCLEAR_BIT              ( 1UL << 27UL )\r
74 #define portNVIC_PEND_SYSTICK_CLEAR_BIT       ( 1UL << 25UL )\r
75 \r
76 #define portNVIC_PENDSV_PRI                   ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )\r
77 #define portNVIC_SYSTICK_PRI                  ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )\r
78 \r
79 /* Constants required to check the validity of an interrupt priority. */\r
80 #define portFIRST_USER_INTERRUPT_NUMBER       ( 16 )\r
81 #define portNVIC_IP_REGISTERS_OFFSET_16       ( 0xE000E3F0 )\r
82 #define portAIRCR_REG                         ( *( ( volatile uint32_t * ) 0xE000ED0C ) )\r
83 #define portMAX_8_BIT_VALUE                   ( ( uint8_t ) 0xff )\r
84 #define portTOP_BIT_OF_BYTE                   ( ( uint8_t ) 0x80 )\r
85 #define portMAX_PRIGROUP_BITS                 ( ( uint8_t ) 7 )\r
86 #define portPRIORITY_GROUP_MASK               ( 0x07UL << 8UL )\r
87 #define portPRIGROUP_SHIFT                    ( 8UL )\r
88 \r
89 /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */\r
90 #define portVECTACTIVE_MASK                   ( 0xFFUL )\r
91 \r
92 /* Constants required to manipulate the VFP. */\r
93 #define portFPCCR                             ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */\r
94 #define portASPEN_AND_LSPEN_BITS              ( 0x3UL << 30UL )\r
95 \r
96 /* Constants required to set up the initial stack. */\r
97 #define portINITIAL_XPSR                      ( 0x01000000 )\r
98 #define portINITIAL_EXC_RETURN                ( 0xfffffffd )\r
99 \r
100 /* The systick is a 24-bit counter. */\r
101 #define portMAX_24_BIT_NUMBER                 ( 0xffffffUL )\r
102 \r
103 /* A fiddle factor to estimate the number of SysTick counts that would have\r
104  * occurred while the SysTick counter is stopped during tickless idle\r
105  * calculations. */\r
106 #define portMISSED_COUNTS_FACTOR              ( 45UL )\r
107 \r
108 /* For strict compliance with the Cortex-M spec the task start address should\r
109  * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */\r
110 #define portSTART_ADDRESS_MASK                ( ( StackType_t ) 0xfffffffeUL )\r
111 \r
112 /*\r
113  * Setup the timer to generate the tick interrupts.  The implementation in this\r
114  * file is weak to allow application writers to change the timer used to\r
115  * generate the tick interrupt.\r
116  */\r
117 void vPortSetupTimerInterrupt( void );\r
118 \r
119 /*\r
120  * Exception handlers.\r
121  */\r
122 void xPortPendSVHandler( void );\r
123 void xPortSysTickHandler( void );\r
124 void vPortSVCHandler( void );\r
125 \r
126 /*\r
127  * Start first task is a separate function so it can be tested in isolation.\r
128  */\r
129 static void prvStartFirstTask( void );\r
130 \r
131 /*\r
132  * Functions defined in portasm.s to enable the VFP.\r
133  */\r
134 static void prvEnableVFP( void );\r
135 \r
136 /*\r
137  * Used to catch tasks that attempt to return from their implementing function.\r
138  */\r
139 static void prvTaskExitError( void );\r
140 \r
141 /*-----------------------------------------------------------*/\r
142 \r
143 /* Each task maintains its own interrupt status in the critical nesting\r
144  * variable. */\r
145 static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;\r
146 \r
147 /*\r
148  * The number of SysTick increments that make up one tick period.\r
149  */\r
150 #if ( configUSE_TICKLESS_IDLE == 1 )\r
151     static uint32_t ulTimerCountsForOneTick = 0;\r
152 #endif /* configUSE_TICKLESS_IDLE */\r
153 \r
154 /*\r
155  * The maximum number of tick periods that can be suppressed is limited by the\r
156  * 24 bit resolution of the SysTick timer.\r
157  */\r
158 #if ( configUSE_TICKLESS_IDLE == 1 )\r
159     static uint32_t xMaximumPossibleSuppressedTicks = 0;\r
160 #endif /* configUSE_TICKLESS_IDLE */\r
161 \r
162 /*\r
163  * Compensate for the CPU cycles that pass while the SysTick is stopped (low\r
164  * power functionality only.\r
165  */\r
166 #if ( configUSE_TICKLESS_IDLE == 1 )\r
167     static uint32_t ulStoppedTimerCompensation = 0;\r
168 #endif /* configUSE_TICKLESS_IDLE */\r
169 \r
170 /*\r
171  * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure\r
172  * FreeRTOS API functions are not called from interrupts that have been assigned\r
173  * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
174  */\r
175 #if ( configASSERT_DEFINED == 1 )\r
176     static uint8_t ucMaxSysCallPriority = 0;\r
177     static uint32_t ulMaxPRIGROUPValue = 0;\r
178     static const volatile uint8_t * const pcInterruptPriorityRegisters = ( uint8_t * ) portNVIC_IP_REGISTERS_OFFSET_16;\r
179 #endif /* configASSERT_DEFINED */\r
180 \r
181 /*-----------------------------------------------------------*/\r
182 \r
183 /*\r
184  * See header file for description.\r
185  */\r
186 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,\r
187                                      TaskFunction_t pxCode,\r
188                                      void * pvParameters )\r
189 {\r
190     /* Simulate the stack frame as it would be created by a context switch\r
191      * interrupt. */\r
192 \r
193     /* Offset added to account for the way the MCU uses the stack on entry/exit\r
194      * of interrupts, and to ensure alignment. */\r
195     pxTopOfStack--;\r
196 \r
197     *pxTopOfStack = portINITIAL_XPSR;                                    /* xPSR */\r
198     pxTopOfStack--;\r
199     *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */\r
200     pxTopOfStack--;\r
201     *pxTopOfStack = ( StackType_t ) prvTaskExitError;                    /* LR */\r
202 \r
203     /* Save code space by skipping register initialisation. */\r
204     pxTopOfStack -= 5;                            /* R12, R3, R2 and R1. */\r
205     *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */\r
206 \r
207     /* A save method is being used that requires each task to maintain its\r
208      * own exec return value. */\r
209     pxTopOfStack--;\r
210     *pxTopOfStack = portINITIAL_EXC_RETURN;\r
211 \r
212     pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */\r
213 \r
214     return pxTopOfStack;\r
215 }\r
216 /*-----------------------------------------------------------*/\r
217 \r
218 static void prvTaskExitError( void )\r
219 {\r
220     /* A function that implements a task must not exit or attempt to return to\r
221      * its caller as there is nothing to return to.  If a task wants to exit it\r
222      * should instead call vTaskDelete( NULL ).\r
223      *\r
224      * Artificially force an assert() to be triggered if configASSERT() is\r
225      * defined, then stop here so application writers can catch the error. */\r
226     configASSERT( uxCriticalNesting == ~0UL );\r
227     portDISABLE_INTERRUPTS();\r
228 \r
229     for( ; ; )\r
230     {\r
231     }\r
232 }\r
233 /*-----------------------------------------------------------*/\r
234 \r
235 __asm void vPortSVCHandler( void )\r
236 {\r
237     PRESERVE8\r
238 \r
239 /* *INDENT-OFF* */\r
240     /* Get the location of the current TCB. */\r
241     ldr r3, =pxCurrentTCB\r
242     ldr r1, [ r3 ]\r
243     ldr r0, [ r1 ]\r
244     /* Pop the core registers. */\r
245     ldmia r0 !, {\r
246         r4 - r11, r14\r
247     }\r
248     msr psp, r0\r
249     isb\r
250     mov r0, #0\r
251     msr basepri, r0\r
252     bx r14\r
253 /* *INDENT-ON* */\r
254 }\r
255 /*-----------------------------------------------------------*/\r
256 \r
257 __asm void prvStartFirstTask( void )\r
258 {\r
259 /* *INDENT-OFF* */\r
260     PRESERVE8\r
261 \r
262     /* Use the NVIC offset register to locate the stack. */\r
263     ldr r0, =0xE000ED08\r
264     ldr r0, [ r0 ]\r
265     ldr r0, [ r0 ]\r
266     /* Set the msp back to the start of the stack. */\r
267     msr msp, r0\r
268 \r
269     /* Clear the bit that indicates the FPU is in use in case the FPU was used\r
270      * before the scheduler was started - which would otherwise result in the\r
271      * unnecessary leaving of space in the SVC stack for lazy saving of FPU\r
272      * registers. */\r
273     mov r0, #0\r
274     msr control, r0\r
275     /* Globally enable interrupts. */\r
276     cpsie i\r
277     cpsie f\r
278     dsb\r
279     isb\r
280     /* Call SVC to start the first task. */\r
281         svc 0\r
282     nop\r
283     nop\r
284 /* *INDENT-ON* */\r
285 }\r
286 /*-----------------------------------------------------------*/\r
287 \r
288 __asm void prvEnableVFP( void )\r
289 {\r
290 /* *INDENT-OFF* */\r
291     PRESERVE8\r
292 \r
293     /* The FPU enable bits are in the CPACR. */\r
294     ldr.w r0, =0xE000ED88\r
295     ldr r1, [ r0 ]\r
296 \r
297     /* Enable CP10 and CP11 coprocessors, then save back. */\r
298     orr r1, r1, #( 0xf << 20 )\r
299     str r1, [ r0 ]\r
300     bx r14\r
301     nop\r
302 /* *INDENT-ON* */\r
303 }\r
304 /*-----------------------------------------------------------*/\r
305 \r
306 /*\r
307  * See header file for description.\r
308  */\r
309 BaseType_t xPortStartScheduler( void )\r
310 {\r
311     #if ( configASSERT_DEFINED == 1 )\r
312         {\r
313             volatile uint32_t ulOriginalPriority;\r
314             volatile uint8_t * const pucFirstUserPriorityRegister = ( uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );\r
315             volatile uint8_t ucMaxPriorityValue;\r
316 \r
317             /* Determine the maximum priority from which ISR safe FreeRTOS API\r
318              * functions can be called.  ISR safe functions are those that end in\r
319              * "FromISR".  FreeRTOS maintains separate thread and ISR API functions to\r
320              * ensure interrupt entry is as fast and simple as possible.\r
321              *\r
322              * Save the interrupt priority value that is about to be clobbered. */\r
323             ulOriginalPriority = *pucFirstUserPriorityRegister;\r
324 \r
325             /* Determine the number of priority bits available.  First write to all\r
326              * possible bits. */\r
327             *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;\r
328 \r
329             /* Read the value back to see how many bits stuck. */\r
330             ucMaxPriorityValue = *pucFirstUserPriorityRegister;\r
331 \r
332             /* The kernel interrupt priority should be set to the lowest\r
333              * priority. */\r
334             configASSERT( ucMaxPriorityValue == ( configKERNEL_INTERRUPT_PRIORITY & ucMaxPriorityValue ) );\r
335 \r
336             /* Use the same mask on the maximum system call priority. */\r
337             ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;\r
338 \r
339             /* Calculate the maximum acceptable priority group value for the number\r
340              * of bits read back. */\r
341             ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;\r
342 \r
343             while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )\r
344             {\r
345                 ulMaxPRIGROUPValue--;\r
346                 ucMaxPriorityValue <<= ( uint8_t ) 0x01;\r
347             }\r
348 \r
349             #ifdef __NVIC_PRIO_BITS\r
350                 {\r
351                     /* Check the CMSIS configuration that defines the number of\r
352                      * priority bits matches the number of priority bits actually queried\r
353                      * from the hardware. */\r
354                     configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );\r
355                 }\r
356             #endif\r
357 \r
358             #ifdef configPRIO_BITS\r
359                 {\r
360                     /* Check the FreeRTOS configuration that defines the number of\r
361                      * priority bits matches the number of priority bits actually queried\r
362                      * from the hardware. */\r
363                     configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );\r
364                 }\r
365             #endif\r
366 \r
367             /* Shift the priority group value back to its position within the AIRCR\r
368              * register. */\r
369             ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;\r
370             ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;\r
371 \r
372             /* Restore the clobbered interrupt priority register to its original\r
373              * value. */\r
374             *pucFirstUserPriorityRegister = ulOriginalPriority;\r
375         }\r
376     #endif /* conifgASSERT_DEFINED */\r
377 \r
378     /* Make PendSV and SysTick the lowest priority interrupts. */\r
379     portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;\r
380 \r
381     portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;\r
382 \r
383     /* Start the timer that generates the tick ISR.  Interrupts are disabled\r
384      * here already. */\r
385     vPortSetupTimerInterrupt();\r
386 \r
387     /* Initialise the critical nesting count ready for the first task. */\r
388     uxCriticalNesting = 0;\r
389 \r
390     /* Ensure the VFP is enabled - it should be anyway. */\r
391     prvEnableVFP();\r
392 \r
393     /* Lazy save always. */\r
394     *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;\r
395 \r
396     /* Start the first task. */\r
397     prvStartFirstTask();\r
398 \r
399     /* Should not get here! */\r
400     return 0;\r
401 }\r
402 /*-----------------------------------------------------------*/\r
403 \r
404 void vPortEndScheduler( void )\r
405 {\r
406     /* Not implemented in ports where there is nothing to return to.\r
407      * Artificially force an assert. */\r
408     configASSERT( uxCriticalNesting == 1000UL );\r
409 }\r
410 /*-----------------------------------------------------------*/\r
411 \r
412 void vPortEnterCritical( void )\r
413 {\r
414     portDISABLE_INTERRUPTS();\r
415     uxCriticalNesting++;\r
416 \r
417     /* This is not the interrupt safe version of the enter critical function so\r
418      * assert() if it is being called from an interrupt context.  Only API\r
419      * functions that end in "FromISR" can be used in an interrupt.  Only assert if\r
420      * the critical nesting count is 1 to protect against recursive calls if the\r
421      * assert function also uses a critical section. */\r
422     if( uxCriticalNesting == 1 )\r
423     {\r
424         configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );\r
425     }\r
426 }\r
427 /*-----------------------------------------------------------*/\r
428 \r
429 void vPortExitCritical( void )\r
430 {\r
431     configASSERT( uxCriticalNesting );\r
432     uxCriticalNesting--;\r
433 \r
434     if( uxCriticalNesting == 0 )\r
435     {\r
436         portENABLE_INTERRUPTS();\r
437     }\r
438 }\r
439 /*-----------------------------------------------------------*/\r
440 \r
441 __asm void xPortPendSVHandler( void )\r
442 {\r
443     extern uxCriticalNesting;\r
444     extern pxCurrentTCB;\r
445     extern vTaskSwitchContext;\r
446 \r
447 /* *INDENT-OFF* */\r
448     PRESERVE8\r
449 \r
450     mrs r0, psp\r
451     isb\r
452     /* Get the location of the current TCB. */\r
453     ldr r3, =pxCurrentTCB\r
454     ldr r2, [ r3 ]\r
455 \r
456     /* Is the task using the FPU context?  If so, push high vfp registers. */\r
457     tst r14, #0x10\r
458     it eq\r
459     vstmdbeq r0 !, {\r
460         s16 - s31\r
461     }\r
462 \r
463     /* Save the core registers. */\r
464     stmdb r0 !, {\r
465         r4 - r11, r14\r
466     }\r
467 \r
468     /* Save the new top of stack into the first member of the TCB. */\r
469     str r0, [ r2 ]\r
470 \r
471     stmdb sp !, {\r
472         r0, r3\r
473     }\r
474     mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY\r
475     cpsid i\r
476     msr basepri, r0\r
477     dsb\r
478     isb\r
479     cpsie i\r
480     bl vTaskSwitchContext\r
481     mov r0, #0\r
482     msr basepri, r0\r
483     ldmia sp !, {\r
484         r0, r3\r
485     }\r
486 \r
487     /* The first item in pxCurrentTCB is the task top of stack. */\r
488     ldr r1, [ r3 ]\r
489     ldr r0, [ r1 ]\r
490 \r
491     /* Pop the core registers. */\r
492     ldmia r0 !, {\r
493         r4 - r11, r14\r
494     }\r
495 \r
496     /* Is the task using the FPU context?  If so, pop the high vfp registers\r
497      * too. */\r
498     tst r14, #0x10\r
499     it eq\r
500     vldmiaeq r0 !, {\r
501         s16 - s31\r
502     }\r
503 \r
504     msr psp, r0\r
505     isb\r
506     #ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */\r
507         #if WORKAROUND_PMU_CM001 == 1\r
508             push {\r
509                 r14\r
510             }\r
511             pop {\r
512                 pc\r
513             }\r
514             nop\r
515         #endif\r
516     #endif\r
517 \r
518     bx r14\r
519 /* *INDENT-ON* */\r
520 }\r
521 /*-----------------------------------------------------------*/\r
522 \r
523 void xPortSysTickHandler( void )\r
524 {\r
525     /* The SysTick runs at the lowest interrupt priority, so when this interrupt\r
526      * executes all interrupts must be unmasked.  There is therefore no need to\r
527      * save and then restore the interrupt mask value as its value is already\r
528      * known - therefore the slightly faster vPortRaiseBASEPRI() function is used\r
529      * in place of portSET_INTERRUPT_MASK_FROM_ISR(). */\r
530     vPortRaiseBASEPRI();\r
531     {\r
532         /* Increment the RTOS tick. */\r
533         if( xTaskIncrementTick() != pdFALSE )\r
534         {\r
535             /* A context switch is required.  Context switching is performed in\r
536              * the PendSV interrupt.  Pend the PendSV interrupt. */\r
537             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;\r
538         }\r
539     }\r
540 \r
541     vPortClearBASEPRIFromISR();\r
542 }\r
543 /*-----------------------------------------------------------*/\r
544 \r
545 #if ( configUSE_TICKLESS_IDLE == 1 )\r
546 \r
547     __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )\r
548     {\r
549         uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;\r
550         TickType_t xModifiableIdleTime;\r
551 \r
552         /* Make sure the SysTick reload value does not overflow the counter. */\r
553         if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )\r
554         {\r
555             xExpectedIdleTime = xMaximumPossibleSuppressedTicks;\r
556         }\r
557 \r
558         /* Stop the SysTick momentarily.  The time the SysTick is stopped for\r
559          * is accounted for as best it can be, but using the tickless mode will\r
560          * inevitably result in some tiny drift of the time maintained by the\r
561          * kernel with respect to calendar time. */\r
562         portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;\r
563 \r
564         /* Calculate the reload value required to wait xExpectedIdleTime\r
565          * tick periods.  -1 is used because this code will execute part way\r
566          * through one of the tick periods. */\r
567         ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );\r
568 \r
569         if( ulReloadValue > ulStoppedTimerCompensation )\r
570         {\r
571             ulReloadValue -= ulStoppedTimerCompensation;\r
572         }\r
573 \r
574         /* Enter a critical section but don't use the taskENTER_CRITICAL()\r
575          * method as that will mask interrupts that should exit sleep mode. */\r
576         __disable_irq();\r
577         __dsb( portSY_FULL_READ_WRITE );\r
578         __isb( portSY_FULL_READ_WRITE );\r
579 \r
580         /* If a context switch is pending or a task is waiting for the scheduler\r
581          * to be unsuspended then abandon the low power entry. */\r
582         if( eTaskConfirmSleepModeStatus() == eAbortSleep )\r
583         {\r
584             /* Restart from whatever is left in the count register to complete\r
585              * this tick period. */\r
586             portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;\r
587 \r
588             /* Restart SysTick. */\r
589             portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;\r
590 \r
591             /* Reset the reload register to the value required for normal tick\r
592              * periods. */\r
593             portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;\r
594 \r
595             /* Re-enable interrupts - see comments above __disable_irq() call\r
596              * above. */\r
597             __enable_irq();\r
598         }\r
599         else\r
600         {\r
601             /* Set the new reload value. */\r
602             portNVIC_SYSTICK_LOAD_REG = ulReloadValue;\r
603 \r
604             /* Clear the SysTick count flag and set the count value back to\r
605              * zero. */\r
606             portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;\r
607 \r
608             /* Restart SysTick. */\r
609             portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;\r
610 \r
611             /* Sleep until something happens.  configPRE_SLEEP_PROCESSING() can\r
612              * set its parameter to 0 to indicate that its implementation contains\r
613              * its own wait for interrupt or wait for event instruction, and so wfi\r
614              * should not be executed again.  However, the original expected idle\r
615              * time variable must remain unmodified, so a copy is taken. */\r
616             xModifiableIdleTime = xExpectedIdleTime;\r
617             configPRE_SLEEP_PROCESSING( xModifiableIdleTime );\r
618 \r
619             if( xModifiableIdleTime > 0 )\r
620             {\r
621                 __dsb( portSY_FULL_READ_WRITE );\r
622                 __wfi();\r
623                 __isb( portSY_FULL_READ_WRITE );\r
624             }\r
625 \r
626             configPOST_SLEEP_PROCESSING( xExpectedIdleTime );\r
627 \r
628             /* Re-enable interrupts to allow the interrupt that brought the MCU\r
629              * out of sleep mode to execute immediately.  see comments above\r
630              * __disable_interrupt() call above. */\r
631             __enable_irq();\r
632             __dsb( portSY_FULL_READ_WRITE );\r
633             __isb( portSY_FULL_READ_WRITE );\r
634 \r
635             /* Disable interrupts again because the clock is about to be stopped\r
636              * and interrupts that execute while the clock is stopped will increase\r
637              * any slippage between the time maintained by the RTOS and calendar\r
638              * time. */\r
639             __disable_irq();\r
640             __dsb( portSY_FULL_READ_WRITE );\r
641             __isb( portSY_FULL_READ_WRITE );\r
642 \r
643             /* Disable the SysTick clock without reading the\r
644              * portNVIC_SYSTICK_CTRL_REG register to ensure the\r
645              * portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set.  Again,\r
646              * the time the SysTick is stopped for is accounted for as best it can\r
647              * be, but using the tickless mode will inevitably result in some tiny\r
648              * drift of the time maintained by the kernel with respect to calendar\r
649              * time*/\r
650             portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );\r
651 \r
652             /* Determine if the SysTick clock has already counted to zero and\r
653              * been set back to the current reload value (the reload back being\r
654              * correct for the entire expected idle time) or if the SysTick is yet\r
655              * to count to zero (in which case an interrupt other than the SysTick\r
656              * must have brought the system out of sleep mode). */\r
657             if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )\r
658             {\r
659                 uint32_t ulCalculatedLoadValue;\r
660 \r
661                 /* The tick interrupt is already pending, and the SysTick count\r
662                  * reloaded with ulReloadValue.  Reset the\r
663                  * portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick\r
664                  * period. */\r
665                 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );\r
666 \r
667                 /* Don't allow a tiny value, or values that have somehow\r
668                  * underflowed because the post sleep hook did something\r
669                  * that took too long. */\r
670                 if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )\r
671                 {\r
672                     ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );\r
673                 }\r
674 \r
675                 portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;\r
676 \r
677                 /* As the pending tick will be processed as soon as this\r
678                  * function exits, the tick value maintained by the tick is stepped\r
679                  * forward by one less than the time spent waiting. */\r
680                 ulCompleteTickPeriods = xExpectedIdleTime - 1UL;\r
681             }\r
682             else\r
683             {\r
684                 /* Something other than the tick interrupt ended the sleep.\r
685                  * Work out how long the sleep lasted rounded to complete tick\r
686                  * periods (not the ulReload value which accounted for part\r
687                  * ticks). */\r
688                 ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;\r
689 \r
690                 /* How many complete tick periods passed while the processor\r
691                  * was waiting? */\r
692                 ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;\r
693 \r
694                 /* The reload value is set to whatever fraction of a single tick\r
695                  * period remains. */\r
696                 portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;\r
697             }\r
698 \r
699             /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG\r
700              * again, then set portNVIC_SYSTICK_LOAD_REG back to its standard\r
701              * value. */\r
702             portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;\r
703             portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;\r
704             vTaskStepTick( ulCompleteTickPeriods );\r
705             portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;\r
706 \r
707             /* Exit with interrupts enabled. */\r
708             __enable_irq();\r
709         }\r
710     }\r
711 \r
712 #endif /* #if configUSE_TICKLESS_IDLE */\r
713 \r
714 /*-----------------------------------------------------------*/\r
715 \r
716 /*\r
717  * Setup the SysTick timer to generate the tick interrupts at the required\r
718  * frequency.\r
719  */\r
720 #if ( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 )\r
721 \r
722     __weak void vPortSetupTimerInterrupt( void )\r
723     {\r
724         /* Calculate the constants required to configure the tick interrupt. */\r
725         #if ( configUSE_TICKLESS_IDLE == 1 )\r
726             {\r
727                 ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );\r
728                 xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;\r
729                 ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );\r
730             }\r
731         #endif /* configUSE_TICKLESS_IDLE */\r
732 \r
733         /* Stop and clear the SysTick. */\r
734         portNVIC_SYSTICK_CTRL_REG = 0UL;\r
735         portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;\r
736 \r
737         /* Configure SysTick to interrupt at the requested rate. */\r
738         portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;\r
739         portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );\r
740     }\r
741 \r
742 #endif /* configOVERRIDE_DEFAULT_TICK_CONFIGURATION */\r
743 /*-----------------------------------------------------------*/\r
744 \r
745 __asm uint32_t vPortGetIPSR( void )\r
746 {\r
747 /* *INDENT-OFF* */\r
748     PRESERVE8\r
749 \r
750     mrs r0, ipsr\r
751     bx r14\r
752 /* *INDENT-ON* */\r
753 }\r
754 /*-----------------------------------------------------------*/\r
755 \r
756 #if ( configASSERT_DEFINED == 1 )\r
757 \r
758     void vPortValidateInterruptPriority( void )\r
759     {\r
760         uint32_t ulCurrentInterrupt;\r
761         uint8_t ucCurrentPriority;\r
762 \r
763         /* Obtain the number of the currently executing interrupt. */\r
764         ulCurrentInterrupt = vPortGetIPSR();\r
765 \r
766         /* Is the interrupt number a user defined interrupt? */\r
767         if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )\r
768         {\r
769             /* Look up the interrupt's priority. */\r
770             ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];\r
771 \r
772             /* The following assertion will fail if a service routine (ISR) for\r
773              * an interrupt that has been assigned a priority above\r
774              * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API\r
775              * function.  ISR safe FreeRTOS API functions must *only* be called\r
776              * from interrupts that have been assigned a priority at or below\r
777              * configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
778              *\r
779              * Numerically low interrupt priority numbers represent logically high\r
780              * interrupt priorities, therefore the priority of the interrupt must\r
781              * be set to a value equal to or numerically *higher* than\r
782              * configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
783              *\r
784              * Interrupts that  use the FreeRTOS API must not be left at their\r
785              * default priority of      zero as that is the highest possible priority,\r
786              * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,\r
787              * and      therefore also guaranteed to be invalid.\r
788              *\r
789              * FreeRTOS maintains separate thread and ISR API functions to ensure\r
790              * interrupt entry is as fast and simple as possible.\r
791              *\r
792              * The following links provide detailed information:\r
793              * http://www.freertos.org/RTOS-Cortex-M3-M4.html\r
794              * http://www.freertos.org/FAQHelp.html */\r
795             configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );\r
796         }\r
797 \r
798         /* Priority grouping:  The interrupt controller (NVIC) allows the bits\r
799          * that define each interrupt's priority to be split between bits that\r
800          * define the interrupt's pre-emption priority bits and bits that define\r
801          * the interrupt's sub-priority.  For simplicity all bits must be defined\r
802          * to be pre-emption priority bits.  The following assertion will fail if\r
803          * this is not the case (if some bits represent a sub-priority).\r
804          *\r
805          * If the application only uses CMSIS libraries for interrupt\r
806          * configuration then the correct setting can be achieved on all Cortex-M\r
807          * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the\r
808          * scheduler.  Note however that some vendor specific peripheral libraries\r
809          * assume a non-zero priority group setting, in which cases using a value\r
810          * of zero will result in unpredictable behaviour. */\r
811         configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );\r
812     }\r
813 \r
814 #endif /* configASSERT_DEFINED */\r