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