You are here

Решение №4: Снижение нагрузки на процессор

Перевод может содержать ошибки. Читайте первоисточник: Solution #4 - Reducing the Processor Overhead

Назад: [Как работает FreeRTOS] Вверх: [Как работает FreeRTOS] Вперёд: [Как работает FreeRTOS]

Примечание: этот раздел обновлялся до выхода FreeRTOS версии v4.0.0. В версии v4.0.0 появилась концепция сопрограмм, использование которой может дать новое отличное решение поставленной здесь задачи. Дополнительная информация находится в разделе Tasks and Co-routines.

 

Краткий обзор

В решении №2 показано, как можно создать чистое приложение, полностью используя функциональность ОСРВ. В решении №3 показано, как это можно адаптировать для встраиваемого компьютера с ограниченными ресурсами ОЗУ. А решение №4 является дальнейшей модификацией с целью уменьшить нагрузку на вычислительные ресурсы.

Алгоритм гибридного планировщика (не полностью вытесняющий, и не полностью кооперативный) создаётся путём конфигурирования ядра для кооперативной многозадачности с последующим переключением контекста из обработчика прерываний событий.

 

Реализация


Решение №4: задачи по функциям и их приоритеты

Критическая по времени задача управления агрегатом снова реализуется задачей с высоким приоритетом, но использование кооперативного планировщика требует изменений в её реализации. Ранее хронометраж поддерживался с помощью использования функции API vTaskDelayUntil(). Когда используется вытесняющий планировщик, назначение задаче управления наивысшего приоритета гарантирует запуск задачи в строго определённое время. Теперь используется кооперативный планировщик - следовательно задачи будут переключаться только по явному запросу из исходного кода приложения, поэтому гарантированное время здесь будет потеряно.

Решение №4 использует прерывание от аппаратного таймера, чтобы гарантировать переключение контекста строго с заданной частотой, которая требуется задаче управления. Планировщик гарантирует, что каждое запрошенное переключение контекста будет приводить к переключению к задаче с наивысшим приоритетом из числа готовых к запуску.

Функция сканирования клавиатуры также регулярно требует процессорного времени, поэтому она также выполняется внутри задачи, приводимой в действие прерыванием таймера. Хронометраж этой задачи может быть легко оценён.  Наихудшее время обработки функции управления определяется случаем возникновения ошибки - когда данные от сетевых датчиков не поступают, что приводит к превышению времени ожидания в функции управления. Время выполнения функции сканирования клавиатуры в основном фиксировано. Поэтому мы можем быть уверены, что объединение их функциональности таким образом не приведёт к дрожанию в частоте цикла управления, или, что ещё хуже, к пропуску циклов управления.

Задача обслуживания интерфейса RS232 будет планироваться обработчиком прерывания от интерфейса RS232.

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

 

Концепция работы

Кооперативный планировщик будет выполнять переключение контекста только тогда, когда оно явно запрошивается. Это значительно снижает нагрузку на процессор со стороны ОСРВ (за исключением того факта, что задача простоя больше не может перевести процессор в режим энергосбережения). Задача простоя, включая функциональность встроенного веб-сервера, будет выполняться без каких-либо ненужных прерываний со стороны ядра.

Прерывание, исходящее либо от RS232, либо от аппаратного таймера, будет переключать контекст точно и только тогда, когда это необходимо. Таким образом, задача обслуживания интерфейса RS232 будет по-прежнему вытеснять задачу простоя, и в свою очеред сама по-прежнему может быть вытеснена задачей управления агрегатом. То есть разделение по приоритетам по-прежнему присутствует в приложении.

 

Конфигурация планировщика

Планировщик настраивается для работы в кооперативном режиме. Тики ядра используются только для поддержания актуального значения счётчика тиков в реальном времени.

 

Оценка

В приложении создаётся только две задачи, следовательно, используется меньше ОЗУ, чем в решении №2.
Затраты на переключение контекста выполнения ОСРВ снижены до минимума - хотя больше больше циклов ЦП может использоваться в задаче простоя которая, которя больше не может использовать режимы энергосбережения.
Может быть использовано только некоторое подмножество возможностей ОСРВ. Это требует большего внимания при рассмотрении хронометража и среды (окружения) выполнения на уровне исходного кода приложения, но по-прежнему позволяет создавать более простую структуру проекта по сравнению с решением №1.
Опирается на архитектуру периферийных устройств процессора. Не портируемо.
Проблемы анализа и взаимозависимостей между модулями, которые были рассмотрены в решении №1, начинают проявляться снова, хотя и гораздо в меньшей степени.
Структура проекта может перестать быть масштабируемой, если приложение становится слишком большим.

 

Заключение

Возможности ядра ОСРВ могут использоваться с очень маленькими накладными расходами, что позволяет упростить проектирование даже тех систем, в которых ограничения процессора и объёма ОЗУ не позволяют использовать полностью вытесняющие решения.

 

Пример

Этот пример является частичной реализацией гипотетического приложения, представленного ранее. Используется API FreeRTOS.

 

Высокоприоритетная задача

Задача с высоким приоритетом срабатывает по семафору, выдаваемому в периодически вызываемом обработчике прерывания по таймеру:

/*----------------------------------------------------------------------------*/
void vTimerInterrupt( void )
{
    /* Выдаём семафор. Это будет пробуждать высокоприоритетную задачу. */
    xSemaphoreGiveFromISR( xTimingSemaphore );
    
    /* Высокоприоритетная задача теперь находится в состоянии готовности к */
    /* выполнению. Но, поскольку используется кооперативный планировщик, */
    /* задача не начнёт выполняться, пока не будет явно вызвано */
    /* переключение контекста. */
    taskYIELD();    
}

Обратите внимание, что синтаксис, используемый для принудительного переключения контекста внутри обработчика прерывания отличается для различных портов ОС. Не копируйте этот пример напрямую. Вместо копирования проверьте документацию для используемого вами порта ОС.

Высокоприоритетная задача содержит и функциональность управления агрегатом, и функциональность сканирования клавиатуры. Сначала вызывается PlantControlCycle(), чтобы обеспечить согласование с её хронометражом.

/*----------------------------------------------------------------------------*/
void HighPriorityTaskTask( void *pvParameters )
{
    /* Начинаем с получения семафора. */
    xSemaphoreTake( xSemaphore, DONT_BLOCK );  

    for( ;; )
    {
        /* Следующий вызов получения семафора будет безуспешным, пока */
        /* обработчик прерывания таймера не вызовет xSemaphoreGiveFromISR(). */
        /* Здесь мы используем очень длительное время блокировки, т.к. время */
        /* контролируется частотой прерывания таймера. */
        if( xSemaphoreTake( xSemaphore, VERY_LONG_TIME ) == pdTRUE )
        {
            /* Задача была разблокирована по получении семафора. */
            /* Сейчас время запуска алгоритма управления. */
            PlantControlCycle();
            
            /* Далее выполняем сканирование клавиатуры. */
            if( KeyPressed( &Key ) )
            {
                UpdateDisplay( Key );
            }
        }
        
        /* Теперь возвращаемся обратно на блокировку задачи до очередного */
        /* получения семафора. Выдача опять будет осуществлена в обработчике */
        /* прерывания таймера. */
    }
}


Задача обслуживания интерфейса RS232

Задача RS232 просто блокируется на очереди, ожидающей поступления данных. Обработчик прерывания RS232 должен поместить данные в очередь, что сделает задачу готовой к запуску, и затем выполнить принудительное переключение контекста. Этот механизм работает аналогично псевдокоду прерывания по таймеру, приведённому выше.

Следовательно задача обслуживания RS232 может быть представлена следующим псевдокодом:

/*----------------------------------------------------------------------------*/
void vRS232Task( void *pvParameters )
{
DataType Data;

    for( ;; )
    {
       if( cQueueReceive( xRS232Queue, &Data, MAX_DELAY ) )
        {
            ProcessRS232Data( Data );
        }        
    }
}

Встроенный веб-сервер и управление светодиодом

Оставшаяся функциональность системы размещена внутри функции-ловушки задачи простоя. Это просто функция, которая вызывается каждым циклом задачи простоя.

/*----------------------------------------------------------------------------*/
void IdleTaskHook( void )
{
static TickType_t LastFlashTime = 0;

    ProcessHTTPRequests();
    
    /* Проверяем значение счётчика тиков, чтобы определить, не пора ли */
    /* мигать светодиодом. */
    if( ( xTaskGetTickCount() - LastFlashTime ) > FLASH_RATE )
    {
        UpdateLED();
        
        /* Запоминаем время, чтобы знать, когда будет следующая вспышка. */
        LastFlashTime = xTaskGetTickCount();
    } 
}

 

Hobby's category: