mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2026-10-09 23:53:04 -04:00
Merge aca328e173 into 8be86d4a24
This commit is contained in:
commit
58225db4b9
4 changed files with 222 additions and 14 deletions
|
|
@ -546,6 +546,14 @@
|
||||||
* vTaskPreemptionEnable APIs. */
|
* vTaskPreemptionEnable APIs. */
|
||||||
#define configUSE_TASK_PREEMPTION_DISABLE 0
|
#define configUSE_TASK_PREEMPTION_DISABLE 0
|
||||||
|
|
||||||
|
/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), set
|
||||||
|
* configUSE_SCHEDULER_CORE_MASK to 1 to enable the scheduler core mask feature.
|
||||||
|
* When enabled, the vTaskSetSchedulerCoreMask and uxTaskGetSchedulerCoreMask
|
||||||
|
* APIs can be used to control which cores are allowed to run non-idle tasks
|
||||||
|
* system-wide at run time. Set to 0 to exclude this feature from the build.
|
||||||
|
* Defaults to 1 if left undefined. */
|
||||||
|
#define configUSE_SCHEDULER_CORE_MASK 1
|
||||||
|
|
||||||
/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), set
|
/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), set
|
||||||
* configUSE_PASSIVE_IDLE_HOOK to 1 to allow the application writer to use
|
* configUSE_PASSIVE_IDLE_HOOK to 1 to allow the application writer to use
|
||||||
* the passive idle task hook to add background functionality without the
|
* the passive idle task hook to add background functionality without the
|
||||||
|
|
|
||||||
|
|
@ -516,6 +516,14 @@
|
||||||
#define configUSE_CORE_AFFINITY 0
|
#define configUSE_CORE_AFFINITY 0
|
||||||
#endif /* configUSE_CORE_AFFINITY */
|
#endif /* configUSE_CORE_AFFINITY */
|
||||||
|
|
||||||
|
#ifndef configUSE_SCHEDULER_CORE_MASK
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#define configUSE_SCHEDULER_CORE_MASK 1
|
||||||
|
#else
|
||||||
|
#define configUSE_SCHEDULER_CORE_MASK 0
|
||||||
|
#endif
|
||||||
|
#endif /* configUSE_SCHEDULER_CORE_MASK */
|
||||||
|
|
||||||
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) )
|
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) )
|
||||||
#ifndef configTASK_DEFAULT_CORE_AFFINITY
|
#ifndef configTASK_DEFAULT_CORE_AFFINITY
|
||||||
#define configTASK_DEFAULT_CORE_AFFINITY tskNO_AFFINITY
|
#define configTASK_DEFAULT_CORE_AFFINITY tskNO_AFFINITY
|
||||||
|
|
@ -1858,6 +1866,22 @@
|
||||||
#define traceRETURN_vTaskCoreAffinityGet( uxCoreAffinityMask )
|
#define traceRETURN_vTaskCoreAffinityGet( uxCoreAffinityMask )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef traceENTER_vTaskSetSchedulerCoreMask
|
||||||
|
#define traceENTER_vTaskSetSchedulerCoreMask( uxCoreMask )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef traceRETURN_vTaskSetSchedulerCoreMask
|
||||||
|
#define traceRETURN_vTaskSetSchedulerCoreMask()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef traceENTER_uxTaskGetSchedulerCoreMask
|
||||||
|
#define traceENTER_uxTaskGetSchedulerCoreMask()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef traceRETURN_uxTaskGetSchedulerCoreMask
|
||||||
|
#define traceRETURN_uxTaskGetSchedulerCoreMask( uxCoreMask )
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef traceENTER_vTaskPreemptionDisable
|
#ifndef traceENTER_vTaskPreemptionDisable
|
||||||
#define traceENTER_vTaskPreemptionDisable( xTask )
|
#define traceENTER_vTaskPreemptionDisable( xTask )
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -2914,6 +2938,10 @@
|
||||||
#error configUSE_CORE_AFFINITY is not supported in single core FreeRTOS
|
#error configUSE_CORE_AFFINITY is not supported in single core FreeRTOS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ( ( configNUMBER_OF_CORES == 1 ) && ( configUSE_SCHEDULER_CORE_MASK != 0 ) )
|
||||||
|
#error configUSE_SCHEDULER_CORE_MASK is not supported in single core FreeRTOS
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_PORT_OPTIMISED_TASK_SELECTION != 0 ) )
|
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_PORT_OPTIMISED_TASK_SELECTION != 0 ) )
|
||||||
#error configUSE_PORT_OPTIMISED_TASK_SELECTION is not supported in SMP FreeRTOS
|
#error configUSE_PORT_OPTIMISED_TASK_SELECTION is not supported in SMP FreeRTOS
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1488,6 +1488,54 @@ BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;
|
||||||
UBaseType_t vTaskCoreAffinityGet( ConstTaskHandle_t xTask );
|
UBaseType_t vTaskCoreAffinityGet( ConstTaskHandle_t xTask );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_SCHEDULER_CORE_MASK == 1 ) )
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Controls which cores are allowed to run non-idle tasks system-wide.
|
||||||
|
* Bit N = 1 means core N may run non-idle tasks; bit N = 0 means core N will
|
||||||
|
* only run its idle task. configNUMBER_OF_CORES must be greater than 1 for
|
||||||
|
* this function to be available.
|
||||||
|
*
|
||||||
|
* Masking a core (including core 0) does NOT power it off or stop its tick
|
||||||
|
* ISR and scheduler from executing. All cores remain active; the mask only
|
||||||
|
* controls whether the scheduler may dispatch a non-idle task onto a core.
|
||||||
|
* A masked core continues to service its tick interrupt and enters the
|
||||||
|
* scheduler normally, but will always be assigned the idle task.
|
||||||
|
*
|
||||||
|
* Passing 0 as the mask is valid; every core will run only its idle task
|
||||||
|
* until a new mask is applied.
|
||||||
|
*
|
||||||
|
* If a core that is currently running a non-idle task becomes disabled by
|
||||||
|
* the new mask, it is yielded immediately so the scheduler can replace the
|
||||||
|
* running task with the idle task.
|
||||||
|
*
|
||||||
|
* @param uxCoreMask Bitmask of cores to enable. Cores are numbered 0 to
|
||||||
|
* configNUMBER_OF_CORES - 1. Pass ( tskNO_AFFINITY ) to re-enable all cores.
|
||||||
|
*
|
||||||
|
* Example usage (4-core system, exclude core 2):
|
||||||
|
*
|
||||||
|
* // Allow scheduling on cores 0, 1 and 3 only.
|
||||||
|
* vTaskSetSchedulerCoreMask( ( 1 << 0 ) | ( 1 << 1 ) | ( 1 << 3 ) );
|
||||||
|
*
|
||||||
|
* // Later, restore all four cores.
|
||||||
|
* vTaskSetSchedulerCoreMask( ( 1 << 0 ) | ( 1 << 1 ) | ( 1 << 2 ) | ( 1 << 3 ) );
|
||||||
|
*/
|
||||||
|
void vTaskSetSchedulerCoreMask( UBaseType_t uxCoreMask ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current global scheduler core mask.
|
||||||
|
*
|
||||||
|
* @return Bitmask where bit N = 1 means core N is currently allowed to run
|
||||||
|
* non-idle tasks.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
*
|
||||||
|
* UBaseType_t uxMask = uxTaskGetSchedulerCoreMask();
|
||||||
|
*/
|
||||||
|
UBaseType_t uxTaskGetSchedulerCoreMask( void ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
|
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
152
tasks.c
152
tasks.c
|
|
@ -513,6 +513,20 @@ PRIVILEGED_DATA STATIC UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U;
|
||||||
PRIVILEGED_DATA STATIC volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */
|
PRIVILEGED_DATA STATIC volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */
|
||||||
PRIVILEGED_DATA STATIC TaskHandle_t xIdleTaskHandles[ configNUMBER_OF_CORES ]; /**< Holds the handles of the idle tasks. The idle tasks are created automatically when the scheduler is started. */
|
PRIVILEGED_DATA STATIC TaskHandle_t xIdleTaskHandles[ configNUMBER_OF_CORES ]; /**< Holds the handles of the idle tasks. The idle tasks are created automatically when the scheduler is started. */
|
||||||
|
|
||||||
|
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_SCHEDULER_CORE_MASK == 1 ) )
|
||||||
|
/* Global scheduler core mask. Bit N = 1 means core N is allowed to run
|
||||||
|
* non-idle tasks. Defaults to all cores enabled. Use
|
||||||
|
* vTaskSetSchedulerCoreMask() / uxTaskGetSchedulerCoreMask() to change it
|
||||||
|
* at run time.
|
||||||
|
*
|
||||||
|
* The mask is derived by right-shifting ~0 rather than left-shifting 1,
|
||||||
|
* because left-shifting by a value equal to the type width is undefined
|
||||||
|
* behaviour in C (C11 §6.5.7). Using UBaseType_t throughout also avoids
|
||||||
|
* the assumption that unsigned long is at least as wide as UBaseType_t. */
|
||||||
|
PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerCoreMask =
|
||||||
|
( ( UBaseType_t ) ( ~( UBaseType_t ) 0U ) >> ( ( sizeof( UBaseType_t ) * ( size_t ) 8U ) - ( size_t ) configNUMBER_OF_CORES ) );
|
||||||
|
#endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_SCHEDULER_CORE_MASK == 1 ) ) */
|
||||||
|
|
||||||
/* Improve support for OpenOCD. The kernel tracks Ready tasks via priority lists.
|
/* Improve support for OpenOCD. The kernel tracks Ready tasks via priority lists.
|
||||||
* For tracking the state of remote threads, OpenOCD uses uxTopUsedPriority
|
* For tracking the state of remote threads, OpenOCD uses uxTopUsedPriority
|
||||||
* to determine the number of priority lists to read back from the remote target. */
|
* to determine the number of priority lists to read back from the remote target. */
|
||||||
|
|
@ -929,12 +943,19 @@ STATIC void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
|
||||||
if( ( pxTCB->uxCoreAffinityMask & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U )
|
if( ( pxTCB->uxCoreAffinityMask & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
|
#if ( configUSE_SCHEDULER_CORE_MASK == 1 )
|
||||||
if( pxCurrentTCBs[ xCoreID ]->xPreemptionDisable == pdFALSE )
|
/* Non-idle tasks may not be scheduled on disabled cores. */
|
||||||
|
if( ( ( pxTCB->uxTaskAttributes & taskATTRIBUTE_IS_IDLE ) != 0U ) ||
|
||||||
|
( ( uxSchedulerCoreMask & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U ) )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
xLowestPriorityToPreempt = xCurrentCoreTaskPriority;
|
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
|
||||||
xLowestPriorityCore = xCoreID;
|
if( pxCurrentTCBs[ xCoreID ]->xPreemptionDisable == pdFALSE )
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
xLowestPriorityToPreempt = xCurrentCoreTaskPriority;
|
||||||
|
xLowestPriorityCore = xCoreID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1078,14 +1099,21 @@ STATIC void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
|
||||||
if( ( pxTCB->uxCoreAffinityMask & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U )
|
if( ( pxTCB->uxCoreAffinityMask & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
/* If the task is not being executed by any core swap it in. */
|
#if ( configUSE_SCHEDULER_CORE_MASK == 1 )
|
||||||
pxCurrentTCBs[ xCoreID ]->xTaskRunState = taskTASK_NOT_RUNNING;
|
/* Non-idle tasks may not run on scheduler-disabled cores. */
|
||||||
#if ( configUSE_CORE_AFFINITY == 1 )
|
if( ( ( pxTCB->uxTaskAttributes & taskATTRIBUTE_IS_IDLE ) != 0U ) ||
|
||||||
pxPreviousTCB = pxCurrentTCBs[ xCoreID ];
|
( ( uxSchedulerCoreMask & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U ) )
|
||||||
#endif
|
#endif
|
||||||
pxTCB->xTaskRunState = xCoreID;
|
{
|
||||||
pxCurrentTCBs[ xCoreID ] = pxTCB;
|
/* If the task is not being executed by any core swap it in. */
|
||||||
xTaskScheduled = pdTRUE;
|
pxCurrentTCBs[ xCoreID ]->xTaskRunState = taskTASK_NOT_RUNNING;
|
||||||
|
#if ( configUSE_CORE_AFFINITY == 1 )
|
||||||
|
pxPreviousTCB = pxCurrentTCBs[ xCoreID ];
|
||||||
|
#endif
|
||||||
|
pxTCB->xTaskRunState = xCoreID;
|
||||||
|
pxCurrentTCBs[ xCoreID ] = pxTCB;
|
||||||
|
xTaskScheduled = pdTRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( pxTCB == pxCurrentTCBs[ xCoreID ] )
|
else if( pxTCB == pxCurrentTCBs[ xCoreID ] )
|
||||||
|
|
@ -1096,9 +1124,16 @@ STATIC void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
|
||||||
if( ( pxTCB->uxCoreAffinityMask & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U )
|
if( ( pxTCB->uxCoreAffinityMask & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
/* The task is already running on this core, mark it as scheduled. */
|
#if ( configUSE_SCHEDULER_CORE_MASK == 1 )
|
||||||
pxTCB->xTaskRunState = xCoreID;
|
/* Non-idle tasks may not continue on scheduler-disabled cores. */
|
||||||
xTaskScheduled = pdTRUE;
|
if( ( ( pxTCB->uxTaskAttributes & taskATTRIBUTE_IS_IDLE ) != 0U ) ||
|
||||||
|
( ( uxSchedulerCoreMask & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U ) )
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* The task is already running on this core, mark it as scheduled. */
|
||||||
|
pxTCB->xTaskRunState = xCoreID;
|
||||||
|
xTaskScheduled = pdTRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -3136,6 +3171,95 @@ STATIC void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_SCHEDULER_CORE_MASK == 1 ) )
|
||||||
|
void vTaskSetSchedulerCoreMask( UBaseType_t uxCoreMask )
|
||||||
|
{
|
||||||
|
BaseType_t xCoreID;
|
||||||
|
UBaseType_t uxOldMask;
|
||||||
|
UBaseType_t uxDisabledCores;
|
||||||
|
UBaseType_t uxEnabledCores;
|
||||||
|
|
||||||
|
traceENTER_vTaskSetSchedulerCoreMask( uxCoreMask );
|
||||||
|
|
||||||
|
/* Verify that uxCoreMask does not reference cores beyond the number of
|
||||||
|
* physical cores available. Any bit at position configNUMBER_OF_CORES
|
||||||
|
* or higher is invalid. */
|
||||||
|
configASSERT( ( uxCoreMask & ~( ( UBaseType_t ) ( ~( UBaseType_t ) 0U ) >> ( ( sizeof( UBaseType_t ) * ( size_t ) 8U ) - ( size_t ) configNUMBER_OF_CORES ) ) ) == 0U );
|
||||||
|
|
||||||
|
taskENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
uxOldMask = uxSchedulerCoreMask;
|
||||||
|
|
||||||
|
/* Clamp to the number of physical cores so stray bits are ignored.
|
||||||
|
* The valid-core mask is derived by right-shifting ~0 to avoid
|
||||||
|
* left-shift UB and unsigned long width assumptions (see the
|
||||||
|
* uxSchedulerCoreMask initialiser for a full explanation). */
|
||||||
|
uxSchedulerCoreMask = uxCoreMask &
|
||||||
|
( ( UBaseType_t ) ( ~( UBaseType_t ) 0U ) >> ( ( sizeof( UBaseType_t ) * ( size_t ) 8U ) - ( size_t ) configNUMBER_OF_CORES ) );
|
||||||
|
|
||||||
|
if( xSchedulerRunning != pdFALSE )
|
||||||
|
{
|
||||||
|
/* For each core that was just disabled (was allowed, now disallowed),
|
||||||
|
* yield it immediately if it is running a non-idle task so the
|
||||||
|
* scheduler re-selects the idle task on that core. For each core
|
||||||
|
* that was just enabled (was disallowed, now allowed), request a
|
||||||
|
* context switch immediately so it stops idling and promptly starts
|
||||||
|
* executing any available ready tasks. The two masks are mutually
|
||||||
|
* exclusive so a single loop suffices. */
|
||||||
|
uxDisabledCores = uxOldMask & ~uxSchedulerCoreMask;
|
||||||
|
uxEnabledCores = ~uxOldMask & uxSchedulerCoreMask;
|
||||||
|
|
||||||
|
for( xCoreID = ( BaseType_t ) 0; xCoreID < ( BaseType_t ) configNUMBER_OF_CORES; xCoreID++ )
|
||||||
|
{
|
||||||
|
UBaseType_t uxCoreBit = ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID;
|
||||||
|
|
||||||
|
if( ( uxDisabledCores & uxCoreBit ) != 0U )
|
||||||
|
{
|
||||||
|
if( ( pxCurrentTCBs[ xCoreID ]->uxTaskAttributes & taskATTRIBUTE_IS_IDLE ) == 0U )
|
||||||
|
{
|
||||||
|
prvYieldCore( xCoreID );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( ( uxEnabledCores & uxCoreBit ) != 0U )
|
||||||
|
{
|
||||||
|
prvYieldCore( xCoreID );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
|
||||||
|
traceRETURN_vTaskSetSchedulerCoreMask();
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_SCHEDULER_CORE_MASK == 1 ) ) */
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_SCHEDULER_CORE_MASK == 1 ) )
|
||||||
|
UBaseType_t uxTaskGetSchedulerCoreMask( void )
|
||||||
|
{
|
||||||
|
UBaseType_t uxCoreMask;
|
||||||
|
|
||||||
|
traceENTER_uxTaskGetSchedulerCoreMask();
|
||||||
|
|
||||||
|
portBASE_TYPE_ENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
uxCoreMask = uxSchedulerCoreMask;
|
||||||
|
}
|
||||||
|
portBASE_TYPE_EXIT_CRITICAL();
|
||||||
|
|
||||||
|
traceRETURN_uxTaskGetSchedulerCoreMask( uxCoreMask );
|
||||||
|
|
||||||
|
return uxCoreMask;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_SCHEDULER_CORE_MASK == 1 ) ) */
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
|
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
|
||||||
|
|
||||||
void vTaskPreemptionDisable( const TaskHandle_t xTask )
|
void vTaskPreemptionDisable( const TaskHandle_t xTask )
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue