Операционная система FreeRTOS
FreeRTOS
Примечание
«Си для встраиваемых систем»
Это онлайн-версия книги «Си для встраиваемых систем».
Мы уже рассмотрели основные концепции ОСРВ, настало время разобрать одну из них — FreeRTOS.
Если рассмотреть типичное приложение с использованием FreeRTOS, то можно выделить три слоя поверх железа: пользовательский код, платформонезависимый код и платформозависимый код.
Платформонезависимый код в свою очередь можно разделить на две подчасти.
Задачи. Основное назначение ядра — это создание, уничтожение и управления задачами, за что отвечают два файла:
tasks.cиtasks.h, где заключено около половины всего кода.Связь. Сами задачи так или иначе обмениваются данными, что создаёт проблему: нужно обеспечить безопасную и гарантированную их передачу. На решение этой проблемы также приходится около половины всего кода ядра. За связь отвечают файлы
queue.cиqueue.h, а критические ресурсы работают через семафоры и мьютексы (semaphr.cиsemaphr.h).
Аппаратное сопряжение. Большая часть кода FreeRTOS платформонезависима, т. е. может быть спокойно откомпилирована и запущена как на 8051, так и на ARM-ядрах. Однако операционная система не может полностью абстрагироваться от железа, а посему программно-зависимый код всё же необходим. Данная часть составляет примерно 5% от всего FreeRTOS и заключается в
port.c,portmacro.h.
Такой подход позволяет организовать поддержку большого количества платформ (ARM Cortex M, 8051, PIC и другие) и компиляторов (GCC, IAR, CodeWarrior и др.) — изменяется всего 5% кода вместо всей операционной системы. Сама ОС довольно гибкая в конфигурации и может быть настроена как для слабого одноядерного микроконтроллера с парой задач в программной части, так и для многоядерного МК с поддержкой стека TCP/IP, файловой системой и т. д. Настройка осуществляется через файл FreeRTOSConfig.h изменением #define-макросов. Ниже приведён пример настройки планировщика, частоты тактирования ядра МК, установки временного среза и максимального количества приоритетов.
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ (SystemCoreClock)
#define configTICK_RATE_HZ ((TickType_t)1000)
#define configMAX_PRIORITIES (7)
Подробное описание конфигурационного файла можно найти в официальной документации. Кроме упомянутых выше файлов, присутствуют и другие: list.c / list.h реализует структуру данных двусвязного списка, который используется для работы планировщика; файл portable.h содержит макросы платформозависимых констант; в StackMacros.h хранятся макросы для контроля переполнения стека; и другие.
Компания ARM, разработавшая ядро и библиотеку CMSIS, также предоставляет обёртку (англ. wrapper) для систем реального времени (файлы cmsis_os.c и cmsis_os.h). Данный слой абстракции немного замедляет работу (будет выполняться лишний код), но позволяет легко переходить с одной операционной системы на другую. Так, если вы будете создавать проект для микроконтроллера STM32, используя утилиту STM32CubeMX, то она автоматически обернёт операционную систему (FreeRTOS) в CMSIS-RTOS API. Отличие по большей части будет заключаться лишь в названии функций. Например, для запуска планировщика задач вам придётся вызывать функцию osKernelStart() вместо vTaskStartScheduler().
osStatus osKernelStart (void) {
vTaskStartScheduler();
return osOK;
}
Далее мы будем рассматривать родные функции FreeRTOS (9-й версии, последней на время написания книги), делая пометку об их эквиваленте из CMSIS-RTOS API.
Ниже рассмотрим основные возможности системы; само описание не является исчерпывающим, но достаточно для начала работы.