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