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