下载 FreeRTOS
 

出色的 RTOS & 嵌入式软件

内核
最新资讯
简化任何设备的身份验证云连接。
利用 CoAP 设计节能型云连接 IoT 解决方案。
11.0.0 版 FreeRTOS 内核简介:
FreeRTOS 路线图和代码贡献流程。
使用 FreeRTOS 实现 OPC-UA over TSN。

RTOS 任务通知
用作轻量级计数信号量

相关页面:


通过直接通知解除 RTOS 任务阻塞状态的速度和使用信号量相比快 45%, 且前者使用的 RAM 更少。 本页 演示了如何实现这一点。

计数信号量的计数值范围从 0 到创建信号量时设置的最大值。 只有在信号量可用的情况下,任务才能“获取”信号量, 而只有在信号量的计数大于零的情况下,信号量才可用。

使用任务通知代替 计数信号量时,接收任务的 通知值用于代替 计数信号量的计数值,以及 ulTaskNotifyTake()(或 ulTaskNotifyTakeIndexed())。 API 函数用于代替信号量的 xSemaphoreTake() API 函数。 ulTaskNotifyTake() 函数的 xClearOnExit 参数设置为 pdFALSE,因此 每次接收通知时,计数值只会递减(而不是清除), 模拟计数信号量。

同样,xTaskNotifyGive()(或 xTaskNotifyGiveIndexed()) vTaskNotifyGiveFromISR()(或 vTaskNotifyGiveIndexedFromISR() )函数用于代替信号量的 xSemaphoreGive() 和 xSemaphoreGiveFromISR()h 函数 。

下面的第一个示例使用接收任务的通知值作为计数 信号量。 第二个示例提供了更加实用和有效的实现。


示例 1:

/* An interrupt handler that does not process interrupts directly,
but instead defers processing to a high priority RTOS task.  The
ISR uses RTOS task notifications to both unblock the RTOS task
and increment the RTOS task's notification value. */
void vANInterruptHandler( void )
{
BaseType_t xHigherPriorityTaskWoken;

    /* Clear the interrupt. */
    prvClearInterruptSource();

    /* xHigherPriorityTaskWoken must be initialised to pdFALSE.
    If calling vTaskNotifyGiveFromISR() unblocks the handling
    task, and the priority of the handling task is higher than
    the priority of the currently running task, then
    xHigherPriorityTaskWoken will be automatically set to pdTRUE. */
    xHigherPriorityTaskWoken = pdFALSE;

    /* Unblock the handling task so the task can perform
    any processing necessitated by the interrupt.  xHandlingTask
    is the task's handle, which was obtained when the task was
    created.  vTaskNotifyGiveFromISR() also increments
    the receiving task's notification value. */
    vTaskNotifyGiveFromISR( xHandlingTask, &xHigherPriorityTaskWoken );

    /* Force a context switch if xHigherPriorityTaskWoken is now
    set to pdTRUE. The macro used to do this is dependent on
    the port and may be called portEND_SWITCHING_ISR. */
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
/*-----------------------------------------------------------*/

/* A task that blocks waiting to be notified that the peripheral
needs servicing. */
void vHandlingTask( void *pvParameters )
{
BaseType_t xEvent;
const TickType_t xBlockTime = pdMS_TO_TICS( 500 );
uint32_t ulNotifiedValue;

    for( ;; )
    {
        /* Block to wait for a notification.  Here the RTOS
        task notification is being used as a counting semaphore.
        The task's notification value is incremented each time
        the ISR calls vTaskNotifyGiveFromISR(), and decremented
        each time the RTOS task calls ulTaskNotifyTake() - so in
        effect holds a count of the number of outstanding interrupts.
        The first parameter is set to pdFALSE, so the notification
        value is only decremented and not cleared to zero, and one
        deferred interrupt event is processed at a time.  See
        example 2 below for a more pragmatic approach. */
        ulNotifiedValue = ulTaskNotifyTake( pdFALSE,
                                            xBlockTime );

        if( ulNotifiedValue > 0 )
        {
            /* Perform any processing necessitated by the interrupt. */
            xEvent = xQueryPeripheral();

            if( xEvent != NO_MORE_EVENTS )
            {
                vProcessPeripheralEvent( xEvent );
            }
        }
        else
        {
            /* Did not receive a notification within the expected
            time. */
            vCheckForErrorConditions();
        }
    }
}


示例 2:

此示例显示了 RTOS 任务更实用、更有效的实现。 在此实现中,从 ulTaskNotifyTake() 返回的值 用于了解必须处理多少未完成的 ISR 事件,从而 允许在每次调用 ulTaskNotifyTake() 时将 RTOS 任务的通知计数 清零。 假设中断服务程序 (ISR) 如 上面的示例 1 所示。

/* The index within the target task's array of task notifications
to use. */
const UBaseType_t xArrayIndex = 0;

/* A task that blocks waiting to be notified that the peripheral
needs servicing. */
void vHandlingTask( void *pvParameters )
{
BaseType_t xEvent;
const TickType_t xBlockTime = pdMS_TO_TICS( 500 );
uint32_t ulNotifiedValue;

    for( ;; )
    {
        /* As before, block to wait for a notification form the ISR.
        This time however the first parameter is set to pdTRUE,
        clearing the task's notification value to 0, meaning each
        outstanding outstanding deferred interrupt event must be
        processed before ulTaskNotifyTake() is called again. */
        ulNotifiedValue = ulTaskNotifyTakeIndexed( xArrayIndex,
                                                   pdTRUE,
                                                   xBlockTime );

        if( ulNotifiedValue == 0 )
        {
            /* Did not receive a notification within the expected
            time. */
            vCheckForErrorConditions();
        }
        else
        {
            /* ulNotifiedValue holds a count of the number of
            outstanding interrupts.  Process each in turn. */
            while( ulNotifiedValue > 0 )
            {
                xEvent = xQueryPeripheral();

                if( xEvent != NO_MORE_EVENTS )
                {
                    vProcessPeripheralEvent( xEvent );
                    ulNotifiedValue--;
                }
                else
                {
                    break;
                }
            }
        }
    }
}




Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.