You are here

Решение №3: Сокращение используемого объёма ОЗУ

Перевод может содержать ошибки. Читайте первоисточник: Solution #3 - Reducing RAM Utilisation

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

 

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

 

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

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

 

Реализация


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

Мы уже видели, что требования к хронометражу нашего гипотетического приложения могут быть разделены на три категории:

  1. Жёсткий хронометраж - управление агрегатом.

    Как и ранее, для критически важных функций управления создаётся высокоприоритетная задача.

  2. Хронометраж "только крайний срок" - интерфейс пользователя.

    Решение №3 группирует RS232, сканирование клавиатуры и управление светодиодами в одну задачу со средним приоритетом.

    По указанным ранее причинам желательно, чтобы задача встроенного веб-сервера выполнялась с низким приоритетом. Вместо того, чтобы создавать отдельную задачу для веб-сервера, реализуем функцию-ловушку для задачи простоя, чтобы добавить его функциональность в задачу простоя. Разумеется в этом случае веб-сервер должен быть реализован так, чтобы он никогда не блокировался!

  3. Гибкий хронометраж - светодиоды.

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

Задачи, кроме задачи простоя, будут блокироваться до тех пор, пока некое событие не укажет на необходимость обработки. События могут быть либо внешними (например - нажатие клавиши), либо внутренними (например - завершение счёта таймера).

 

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

Группировка функциональных возможностей в задачу со средним приоритетом имеет три важных преимущества переда реализацией бесконечного цикла, представленной в решении №1:

  1. Использование очереди позволяет задаче со средним приоритетом блокироваться, пока событие не приведёт к готовности данных - и затем немедленно перейти к соответствующей функции для обработки события. Это предотвращает работу процессора впустую - в отличие от реализации с бесконечным циклом, при которой событие будет обработано только после того, как цикл доберётся до соответствующего обработчика.
  2. Использование ядра реального времени убирает необходимость явного учёта планирования времени критической задачи в исходном коде приложения.
  3. Удаление функции встроенного веб-сервена из цикла делает время выполнения более предсказуемым.

Кроме того, функциональность, которая была сгруппирована в одну задачу была взята из нескольких задач, которые в любом случае ранее имели одинаковый приоритет (за исключением функции светодиода). Частота, с которой код с этим приоритетом будет выполняться, не зависит от того, используется одна задача или несколько.

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

 

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

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

 

Оценка

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

 

Заключение

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

 

Пример

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

 

Задача управления агрегатом

Задача управления агрегатом идентична описанной в решении №2.

 

Встроенный веб-сервер

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

 

Задача со средним приоритетом

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

/*----------------------------------------------------------------------------*/
#define DELAY_PERIOD 4
#define FLASH_RATE 1000

void MediumPriorityTask( void *pvParameters )
{
xQueueItem Data;
TickType_t FlashTime;

    InitialiseQueue();
    FlashTime = xTaskGetTickCount();
    
    for( ;; )
    {
        do
        {
            // A
            if( xQueueReceive( xCommsQueue, &Data, DELAY_PERIOD ) )
            {
                ProcessRS232Characters( Data.Value );
            }
            
          // B
        } while ( uxQueueMessagesWaiting( xCommsQueue ) );
        
        // C
        if( ScanKeypad() )
        {
            UpdateLCD();
        }
        
        // D
        if( ( xTaskGetTickCount() - FlashTime ) >= FLASH_RATE )
        {
            FlashTime = xTaskGetTickCount();
            UpdateLED();
        }
    }

    /* Здесь никогда не должны оказаться. */
    return 0;
}

Пояснения к меткам в представленном выше фрагменте кода:

  1. Сначала задача блокируется на ожидании события связи. Время блокировки относительно короткое.
  2. Цикл do-while выполняется до тех пор, пока в очереди данных от порта RS232 не останется никаких данных. Эту реализацию пришлось бы изменить, если бы данные поступали слишком быстро, и очередь никогда не оказывалась бы пустой.
  3. Либо очередь данных пуста, либо данные не поступили в течение указанного времени блокировки DELAY_PERIOD. Максимальное время, которое можно потратить на блокировку в ожидании данных довольно мало, чтобы клавиатура сканировалась достаточно часто, чтобы соответствовать указанным ограничениям хронометража.
  4. Проверяем, не пришло ли время мигать светодиодом. Имеется некоторое дрожание частоты, с которой выполняется эта строка, но требования к хронометражу светодиодов довольно гибкие, и соответствуют такой реализации.

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

Hobby's category: