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 /* Standard includes. */
30 #include <stdlib.h>
31
32 /* Scheduler includes. */
33 #include "FreeRTOS.h"
34 #include "task.h"
35
36 #ifndef configINTERRUPT_CONTROLLER_BASE_ADDRESS
37 #error configINTERRUPT_CONTROLLER_BASE_ADDRESS must be defined. See https://www.FreeRTOS.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
38 #endif
39
40 #ifndef configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET
41 #error configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET must be defined. See https://www.FreeRTOS.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
42 #endif
43
44 #ifndef configUNIQUE_INTERRUPT_PRIORITIES
45 #error configUNIQUE_INTERRUPT_PRIORITIES must be defined. See https://www.FreeRTOS.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
46 #endif
47
48 #ifndef configSETUP_TICK_INTERRUPT
49 #error configSETUP_TICK_INTERRUPT() must be defined. See https://www.FreeRTOS.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
50 #endif /* configSETUP_TICK_INTERRUPT */
51
52 #ifndef configMAX_API_CALL_INTERRUPT_PRIORITY
53 #error configMAX_API_CALL_INTERRUPT_PRIORITY must be defined. See https://www.FreeRTOS.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
54 #endif
55
56 #if configMAX_API_CALL_INTERRUPT_PRIORITY == 0
57 #error configMAX_API_CALL_INTERRUPT_PRIORITY must not be set to 0
58 #endif
59
60 #if configMAX_API_CALL_INTERRUPT_PRIORITY > configUNIQUE_INTERRUPT_PRIORITIES
61 #error configMAX_API_CALL_INTERRUPT_PRIORITY must be less than or equal to configUNIQUE_INTERRUPT_PRIORITIES as the lower the numeric priority value the higher the logical interrupt priority
62 #endif
63
64 #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
65 /* Check the configuration. */
66 #if( configMAX_PRIORITIES > 32 )
67 #error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
68 #endif
69 #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
70
71 /* In case security extensions are implemented. */
72 #if configMAX_API_CALL_INTERRUPT_PRIORITY <= ( configUNIQUE_INTERRUPT_PRIORITIES / 2 )
73 #error configMAX_API_CALL_INTERRUPT_PRIORITY must be greater than ( configUNIQUE_INTERRUPT_PRIORITIES / 2 )
74 #endif
75
76 /* Some vendor specific files default configCLEAR_TICK_INTERRUPT() in
77 portmacro.h. */
78 #ifndef configCLEAR_TICK_INTERRUPT
79 #define configCLEAR_TICK_INTERRUPT()
80 #endif
81
82 /* A critical section is exited when the critical section nesting count reaches
83 this value. */
84 #define portNO_CRITICAL_NESTING ( ( size_t ) 0 )
85
86 /* In all GICs 255 can be written to the priority mask register to unmask all
87 (but the lowest) interrupt priority. */
88 #define portUNMASK_VALUE ( 0xFFUL )
89
90 /* Tasks are not created with a floating point context, but can be given a
91 floating point context after they have been created. A variable is stored as
92 part of the tasks context that holds portNO_FLOATING_POINT_CONTEXT if the task
93 does not have an FPU context, or any other value if the task does have an FPU
94 context. */
95 #define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
96
97 /* Constants required to setup the initial task context. */
98 #define portSP_ELx ( ( StackType_t ) 0x01 )
99 #define portSP_EL0 ( ( StackType_t ) 0x00 )
100
101 #if defined( GUEST )
102 #define portEL1 ( ( StackType_t ) 0x04 )
103 #define portINITIAL_PSTATE ( portEL1 | portSP_EL0 )
104 #else
105 #define portEL3 ( ( StackType_t ) 0x0c )
106 /* At the time of writing, the BSP only supports EL3. */
107 #define portINITIAL_PSTATE ( portEL3 | portSP_EL0 )
108 #endif
109
110
111 /* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary
112 point is zero. */
113 #define portBINARY_POINT_BITS ( ( uint8_t ) 0x03 )
114
115 /* Masks all bits in the APSR other than the mode bits. */
116 #define portAPSR_MODE_BITS_MASK ( 0x0C )
117
118 /* The I bit in the DAIF bits. */
119 #define portDAIF_I ( 0x80 )
120
121 /* Macro to unmask all interrupt priorities. */
122 #define portCLEAR_INTERRUPT_MASK() \
123 { \
124 portDISABLE_INTERRUPTS(); \
125 portICCPMR_PRIORITY_MASK_REGISTER = portUNMASK_VALUE; \
126 __asm volatile ( "DSB SY \n" \
127 "ISB SY \n" ); \
128 portENABLE_INTERRUPTS(); \
129 }
130
131 /* Hardware specifics used when sanity checking the configuration. */
132 #define portINTERRUPT_PRIORITY_REGISTER_OFFSET 0x400UL
133 #define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
134 #define portBIT_0_SET ( ( uint8_t ) 0x01 )
135
136 /*-----------------------------------------------------------*/
137
138 /*
139 * Starts the first task executing. This function is necessarily written in
140 * assembly code so is implemented in portASM.s.
141 */
142 extern void vPortRestoreTaskContext( void );
143
144 /*-----------------------------------------------------------*/
145
146 /* A variable is used to keep track of the critical section nesting. This
147 variable has to be stored as part of the task context and must be initialised to
148 a non zero value to ensure interrupts don't inadvertently become unmasked before
149 the scheduler starts. As it is stored as part of the task context it will
150 automatically be set to 0 when the first task is started. */
151 volatile uint64_t ullCriticalNesting = 9999ULL;
152
153 /* Saved as part of the task context. If ullPortTaskHasFPUContext is non-zero
154 then floating point context must be saved and restored for the task. */
155 uint64_t ullPortTaskHasFPUContext = pdFALSE;
156
157 /* Set to 1 to pend a context switch from an ISR. */
158 uint64_t ullPortYieldRequired = pdFALSE;
159
160 /* Counts the interrupt nesting depth. A context switch is only performed if
161 if the nesting depth is 0. */
162 uint64_t ullPortInterruptNesting = 0;
163
164 /* Used in the ASM code. */
165 __attribute__(( used )) const uint64_t ullICCEOIR = portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS;
166 __attribute__(( used )) const uint64_t ullICCIAR = portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS;
167 __attribute__(( used )) const uint64_t ullICCPMR = portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS;
168 __attribute__(( used )) const uint64_t ullMaxAPIPriorityMask = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
169
170 /*-----------------------------------------------------------*/
171
172 /*
173 * See header file for description.
174 */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters)175 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
176 {
177 /* Setup the initial stack of the task. The stack is set exactly as
178 expected by the portRESTORE_CONTEXT() macro. */
179
180 /* First all the general purpose registers. */
181 pxTopOfStack--;
182 *pxTopOfStack = 0x0101010101010101ULL; /* R1 */
183 pxTopOfStack--;
184 *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
185 pxTopOfStack--;
186 *pxTopOfStack = 0x0303030303030303ULL; /* R3 */
187 pxTopOfStack--;
188 *pxTopOfStack = 0x0202020202020202ULL; /* R2 */
189 pxTopOfStack--;
190 *pxTopOfStack = 0x0505050505050505ULL; /* R5 */
191 pxTopOfStack--;
192 *pxTopOfStack = 0x0404040404040404ULL; /* R4 */
193 pxTopOfStack--;
194 *pxTopOfStack = 0x0707070707070707ULL; /* R7 */
195 pxTopOfStack--;
196 *pxTopOfStack = 0x0606060606060606ULL; /* R6 */
197 pxTopOfStack--;
198 *pxTopOfStack = 0x0909090909090909ULL; /* R9 */
199 pxTopOfStack--;
200 *pxTopOfStack = 0x0808080808080808ULL; /* R8 */
201 pxTopOfStack--;
202 *pxTopOfStack = 0x1111111111111111ULL; /* R11 */
203 pxTopOfStack--;
204 *pxTopOfStack = 0x1010101010101010ULL; /* R10 */
205 pxTopOfStack--;
206 *pxTopOfStack = 0x1313131313131313ULL; /* R13 */
207 pxTopOfStack--;
208 *pxTopOfStack = 0x1212121212121212ULL; /* R12 */
209 pxTopOfStack--;
210 *pxTopOfStack = 0x1515151515151515ULL; /* R15 */
211 pxTopOfStack--;
212 *pxTopOfStack = 0x1414141414141414ULL; /* R14 */
213 pxTopOfStack--;
214 *pxTopOfStack = 0x1717171717171717ULL; /* R17 */
215 pxTopOfStack--;
216 *pxTopOfStack = 0x1616161616161616ULL; /* R16 */
217 pxTopOfStack--;
218 *pxTopOfStack = 0x1919191919191919ULL; /* R19 */
219 pxTopOfStack--;
220 *pxTopOfStack = 0x1818181818181818ULL; /* R18 */
221 pxTopOfStack--;
222 *pxTopOfStack = 0x2121212121212121ULL; /* R21 */
223 pxTopOfStack--;
224 *pxTopOfStack = 0x2020202020202020ULL; /* R20 */
225 pxTopOfStack--;
226 *pxTopOfStack = 0x2323232323232323ULL; /* R23 */
227 pxTopOfStack--;
228 *pxTopOfStack = 0x2222222222222222ULL; /* R22 */
229 pxTopOfStack--;
230 *pxTopOfStack = 0x2525252525252525ULL; /* R25 */
231 pxTopOfStack--;
232 *pxTopOfStack = 0x2424242424242424ULL; /* R24 */
233 pxTopOfStack--;
234 *pxTopOfStack = 0x2727272727272727ULL; /* R27 */
235 pxTopOfStack--;
236 *pxTopOfStack = 0x2626262626262626ULL; /* R26 */
237 pxTopOfStack--;
238 *pxTopOfStack = 0x2929292929292929ULL; /* R29 */
239 pxTopOfStack--;
240 *pxTopOfStack = 0x2828282828282828ULL; /* R28 */
241 pxTopOfStack--;
242 *pxTopOfStack = ( StackType_t ) 0x00; /* XZR - has no effect, used so there are an even number of registers. */
243 pxTopOfStack--;
244 *pxTopOfStack = ( StackType_t ) 0x00; /* R30 - procedure call link register. */
245 pxTopOfStack--;
246
247 *pxTopOfStack = portINITIAL_PSTATE;
248 pxTopOfStack--;
249
250 *pxTopOfStack = ( StackType_t ) pxCode; /* Exception return address. */
251 pxTopOfStack--;
252
253 /* The task will start with a critical nesting count of 0 as interrupts are
254 enabled. */
255 *pxTopOfStack = portNO_CRITICAL_NESTING;
256 pxTopOfStack--;
257
258 /* The task will start without a floating point context. A task that uses
259 the floating point hardware must call vPortTaskUsesFPU() before executing
260 any floating point instructions. */
261 *pxTopOfStack = portNO_FLOATING_POINT_CONTEXT;
262
263 return pxTopOfStack;
264 }
265 /*-----------------------------------------------------------*/
266
xPortStartScheduler(void)267 BaseType_t xPortStartScheduler( void )
268 {
269 uint32_t ulAPSR;
270
271 #if( configASSERT_DEFINED == 1 )
272 {
273 volatile uint8_t ucOriginalPriority;
274 volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + portINTERRUPT_PRIORITY_REGISTER_OFFSET );
275 volatile uint8_t ucMaxPriorityValue;
276
277 /* Determine how many priority bits are implemented in the GIC.
278
279 Save the interrupt priority value that is about to be clobbered. */
280 ucOriginalPriority = *pucFirstUserPriorityRegister;
281
282 /* Determine the number of priority bits available. First write to
283 all possible bits. */
284 *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
285
286 /* Read the value back to see how many bits stuck. */
287 ucMaxPriorityValue = *pucFirstUserPriorityRegister;
288
289 /* Shift to the least significant bits. */
290 while( ( ucMaxPriorityValue & portBIT_0_SET ) != portBIT_0_SET )
291 {
292 ucMaxPriorityValue >>= ( uint8_t ) 0x01;
293 }
294
295 /* Sanity check configUNIQUE_INTERRUPT_PRIORITIES matches the read
296 value. */
297
298 configASSERT( ucMaxPriorityValue >= portLOWEST_INTERRUPT_PRIORITY );
299
300
301 /* Restore the clobbered interrupt priority register to its original
302 value. */
303 *pucFirstUserPriorityRegister = ucOriginalPriority;
304 }
305 #endif /* configASSERT_DEFINED */
306
307
308 /* At the time of writing, the BSP only supports EL3. */
309 __asm volatile ( "MRS %0, CurrentEL" : "=r" ( ulAPSR ) );
310 ulAPSR &= portAPSR_MODE_BITS_MASK;
311
312 #if defined( GUEST )
313 #warning Building for execution as a guest under XEN. THIS IS NOT A FULLY TESTED PATH.
314 configASSERT( ulAPSR == portEL1 );
315 if( ulAPSR == portEL1 )
316 #else
317 configASSERT( ulAPSR == portEL3 );
318 if( ulAPSR == portEL3 )
319 #endif
320 {
321 /* Only continue if the binary point value is set to its lowest possible
322 setting. See the comments in vPortValidateInterruptPriority() below for
323 more information. */
324 configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
325
326 if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE )
327 {
328 /* Interrupts are turned off in the CPU itself to ensure a tick does
329 not execute while the scheduler is being started. Interrupts are
330 automatically turned back on in the CPU when the first task starts
331 executing. */
332 portDISABLE_INTERRUPTS();
333
334 /* Start the timer that generates the tick ISR. */
335 configSETUP_TICK_INTERRUPT();
336
337 /* Start the first task executing. */
338 vPortRestoreTaskContext();
339 }
340 }
341
342 return 0;
343 }
344 /*-----------------------------------------------------------*/
345
vPortEndScheduler(void)346 void vPortEndScheduler( void )
347 {
348 /* Not implemented in ports where there is nothing to return to.
349 Artificially force an assert. */
350 configASSERT( ullCriticalNesting == 1000ULL );
351 }
352 /*-----------------------------------------------------------*/
353
vPortEnterCritical(void)354 void vPortEnterCritical( void )
355 {
356 /* Mask interrupts up to the max syscall interrupt priority. */
357 uxPortSetInterruptMask();
358
359 /* Now interrupts are disabled ullCriticalNesting can be accessed
360 directly. Increment ullCriticalNesting to keep a count of how many times
361 portENTER_CRITICAL() has been called. */
362 ullCriticalNesting++;
363
364 /* This is not the interrupt safe version of the enter critical function so
365 assert() if it is being called from an interrupt context. Only API
366 functions that end in "FromISR" can be used in an interrupt. Only assert if
367 the critical nesting count is 1 to protect against recursive calls if the
368 assert function also uses a critical section. */
369 if( ullCriticalNesting == 1ULL )
370 {
371 configASSERT( ullPortInterruptNesting == 0 );
372 }
373 }
374 /*-----------------------------------------------------------*/
375
vPortExitCritical(void)376 void vPortExitCritical( void )
377 {
378 if( ullCriticalNesting > portNO_CRITICAL_NESTING )
379 {
380 /* Decrement the nesting count as the critical section is being
381 exited. */
382 ullCriticalNesting--;
383
384 /* If the nesting level has reached zero then all interrupt
385 priorities must be re-enabled. */
386 if( ullCriticalNesting == portNO_CRITICAL_NESTING )
387 {
388 /* Critical nesting has reached zero so all interrupt priorities
389 should be unmasked. */
390 portCLEAR_INTERRUPT_MASK();
391 }
392 }
393 }
394 /*-----------------------------------------------------------*/
395
FreeRTOS_Tick_Handler(void)396 void FreeRTOS_Tick_Handler( void )
397 {
398 /* Must be the lowest possible priority. */
399 #if !defined( QEMU )
400 {
401 configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER == ( uint32_t ) ( portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
402 }
403 #endif
404
405 /* Interrupts should not be enabled before this point. */
406 #if( configASSERT_DEFINED == 1 )
407 {
408 uint32_t ulMaskBits;
409
410 __asm volatile( "mrs %0, daif" : "=r"( ulMaskBits ) :: "memory" );
411 configASSERT( ( ulMaskBits & portDAIF_I ) != 0 );
412 }
413 #endif /* configASSERT_DEFINED */
414
415 /* Set interrupt mask before altering scheduler structures. The tick
416 handler runs at the lowest priority, so interrupts cannot already be masked,
417 so there is no need to save and restore the current mask value. It is
418 necessary to turn off interrupts in the CPU itself while the ICCPMR is being
419 updated. */
420 portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
421 __asm volatile ( "dsb sy \n"
422 "isb sy \n" ::: "memory" );
423
424 /* Ok to enable interrupts after the interrupt source has been cleared. */
425 configCLEAR_TICK_INTERRUPT();
426 portENABLE_INTERRUPTS();
427
428 /* Increment the RTOS tick. */
429 if( xTaskIncrementTick() != pdFALSE )
430 {
431 ullPortYieldRequired = pdTRUE;
432 }
433
434 /* Ensure all interrupt priorities are active again. */
435 portCLEAR_INTERRUPT_MASK();
436 }
437 /*-----------------------------------------------------------*/
438
vPortTaskUsesFPU(void)439 void vPortTaskUsesFPU( void )
440 {
441 /* A task is registering the fact that it needs an FPU context. Set the
442 FPU flag (which is saved as part of the task context). */
443 ullPortTaskHasFPUContext = pdTRUE;
444
445 /* Consider initialising the FPSR here - but probably not necessary in
446 AArch64. */
447 }
448 /*-----------------------------------------------------------*/
449
vPortClearInterruptMask(UBaseType_t uxNewMaskValue)450 void vPortClearInterruptMask( UBaseType_t uxNewMaskValue )
451 {
452 if( uxNewMaskValue == pdFALSE )
453 {
454 portCLEAR_INTERRUPT_MASK();
455 }
456 }
457 /*-----------------------------------------------------------*/
458
uxPortSetInterruptMask(void)459 UBaseType_t uxPortSetInterruptMask( void )
460 {
461 uint32_t ulReturn;
462
463 /* Interrupt in the CPU must be turned off while the ICCPMR is being
464 updated. */
465 portDISABLE_INTERRUPTS();
466 if( portICCPMR_PRIORITY_MASK_REGISTER == ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) )
467 {
468 /* Interrupts were already masked. */
469 ulReturn = pdTRUE;
470 }
471 else
472 {
473 ulReturn = pdFALSE;
474 portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
475 __asm volatile ( "dsb sy \n"
476 "isb sy \n" ::: "memory" );
477 }
478 portENABLE_INTERRUPTS();
479
480 return ulReturn;
481 }
482 /*-----------------------------------------------------------*/
483
484 #if( configASSERT_DEFINED == 1 )
485
vPortValidateInterruptPriority(void)486 void vPortValidateInterruptPriority( void )
487 {
488 /* The following assertion will fail if a service routine (ISR) for
489 an interrupt that has been assigned a priority above
490 configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
491 function. ISR safe FreeRTOS API functions must *only* be called
492 from interrupts that have been assigned a priority at or below
493 configMAX_SYSCALL_INTERRUPT_PRIORITY.
494
495 Numerically low interrupt priority numbers represent logically high
496 interrupt priorities, therefore the priority of the interrupt must
497 be set to a value equal to or numerically *higher* than
498 configMAX_SYSCALL_INTERRUPT_PRIORITY.
499
500 FreeRTOS maintains separate thread and ISR API functions to ensure
501 interrupt entry is as fast and simple as possible. */
502 configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
503
504 /* Priority grouping: The interrupt controller (GIC) allows the bits
505 that define each interrupt's priority to be split between bits that
506 define the interrupt's pre-emption priority bits and bits that define
507 the interrupt's sub-priority. For simplicity all bits must be defined
508 to be pre-emption priority bits. The following assertion will fail if
509 this is not the case (if some bits represent a sub-priority).
510
511 The priority grouping is configured by the GIC's binary point register
512 (ICCBPR). Writting 0 to ICCBPR will ensure it is set to its lowest
513 possible value (which may be above 0). */
514 configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
515 }
516
517 #endif /* configASSERT_DEFINED */
518 /*-----------------------------------------------------------*/
519