You are here

Использование уведомлений в качестве группы флагов

Source: https://www.freertos.org/RTOS_Task_Notification_As_Event_Group.html

Перевод может содержать ошибки. Читайте первоисточник.


[Task Notifications - Уведомления]

RTOS Task Notifications Used As Light Weight Event Group -

Использование уведомлений в качестве группы флагов

Группа флагов - это множество отдельных флагов, каждый из которых разработчик имеет возможность использовать в различных произвольных целях. Задача RTOS может перейти в заблокированное состояние на время ожидания перехода в активное состояние одного или нескольких флагов внутри группы. Задача RTOS не использует процессорное время, пока находится в заблокированном состоянии.

Когда уведомления используются вместо группы флагов, поле уведомления задачи-получателя используется вместо группы флагов. Биты внутри поля уведомления используются как флаги, а функция API xTaskNotifyWait() используется вместо функции API xEventGroupWaitBits().

Аналогично биты устанавливаются с использованием функций API xTaskNotify() и xTaskNotifyFromISR() со значением параметра eAction == eSetBits вместо функций API xEventGroupSetBits() и xEventGroupSetBitsFromISR().

xTaskNotifyFromISR() имеет значительное преимущество в производительности по сравнению с xEventGroupSetBitsFromISR(), поскольку xTaskNotifyFromISR() выполняется полностью и обработчике прерывания, тогда как xEventGroupSetBitsFromISR() должна отложить часть выполнения до передачи управления задаче-демону RTOS. (Т.е. до передачи управления ядру ОС? Оригинал: ...defer some processing to the RTOS daemon task).

Есть и существенное отличие от использования группы флагов. В случае группы флагов задача-получатель может указать, что она хочет оставаться в заблокированном состоянии до тех пор, пока состояние флагов группы не придёт к некоторой заданной комбинации. А если в качестве группы флагов используются уведомления, то задача-получатель разблокируется, когда любой бит уведомления становится активным. И в этом случае задача-получатель должна сама анализировать состояние всех интересуемых бит в поле уведомления.

Пример:

/*----------------------------------------------------------------------------*/
/* Этот пример демонстрирует использование одной задачи RTOS для обработки
флагов, которые выставляются из двух отдельных обработчиков прерывания: один
флаг из прерывания по отправке данных, а второй флаг из прерывания по приёму
данных. Следует заметить, что во многих периферийных устройствах используется
одно и то же прерывание для обработки различных действий. В этом случае можно
просто выполнять операцию "побитовое ИЛИ" для вычисления нового значения
уведомления для задачи-получателя. */
 
/* Определяем биты для представления каждого из источников прерывания. */
#define TX_BIT    0x01
#define RX_BIT    0x02
 
/* Дескриптор задачи, которая получит уведомление из прерывания. Дескриптор был
получен при создании задачи RTOS. */
static TaskHandle_t xHandlingTask;
 
/*----------------------------------------------------------------------------*/
/* Реализация обработчика прерывания по отправке данных. */
void vTxISR( void )
{
    /* Переменная xHigherPriorityTaskWoken должна быть инициализирована
    значением pdFALSE. Если вызов функции API с суффиксом "FromISR" разблокирует
    задачу, приоритет которой выше, чем приоритет текущей запущенной задачи, то
    xHigherPriorityTaskWoken после вызова этой функции будет установлена
    в значение pdTRUE. */
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 
    /* Сбрасываем флаг прерывания. */
    prvClearInterrupt();
 
    /* Уведомляем задачу-получатель о прерывании по отправке данных установкой
    бита TX_BIT в поле уведомления. */
    xTaskNotifyFromISR( xHandlingTask,
                        TX_BIT,
                        eSetBits,
                        &xHigherPriorityTaskWoken );
 
    /* Если значение xHigherPriorityTaskWoken изменилось на pdTRUE, необходимо
    выполнить переключение контекста, чтобы выход из обработчика прерывания был
    осуществлён непосредственно в задачу с наивысшим приоритетом из числа
    разблокированных. Макрос, используемый для этого, зависит от порта
    для вашего процессора, и может называться portEND_SWITCHING_ISR. */
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
 
/*----------------------------------------------------------------------------*/
/* Реализация обработчика прерывания по приёму данных идентична реализации
обработчика прерывания по передаче данных, за исключением бита, устанавливаемого
в уведомлении. */
void vRxISR( void )
{
    /* Переменная xHigherPriorityTaskWoken должна быть инициализирована
    значением pdFALSE. Если вызов функции API с суффиксом "FromISR" разблокирует
    задачу, приоритет которой выше, чем приоритет текущей запущенной задачи, то
    xHigherPriorityTaskWoken после вызова этой функции будет установлена
    в значение pdTRUE. */
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 
    /* Сбрасываем флаг прерывания. */
    prvClearInterrupt();
 
    /* Уведомляем задачу-получатель о прерывании по приёму данных установкой
    бита RX_BIT в поле уведомления. */
    xTaskNotifyFromISR( xHandlingTask,
                        RX_BIT,
                        eSetBits,
                        &xHigherPriorityTaskWoken );
 
    /* Если значение xHigherPriorityTaskWoken изменилось на pdTRUE, необходимо
    выполнить переключение контекста, чтобы выход из обработчика прерывания был
    осуществлён непосредственно в задачу с наивысшим приоритетом из числа
    разблокированных. Макрос, используемый для этого, зависит от порта
    для вашего процессора, и может называться portEND_SWITCHING_ISR. */
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
 
/*----------------------------------------------------------------------------*/
/* Реализация задачи RTOS, которая получает уведомление от обработчиков
прерываний. */
static void prvHandlingTask( void *pvParameter )
{
    const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 500 );
    BaseType_t xResult;
 
    for( ;; )
    {
        /* Ожидаем уведомления от обрабочиков прерываний. */
        xResult = xTaskNotifyWait(
                        pdFALSE,            /* Не очищать биты при входе. */
                        ULONG_MAX,          /* Очищать все биты при выходе. */
                        &ulNotifiedValue,   /* Куда сохранить уведомление. */
                        xMaxBlockTime );
 
        if( xResult == pdPASS )
        {
            /* Уведомление получено. Смотрим, какие биты установлены. */
            if( ( ulNotifiedValue & TX_BIT ) != 0 )
            {
                /* Обработчик прерывания по передаче данных установил бит. */
                prvProcessTx();
            }
 
            if( ( ulNotifiedValue & RX_BIT ) != 0 )
            {
                /* Обработчик прерывания по приёму данных установил бит. */
                prvProcessRx();
            }
        }
        else
        {
            /* Уведомление не было получено за отведённое время. */
            prvCheckForErrors();
        }
    }
}

Похожие страницы:

Hobby's category: