You are here

Файл FreeRTOSConfig.h

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

Назад: [Advanced] Вверх: [Advanced] Вперёд: [Advanced]

 

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

Каждый демонстрационный проект, включённый в поставку FreeRTOS, содержит свой собственный файл FreeRTOSConfig.h. Некоторые демо-проекты довольно старые и могут содержать не все доступные в последней версии RTOS конфигурационные параметры. Отсутствующие параметры устанавливаются в значения по-умолчанию в исходных файлах RTOS.

Настройки FreeRTOS в этом файле в некоторых местах документации называются "константами времени компиляции". - прим. переводчика.

Приведём типичное определение параметров в файле FreeRTOSConfig.h и подробно остановимся на описании каждого из них:

Пример конфигурационного файла

/*----------------------------------------------------------------------------*/
#ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H

/* Здесь удобно добавить заголовочные файлы, которые необходимы вашему приложению. */ #include "something.h"

/* Основные настройки. */ #define configUSE_PREEMPTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 #define configUSE_TICKLESS_IDLE 0 #define configCPU_CLOCK_HZ 60000000 #define configTICK_RATE_HZ 250 #define configMAX_PRIORITIES 5 #define configMINIMAL_STACK_SIZE 128 #define configMAX_TASK_NAME_LEN 16 #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 #define configUSE_TASK_NOTIFICATIONS 1 #define configUSE_MUTEXES 0 #define configUSE_RECURSIVE_MUTEXES 0 #define configUSE_COUNTING_SEMAPHORES 0 #define configUSE_ALTERNATIVE_API 0 /* Устарело! */ #define configQUEUE_REGISTRY_SIZE 10 #define configUSE_QUEUE_SETS 0 #define configUSE_TIME_SLICING 0 #define configUSE_NEWLIB_REENTRANT 0 #define configENABLE_BACKWARD_COMPATIBILITY 0 #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 /* Настройки для выделения памяти. */ #define configSUPPORT_STATIC_ALLOCATION 1 #define configSUPPORT_DYNAMIC_ALLOCATION 1 #define configTOTAL_HEAP_SIZE 10240 #define configAPPLICATION_ALLOCATED_HEAP 1 /* Настройки для функций-ловушек. */ #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCHECK_FOR_STACK_OVERFLOW 0 #define configUSE_MALLOC_FAILED_HOOK 0 #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 /* Настройки для сбора времени выполнения и статистики задач. */ #define configGENERATE_RUN_TIME_STATS 0 #define configUSE_TRACE_FACILITY 0 #define configUSE_STATS_FORMATTING_FUNCTIONS 0 /* Настройки для созадач. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES 1 /* Настройки для программных таймеров. */ #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY 3 #define configTIMER_QUEUE_LENGTH 10 #define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE /* Настройки поведения вложенных прерываний. */ #define configKERNEL_INTERRUPT_PRIORITY [зависит от архитектуры ядра процессора] #define configMAX_SYSCALL_INTERRUPT_PRIORITY [зависит от архитектуры ядра процессора и приложения] #define configMAX_API_CALL_INTERRUPT_PRIORITY [зависит от архитектуры ядра процессора и приложения] /* Макроопределение для захвата ошибок во время разработки. */ #define configASSERT( ( x ) ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) /* Настройки FreeRTOS, зависящие от архитектуры ядра микроконтроллера/процессора. */ #define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 /* Дополнительные настройки - большинство современных компоновщиков автоматически исключит
неиспользуемые функции из сборки. */
#define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_xResumeFromISR 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 #define INCLUDE_xTaskGetSchedulerState 1 #define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_uxTaskGetStackHighWaterMark 0 #define INCLUDE_xTaskGetIdleTaskHandle 0 #define INCLUDE_eTaskGetState 0 #define INCLUDE_xEventGroupSetBitFromISR 1 #define INCLUDE_xTimerPendFunctionCall 0 #define INCLUDE_xTaskAbortDelay 0 #define INCLUDE_xTaskGetHandle 0 #define INCLUDE_xTaskResumeFromISR 1 /* Заголовочный файл, который определяет макрос трассировки, может быть включен здесь. */ #endif /* FREERTOS_CONFIG_H */
/*----------------------------------------------------------------------------*/

 

Описание параметров конфигурационного файла 

 configUSE_PREEMPTION

Устанавливается в 1 для использования вытесняющего планировщика RTOS, либо в 0 для использования кооперативной многозадачности.

 configUSE_PORT_OPTIMISED_TASK_SELECTION

Некоторые варианты портирования имеют два метода для выбора следующей запускаемой задачи - основной метод и платформозависимый метод.

Основной метод:

  • Используется, когда configUSE_PORT_OPTIMISED_TASK_SELECTION установлен в 0, или когда port specific метод не реализован.
  • Может быть использован на всех платформах, для которых FreeRTOS была портирована.
  • Полностью написан на C, что делает его менее эффективным, чем платформозависимый метод.
  • Не накладывает ограничений на максимальное количество доступных приоритетов.

Платформозависимый метод:

  • Исползьуется, когда configUSE_PORT_OPTIMISED_TASK_SELECTION установлен в 1.
  • Доступен не для всех платформ.
  • Использует одну или несколько специфических ассемблерных команд (как правило [CLZ] (Count Leading Zeros) или аналогичные), поэтому может использоваться только на той архитектуре, для которой специально написан.
  • Более эффективен, чем основной метод.
  • Обычно накладывается ограничение на количество приоритетов, равное 32.
 configUSE_TICKLESS_IDLE

Установливается configUSE_TICKLESS_IDLE в 1 для использования режима "энергосберегающего простоя без тиков, или в 0 для выработки прерываний от системного таймера во всех состояниях. Режим "энергосберегающий простой без тиков" доступен не для всех платформ.

 configUSE_IDLE_HOOK

Установите значение 1, если хотите использовать ловушку простоя (idle hook), или значение 0, чтобы не использовать её.

 configUSE_MALLOC_FAILED_HOOK

Ядро использует вызов pvPortMalloc() для выделения памяти из кучи каждый раз, когда создаётся задача, очередь или семафор. Официальная поставка FreeRTOS включает в себя четыре схемы работы с памятью для этих целей. Эти схемы реализованы в исходных файлах  heap_1.c, heap_2.c, heap_3.c, heap_4.c and heap_5.c соответственно. configUSE_MALLOC_FAILED_HOOK имеет значение только тогда, когда используется одна из этих трёх примеров схем. /Это как? Три, четыре или пять?!/

Функция ловушки ошибки маллок() есть функция ловушки (или обратного вызова), которая, если определена и сконфигурирована, будет вызываться когда pvPortMalloc() возвращает NULL. А значение NULL будет возвращено только если оставшаяся доступная для FreeRTOS память недостаточна для выделения области запрошенного размера.

Если configUSE_MALLOC_FAILED_HOOK установлено в 1, то в приложении должна быть определена функция-ловушка ошибки выделения памяти. Если  configUSE_MALLOC_FAILED_HOOK установлена в 0, то ошибка выделеня памяти в malloc() не будет вызывать ловушку даже если та определена. Функция ловушки ошибки выделения памяти должна иметь название и прототип, как указано ниже:

void vApplicationMallocFailedHook( void );
 configUSE_DAEMON_TASK_STARTUP_HOOK

Если параметры configUSE_TIMERS и configUSE_DAEMON_TASK_STARTUP_HOOK оба установлены в 1, тогдаприложение может определить функцию-ловушку по шаблону, который приведён ниже. Функция-ловушка будет вызываться ровно один раз, когда задача демона RTOS (так же известная как задача обслуживания таймера) запускается первый раз. В эту функцию-ловушку может быть помещён любой код инициализации приложения, для которого требуется запуск RTOS.

void vApplicationDaemonTaskStartupHook( void );
 configUSE_TICK_HOOK

Устанавливается в 1, если вы хотите использовать ловушку тиков ОСРВ, или в 0, если она не нужна.

 configCPU_CLOCK_HZ

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

Проще говоря: укажите частоту тактирования таймера, который используется для выработки прерываний тиков ОСРВ, чтобы была возможность настроить его таким образом, чтобы он отсчитывал нужный период тиков ОСРВ.

 configTICK_RATE_HZ

Частота повторения прерываний тиков RTOS.

Прерывания тиков используются для измерения отрезков времени. Поэтому более высокая частота позволяет измерять время с бОльшим разрешением. Однако высокая частота тиков также означает, что ядро ОСРВ будет использовть больше процессорного времени, и, как следствие, будет менее эффективным. Все примеры, включённые в поставку FreeRTOS используют частоту тиков 1000 Гц. Такая частота используется для тестирования ядра ОСРВ, а для реальных приложений обычно достаточно меньших значений.

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

More than one task can share the same priority. The RTOS scheduler will share processor time between tasks of the same priority by switching between the tasks during each RTOS tick. Следовательно, высокая частота тиков будет также уменьшать временной интервал ('time slice'), отводимый каждой  задаче.

 configMAX_PRIORITIES

Количество приоритетов, доступных для задач приложения. Любое количество задач может использовать один и тот же уровень приоритета. Созадачи расставлены по приоритетам отдельно - см. configMAX_CO_ROUTINE_PRIORITIES.

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

 configMINIMAL_STACK_SIZE

Размер стека, используемый задачей ожидания. Как правило это значение не должно быть меньше, чем установленное в файле FreeRTOSConfig.h, предоставляемом в составе демонстрационного приложения для порта, который вы используете.

Как и в параметре размера стека для функций xTaskCreate() и xTaskCreateStatic(), в параметре configMINIMAL_STACK_SIZE размер стека указывается не в байтах, а в словах. Если размер элемента, помещаемого в стек, равен 32 битам, то указание размера стека равным 100 будет означать выделение под него 400 байт (каждый 32-битный элемент стека занимает 4 байта).

 configMAX_TASK_NAME_LEN

Максимально допустимая длина описательного имени, присваиваемого задаче при её создании. Длина указывается в количестве символов, включая завершающий байт NULL (0x00).

 configUSE_TRACE_FACILITY

Устанавливаем в 1, если хотим использовать дополнительные поля структуры и вспомогательные функции для визуализации и отслеживания выполнения.

 configUSE_STATS_FORMATTING_FUNCTIONS

Установите в 1 configUSE_TRACE_FACILITY и configUSE_STATS_FORMATTING_FUNCTIONS для включения в сборку функций vTaskList() и vTaskGetRunTimeStats(). Если значение установить в 0, эти функции не будут включены в сборку. 

 configUSE_16_BIT_TICKS

Время измеряется в "тиках" - это количество раз, сколько вызывалось прерывание тиков ОС с момента старта ядра. Количество тиков хранится в переменной, имеющей тип TickType_t.

От значения настройки configUSE_16_BIT_TICKS зависит размер этой переменной. Если 1 - TickType_t определён (typedef) как 16-битное беззнаковое значение. Если 0 - как 32-битное беззнаковое.

Использовние 16-битного типа счётчика существенно улучшит производительноть на 8- и 16-битных архитектурах, но ограничит максимально значение величиной 65535 тиков. Поэтому например при частоте тиков 250 максимальное время, на которое задача может задержаться (delay), либо быть заблокирована, составит 262 секунды. Для сравнения: в случае 32-битного счётчика это время будет 17179869 секунд.

 configIDLE_SHOULD_YIELD

Этот параметр управляет поведением задач, имеющих приоритет простоя. Он имеет значение если:

  1. Используется вытесняющий планировщик.
  2. Приложение создаёт задачи, которые выполняются с приоритетом простоя.

Задачи, которые имеют одинаковый приоритет, переключаются с использованием алгоритма циклического перебора с выделением времени. Каждая задача будет в порядке выбираться для перевода в запущенное состояние, но может оставаться запущенной не весь квант времени ОС. Например, задача может быть вытеснена процессом с бОльшим приоритетом, может уступить процессорное время, может перейти в заблокированное состояние раньше следующего прерывания тика ОС.

Если значение параметра configUSE_TIME_SLICING установлено в 1 (или не определено), то задачи, имеющие одинаковый приоритет, будут иметь одинаковый временной интервал для использования процессорного времени. Если при этом ни одна задача не была вытеснена, то можно предположить, что каждой задаче с данным приоритетом будет выделено одинаковое количество процессорного времени - и если приоритет выше чем приоритет простоя, то это действительно так.

Если же задачи имеют приоритет простоя, поведение может немного отличаться. Если configIDLE_SHOULD_YIELD установлен в 1, то задача простоя будет немедленно завершена, если любая другая задача с приоритетом простоя будет готова к запуску. Это гарантирует, что на задачу простоя будет затрачено минимальное количество процессорного времени, если есть задачи, готовые к запуску. Однако такое поведение может иметь некоторые нежелательные эффекты (в зависимости от потребностей вашего приложения), как показано ниже:

Рисунок выше иллюстритует схему выполнения четырёх задач, которые запущены с приоритетом простоя. Задача A, B и C - это задачи приложения. Задача I - это задача простоя (idle task). Переключение контекста выполняется с постоянным периодом в моменты времени T0, T1, ..., T6. И когда задача простоя уступает процессорное время, запускается задача A - но задача простоя уже использовала часть текущего кванта времени ОС. В результате задачи I и A делят один и тот же квант. Следовательно задачи B и C получают больше процессорного времени, чем задача A.

Чтобы избежать этого:

  • По возможности используйте ловушку простоя (idle hook) вместо отдельных задач с приоритетом простоя.
  • Создавайте все задачи приложения с приоритетом выше, чем приоритет простоя.
  • Устанавливайте configIDLE_SHOULD_YIELD в 0.

Установка configIDLE_SHOULD_YIELD в 0 предотвращает уступание процессорного времени задачей простоя до завершения кванта времени ОС. времени активизацию задачи простоя пока не закончится очередной интервал. Это гарантирует, что всем задачам с приоритетом простоя будет выделяться одинаковое количество процессорного времени (если задачи не будут вытесняться процессами с бОльшим приоритетом). Обратная сторона медали - для задачи простоя выделяется большая доля общего времени обработки.

 configUSE_TASK_NOTIFICATIONS

Если значение параметра configUSE_TASK_NOTIFICATIONS установлено в 1 (или не определено), в сборку будет включён функционал уведомлений и функции API для работы с уведомлениями.

Если значение параметра configUSE_TASK_NOTIFICATIONS установлено в 0, функционал уведомлений и функции API для работы с ними не будут включены в сборку.

Каждая задача использует 8 дополнительных байт ОЗУ, если уведомления включены в сборку.

 configUSE_MUTEXES

Установка этого параметра в 1 включает функционал мьютексов в сборку. Если установить в 0, мьютексы не будут добавлены к сборке. Будьте внимательны: как следует изучите различия между мьютексами и бинарными семафорами, и как они используются во FreeRTOS.

 configUSE_RECURSIVE_MUTEXES

Установка этого параметра в 1 добавляет в сборку функционал рекурсивных мьютексов, и наоборот, установка в 0 убирает рекурсивные мьютексы из сборки.

 configUSE_COUNTING_SEMAPHORES

Установка этого параметра в 1 добавляет в сборку функционал счётных семафоров. И наоборот, установка в 0 убирает счётные семафоры из сборки.

 configUSE_ALTERNATIVE_API

Установка в 1 включает в сборку 'альтернативные' функции работы с очередями, и наоборот, установка в 0 исключает из сборки эти функции. Функции альтернативного API описаны в заголовочном файле queue.h. Эти функции устарели, и не должны использоваться в новых проектах.

 configCHECK_FOR_STACK_OVERFLOW

Подробное описание использования этого параметра приведено на странице "проверка переполнения стека".

 configQUEUE_REGISTRY_SIZE

Реестр очереди имеет два предназначения, оба из которых связаны с отладкой с поддержкой ядра ОС: The queue registry has two purposes, both of which are associated with RTOS kernel aware debugging:

  1. Это позволяет текстовому имени быть связанным с очередью для лёгкой идентификации очереди в GUI отладчика. It allows a textual name to be associated with a queue for easy queue identification within a debugging GUI.
  2. Он содержит информацию, необходимую отладчику для определения размещения каждой зарегистрированной очереди и семафора. It contains the information required by a debugger to locate each registered queue and semaphore.

Реестр очереди не имеет смысла, пока вы не используете отладчик с поддержкой ядра FreeRTOS. The queue registry has no purpose unless you are using a RTOS kernel aware debugger.

Параметр configQUEUE_REGISTRY_SIZE определяет максимальное количество очередей и семафоров, которые могут быть зарегистрированы. Зарегистрированы должны быть только те очереди и семафоры, которые вы хотите просмотреть с помощью отладчика с поддержкой ядра FreeRTOS. Дополнительную информацию вы найдёте в документации по функциям API vQueueAddToRegistry() и vQueueUnregisterQueue().

Другое описание:

Устанавливает максимальное количество очередей и семафоров, на которые можно ссылаться из реестра очередей одновременно. Только очереди и семафоры, которые должны просматриваться в интерфейсе отладки с поддержкой ядра, должны быть зарегистрированы. Реестр очереди требуется только при использовании отладчика с поддержкой ядра. Во всех других случаях это не имеет смысла и может быть опущено путем установки configQUEUE_REGISTRY_SIZE равным 0 или путем исключения определения константы конфигурации configQUEUE_REGISTRY_SIZE в целом.

 configUSE_QUEUE_SETS

Установка этого параметра в 1 добавляет в сборку функционал набора очередей (queue set) (возможность блокировки, или ожидания, на нескольких очередях и семафорах), установка в 0 исключает из сборки этот функционал.

 configUSE_TIME_SLICING

По-умолчанию (если configUSE_TIME_SLICING не определён, или configUSE_TIME_SLICING установлен в 1) FreeRTOS использует приоритетный вытесняющий планировщик с квантами времени. Это означает, что планировщик всегда будет запускать задачу с наивысшим приоритетом из числа находящихся в состоянии готовности, и будет переключаться между задачами с одинаковым приоритетом при каждом прерывании тика ОС. Если же configUSE_TIME_SLICING установлен в 0, то планировщик всё равно будет запускать задачу с наивысшим приоритетом, которая находится в состоянии готовности, но не будет переключать между задачами с одинаковым приоритетом просто потому, что произошло прерывание по тику ОС.

 configUSE_NEWLIB_REENTRANT

Если параметр configUSE_NEWLIB_REENTRANT установлен в 1, то при использовании библиотеки newlib для каждой задачи будет выделена своя структура для обеспечения реентерабельности.

Если configUSE_NEWLIB_REENTRANT установлен в 1, то для каждого созданного задания будет выделена структура повторного запуска newlib.

Примечание: поддержка newlib включена по многочисленным просьбам, но при этом не используется самими разрабочиками FreeRTOS. И FreeRTOS не несёт ответственности за результат работы newlib. Пользователь должен хорошо знаком с этой библиотекой и самостоятельно предоставлять общесистемные реализации необходимых заглушек. Имейте в виду, что на момент написания текущая версия newlib реализует общесистемный вызов malloc(), который должен быть снабжён блокировками.

 configENABLE_BACKWARD_COMPATIBILITY

Заголовочный файл FreeRTOS.h содержит набор макросов #define, которые сопоставляют имена типов данных, используемых в версиях FreeRTOS до версии 8.0.0, с именами, используемыми в версиях FreeRTOS начиная с 8.0.0. Эти макросы позволяют обновлять FreeRTOS до версии начиная с 8.0.0 без внесения изменений в код приложения. Установка configENABLE_BACKWARD_COMPATIBILITY в 0 в файле FreeRTOSConfig.h исключает эти макросы из сборки, и при этом разрешает проверку на неиспользование имён типов данных, использовавшихся до версии 8.0.0.

 configNUM_THREAD_LOCAL_STORAGE_POINTERS

Устанавливает количество индексов в массиве локального хранилища каждой задачи.

Не осознал. Пока оставляю оригинал. Sets the number of indexes in each task's thread local storage array.

 configSUPPORT_STATIC_ALLOCATION

Если параметр configSUPPORT_STATIC_ALLOCATION установлен в 1, объекты ОС могут создаваться с использованием ОЗУ, предоставленного разработчиком приложения.

Если параметр configSUPPORT_STATIC_ALLOCATION установлен в 0, объекты ОС могут создаваться только с использованием ОЗУ, выделяемого из кучи ОС.

Если configSUPPORT_STATIC_ALLOCATION не определён, его значение устанавливается по умолчанию в 0.

Если параметр configSUPPORT_STATIC_ALLOCATION установлен в 1, разработчик приложения должен предоставить две функции обратного вызова: vApplicationGetIdleTaskMemory() для предоставления памяти для использования задачей простоя ОС, и (если configUSE_TIMERS установлен в 1) vApplicationGetTimerTaskMemory() для предоставления памяти для использования демоном ОСРВ/сервисной задачей таймеров. Ниже приведён пример.

/*----------------------------------------------------------------------------*/
/* configSUPPORT_STATIC_ALLOCATION установлен в 1, поэтому приложение должно
предоставить реализацию функции vApplicationGetIdleTaskMemory() для
предоставления памяти, которая будет использоваться задачей простоя. */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
                                    StackType_t **ppxIdleTaskStackBuffer,
                                    uint32_t *pulIdleTaskStackSize )
{
/* Если буферы, предоставленные задаче простоя, объявляются внутри этой функции,
то они должны быть объявлены как статические. Иначе они будут расположены в
стеке, и не будут существовать после завершения функции. */
static StaticTask_t xIdleTaskTCB;
static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];

    /* Раздаём указатель на структуру StaticTask_t, в которой будет сохраняться
    состояние задачи простоя. */
    *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;

    /* Раздаём адрес массива, который будет использоваться как стек задачи
    простоя. */
    *ppxIdleTaskStackBuffer = uxIdleTaskStack;

    /* Раздаём размер массива, на который указывает *ppxIdleTaskStackBuffer.
    Обратите внимание, что, поскольку массив обязательно имеет тип StackType_t,
    configMINIMAL_STACK_SIZE определяется в словах, а не байтах. */
    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}

/*----------------------------------------------------------------------------*/
/* configSUPPORT_STATIC_ALLOCATION и configUSE_TIMERS оба установлены в 1,
поэтому приложение должно предоставить реализацию
vApplicationGetTimerTaskMemory() для предоставления памяти, которая будет
использоваться сервисной задачей таймеров. */
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
                                     StackType_t **ppxTimerTaskStackBuffer,
                                     uint32_t *pulTimerTaskStackSize )
{
/* Если буферы для сервисной задачи таймеров объявляются внутри этой функции,
то они должны объявляться статическими. Иначе они будут расположены в стеке,
и перестанут существовать после выхода из этой функции. */
static StaticTask_t xTimerTaskTCB;
static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];

    /* Раздаём указатель на структуру StaticTask_t, в которой сервисная задача
    таймеров будет сохранять своё состояние. */
    *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;

    /* Раздаём адрес массива, который будет использоваться как стек сервисной
    задачи таймеров. */
    *ppxTimerTaskStackBuffer = uxTimerTaskStack;

    /* Раздаём размер массива, на который ссылается *ppxTimerTaskStackBuffer.
    Обратите внимание, что, поскольку массив обязательно имеет тип StackType_t,
    configTIMER_TASK_STACK_DEPTH определяется в словах, а не байтах. */
    *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}

Пример функций обратного вызова, которые должны быть предоставлены разработчиком приложения для поддержки ОЗУ, используемого задачей простоя и сервисной задачей таймеров, если configSUPPORT_STATIC_ALLOCATION установлен в 1.

Дополнительную информацию можно найти на странице "Статическое или динамическое выделение памяти".

 configSUPPORT_DYNAMIC_ALLOCATION

Если параметр configSUPPORT_DYNAMIC_ALLOCATION установлен в 1, объекты ОС могут создаваться используя ОЗУ, которое автоматически выделяется из кучи FreeRTOS.

Если параметр configSUPPORT_DYNAMIC_ALLOCATION установлен в 0, объекты ОС могут быть расположены только в ОЗУ, предоставляемом разрабочиком приложения.

Если параметр configSUPPORT_DYNAMIC_ALLOCATION не определён, его значение устанавливается по умолчанию в 1.

Дополнительную информацию можно найти на странице "Статическое или динамическое выделение памяти".

 configTOTAL_HEAP_SIZE

Общий объём ОЗУ, доступный в куче FreeRTOS.

Это значение будет только использовано если параметр configSUPPORT_DYNAMIC_ALLOCATION установлен в 1, и приложение использует один из примеров схем распределения памяти, предоставляемых в составе исходных кодов FreeRTOS. Детальная информация предоставлена в разделе "конфигурация памяти".

 configAPPLICATION_ALLOCATED_HEAP

По-умолчанию куча FreeRTOS обявляется FrerRTOSью и размещается в памяти линкером. Установка параметра configAPPLICATION_ALLOCATED_HEAP в 1 позволяет разработчику приложения самостоятельно объявлять кучу, что позволяет разработчику размещать её в том месте в памяти, где он считает нужным.

Если используется heap_1.c, heap_2.c или heap_4.c, и configAPPLICATION_ALLOCATED_HEAP установлен в 1, то разрабочик приложения должен предоставить массив типа uint8_t с именем и размером, как показано ниже. Массив будет использован как куча FreeRTOS. Как разместить массив в нужном месте в памяти - зависит от используемого компилятора, поэтому подробности ищите в документации по компилятору.

uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
configGENERATE_RUN_TIME_STATS

Этот параметр описан на странице "Run Time Statistics".

 configUSE_CO_ROUTINES

Установка в 1 добавляет в сборку функционал сопрограмм, установка в 0 убирает его из сборки. Для добавления сопрограмм файл croutine.c должен быть включён в проект.

 configMAX_CO_ROUTINE_PRIORITIES

Количество приоритетов, доступных созадачам приложения. Любое количество созадач может использовать один и тот же приоритет. При этом задачи отдельно распределяются по приоритетам - см. параметр configMAX_PRIORITIES.

 configUSE_TIMERS

Установка в 1 добавляет в сборку функционал программных таймеров, установка в 0 убирает его из сборки. Полная информация находится на странице "Программные таймеры во FreeRTOS".

 configTIMER_TASK_PRIORITY

Устанавливает приоритет демона/сервисной задачи таймеров. Полная информация находится на странице "Программные таймеры во FreeRTOS".

 configTIMER_QUEUE_LENGTH

Устанавливает длину очереди команд программных таймеров. Полная информация находится на странице "Программные таймеры во FreeRTOS".

 configTIMER_TASK_STACK_DEPTH

Устанавливает глубину стека, выделенного для службы/демона задачи программных таймеров. Полная информация находится на странице "Программные таймеры во FreeRTOS".

 configKERNEL_INTERRUPT_PRIORITY,
 configMAX_SYSCALL_INTERRUPT_PRIORITY and
 configMAX_API_CALL_INTERRUPT_PRIORITY

Порты ОС для ARM Cortex-M3, PIC24, dsPIC, PIC32, SuperH and RX600 содержат параметр configKERNEL_INTERRUPT_PRIORITY.

Порты ОС для PIC32, RX600, ARM Cortex-A and ARM Cortex-M содержат параметр configMAX_SYSCALL_INTERRUPT_PRIORITY.

В случае использования ARM Cortex-M3 и ARM Cortex-M4 обязательно прочитайте примечание в конце этого раздела!

Параметр configMAX_API_CALL_INTERRUPT_PRIORITY это новое имя для параметра configMAX_SYSCALL_INTERRUPT_PRIORITY, которое используется только в новых портах ОС. Оба названия эквивалентны.

configKERNEL_INTERRUPT_PRIORITY должен быть установлен в самый низкий приоритет из доступных.

Обратите внимание на следующую дискуссию о том, что только функции API, заканчивающиеся на "FromISR", могут вызваться из  обработчиков прерываний.

Для портов ОС, в которых используется configKERNEL_INTERRUPT_PRIORITY:
configKERNEL_INTERRUPT_PRIORITY устанавливает приоритет прерывания, используемого самим ядром ОС. Прерывания, которые вызывают функции API, должны также выполняться с этим приоритетом. Прерывания которые не используют вызовов функций API могут выполняться с более высокими приоритетоми и, следовательно, их выполнение никогда не притормаживается активностью ядра ОСРВ (внутри ограничений самой аппаратуры).(within the limits of the hardware itself).

Для портов ОС, в которых используется и configKERNEL_INTERRUPT_PRIORITY, и configMAX_SYSCALL_INTERRUPT_PRIORITY:
configKERNEL_INTERRUPT_PRIORITY устанавливает приоритет прерывания, используемого самим ядром. А configMAX_SYSCALL_INTERRUPT_PRIORITY задаёт наивысший приоритет для прерывания, из которого могут быть вызваны interrupt-safe функции API.

Полная модель вложенности прерываний достигаетс установкой параметра configMAX_SYSCALL_INTERRUPT_PRIORITY выше (т.е. с более высоким уровнем приоритета), чем configKERNEL_INTERRUPT_PRIORITY. Это означает, что ядро FreeRTOS не полностью запрещает прерывания, даже внутри критических секций. Мало того, это достигается без недостатков архитектуры сегментированного ядра. Однако обратите внимание, что некоторые некоторые архитектуры микроконтроллеров будут запрещать прерывания (аппаратно) при приёме нового прерывания - это означает, что прерывания неизбежно отключаются на короткий промежуток времени между приёмом аппаратного прерывания и повторным разрешением прерывания во FreeRTOS.

(оставлено для уточнения перевода выше) A full interrupt nesting model is achieved by setting configMAX_SYSCALL_INTERRUPT_PRIORITY above (that is, at a higher priority level) than configKERNEL_INTERRUPT_PRIORITY. This means the FreeRTOS kernel does not completely disable interrupts, even inside critical sections. Further, this is achieved without the disadvantages of a segmented kernel architecture. Note however, certain microcontroller architectures will (in hardware) disable interrupts when a new interrupt is accepted - meaning interrupts are unavoidably disabled for the short period between the hardware accepting the interrupt, and the FreeRTOS code re-enabling interrupts.

Прерывания, которые не используют вызовы функций API, могут выполняться с приоритетом выше configMAX_SYSCALL_INTERRUPT_PRIORITY и, следовательно, никогда не будут задержаны выполнением ядра ОС.

Например, представим себе гипотетический микроконтроллер, у которого есть 8 уровней приоритета прерываний: 0 означает самый низкий, а 7 - самый высокий (см. примечание в конце раздела, касающееся ядра ARM Cortex-M3). На изображении ниже показано, что можно, и что нельзя выполнять на каждом уровне приоритета, если два конфигурационных параметра установлены в 4 и 0, как указано:


Пример конфигурации приоритетов прерываний.

Эти конфигурационные параметры позволяют реализовать очень гибкую схему обработки прерываний:

  • 'Задачи'-обработчики прерываний могут быть написаны и расставлены по приоритетам как и все прочие задачи в системе. Это задачи, которые будут разбужены прерыванием. Сам обработчик прерывания должен быть настолько коротким, насколько это возможно - он просто захватывает данные, а затем запускает задачу-обработчик с высоким приоритетом. Тогда обработчик прерывания возвращает управление прямиком в задачу-обработчик - получается, что прерывание обрабатывается непрерывно во времени так же, как это было бы сделано внутри обработчика прерывания. Преимущество этого способа состоит в том, что  все прерывания остаются разрешёнными, пока запущена задача-обработчик.
  • Порты ОС, которые реализуют configMAX_SYSCALL_INTERRUPT_PRIORITY, делают это ещё развёрнутее - разрешая полностью вложенную модель, где прерывания между приоритетом ядра ОС и configMAX_SYSCALL_INTERRUPT_PRIORITY могут вложить и сделать соответствующие вызовы API. Прерывания с приоритетом выше configMAX_SYSCALL_INTERRUPT_PRIORITY никогда не задерживаются активностью ядра ОС.
  • Обработчики прерываний с максимальным приоритетом системного вызова никогда не маскируются самим ядром ОС, поэтому из "отзывчивость" не зависит от функциональности ядра ОС. Это идеально для прерываний, которые очень высокой временнОй точности - например, прерывание, которое выполняет коммутацию мотора. Однако такие обработчики прерываний не могут использовать функции API FreeRTOS.

Чтобы использовать эту схему в приложении необходимо придерживаться следующего правила: любые прерывания, использующие вызовы функций API, должны иметь тот же приоритет, что и ядро ОС (указанный в параметре configKERNEL_INTERRUPT_PRIORITY), или приоритет меньший либо равный указанному в параметре configMAX_SYSCALL_INTERRUPT_PRIORITY для тех портов ОС, в которых этот параметр присутствует.

Специальное примечание для случаев использования архитектур ARM Cortex-M3 и ARM Cortex-M4: Пожалуйста прочитайте страницу, посвящённую настройкам приоритета в устройствах с архитектурой ARM Cortex-M. Как минимум, запомните, что ARM Cortex-M используетс маленькие значения приоритета для представления ВЫСОКОГО уровня приоритета прерываний, что может быть легко упущено из виду, т.к. кажется нелогичным. Если вы хотите назначить прерыванию низкий приоритет, НЕ назначайте приоритет 0 (или другие маленькие числовые значения), так как это может привести к тому, что будет иметь самый высокий приоритет в системе и, следовательно, потенциально может привести к краху системы, если этот приоритет окажется выше configMAX_SYSCALL_INTERRUPT_PRIORITY.

Самый низкий приоритет для ядра ARM Cortex-M соответствует значению 255. Но разные производители ARM Cortex-M реализуют в своих микропроцессорах различное количество битов в контроллере прерываний и предоставляют библиотечные функции для работы с приоритетами в самых разных вариантах. Например для STM32 при вызове библиотечных функций самый низкий приоритет вы можете задать, указав значение 15, а самый высокий - указав 0.

 configASSERT

Назначение макроса configASSERT() такое же, как и у стандартного макроса Си assert(). Утверждение срабатывает, если параметр, переданный в configASSERT() равен нулю.

configASSERT() вызывается во всех исходных файлах FreeRTOS для проверки того, как приложение использует FreeRTOS. Настоятельно рекомендуется при разработке приложений под FreeRTOS определять макрос configASSERT().

Пример определения (показан в начале страницы и продублирован ниже) вызывает функцию vAssertCalled(), передавая имя файла и и номер строки точки вызова configASSERT() (стандартные макросы __FILE__ и __LINE__ предоставляются большинством компиляторов). Это просто демонстрация того, что vAssertCalled() не является функцией самой FreeRTOS, а макрос configASSERT() может быть определён для выполнения любых действий, которые разработчик приложения считает нужным.

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

Заметьте, что определение configASSERT() будет увеличивать и объём кода, и время выполнения. Поэтому когда приложение будет доведено до стабильной работы, от этих издержек можно избавиться просто закомментировав определение configASSERT() в FreeRTOSConfig.h.

/* Определите макрос configASSERT() для вызова vAssertCalled(), если утверждение
(assertion) ошибочно. Утверждение ошибочно, если значение параметра,
передаваемого в configASSERT() равно нулю (т.е. эквивалентно bool false). */
#define configASSERT( ( x ) )     if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ )

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

/* Макрос configASSERT(), запрещающий прерывание и входящий в вечный цикл. */
#define configASSERT( ( x ) )     if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }
 configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS

Параметр configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS используется только FreeRTOS MPU. (в файле mpu_wrappers.c, для включения файла application_defined_privileged_functions.h).

Если параметр configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS установлен в 1, то разработчик приложения должен предоставить заголовочный файл application_defined_privileged_functions.h, в котором могут быть реализованы фнукции, которые должны выполняться в привилегированном режиме. Обратите внимание на то, что, несмотря на расширение .h файла, он должен содержать в себе  реализацию функций C, а не только их прототипы.

Функции, реализованные в application_defined_privileged_functions.h должны сохранять и восстанавливать уровень привилегий процессора, используя функцию prvRaisePrivilege() и макрос portRESET_PRIVILEGE() соответственно. Например, если библиотечная функция print обращается к ОЗУ за пределами области, контролируемой разработчиком приложения, и следовательно (ОЗУ) не может быть выделено для задачи в режиме пользователя с защитой памяти (выделена защищённой задаче непривилегированного режима памяти), то тогда функция print может быть инкапсулирована в привилегированную функцию используя следующий код: (оставляю оригинал, т.к. смысл пока что не полностью уяснил)

Functions implemented in "application_defined_privileged_functions.h" must save and restore the processor's privilege state using the prvRaisePrivilege() function and portRESET_PRIVILEGE() macro respectively. For example, if a library provided print function accesses RAM that is outside of the control of the application writer, and therefore cannot be allocated to a memory protected user mode task, then the print function can be encapsulated in a privileged function using the following code:

void MPU_debug_printf( const char *pcMessage )
{
/* Состояние уровня привилегий процессора в момент вызова функции. */
BaseType_t xRunningPrivileged = prvRaisePrivilege();

    /* Вызываем функцию библиотеки, которая теперь имеет доступ
    ко всему ОЗУ. */
    debug_printf( pcMessage );

    /* Сбрасываем уровень привилегий процессора к состоянию на момент
    вызова этой функции. */
    portRESET_PRIVILEGE( xRunningPrivileged );
}

Эту технику допустимо использовать только во время разработки, но не развёртывания, т.к. она обходит защиту памяти.


Параметры INCLUDE

Макроопределения, начинающиеся с 'INCLUDE' позволяют исключить из сборки те компоненты ядра ОС, которые не используются вашим приложением. Это гарантирует, что ОС не использует ОЗУ и ПЗУ больше, чем необходимо для вашего конкретного встраиваемого приложения.

Каждое макроопределение принимает форму...

INCLUDE_FunctionName

... где FunctionName указывает функцию API (или набор функций), которую при желании можно исключить. Чтобы включить функцию API, установите значение в 1, чтобы исключить функцию установите макрос в 0. Например, чтобы использовать функцию API vTaskDelete(), используйте макроопределение:

#define INCLUDE_vTaskDelete 1

Для исключения из сборки vTaskDelete() используйте макроопределение:

#define INCLUDE_vTaskDelete 0

 

Hobby's category: