Перевод может содержать ошибки. Читайте первоисточник.
Назад: [Advanced] | Вверх: [Advanced] | Вперёд: [Advanced] |
Настройки FreeRTOS находятся в файле FreeRTOSConfig.h. В каждом приложении, использующем FreeRTOS, препроцессору должен быть указан путь, где лежит этот заголовочный файл. Файл FreeRTOSConfig.h адаптирует ядро RTOS к создаваемому приложению. Поэтому он относится именно к приложению, а не к самой FreeRTOS, и должен располагаться в каталоге приложения, а не в каталоге с исходными файлами FreeRTOS.
Каждый демонстрационный проект, включённый в поставку FreeRTOS, содержит свой собственный файл FreeRTOSConfig.h. Некоторые демо-проекты довольно старые и могут содержать не все доступные в последней версии RTOS конфигурационные параметры. Отсутствующие параметры устанавливаются в значения по-умолчанию в исходных файлах RTOS.
Настройки FreeRTOS в этом файле в некоторых местах документации называются "константами времени компиляции". - прим. переводчика.
Приведём типичное определение параметров в файле FreeRTOSConfig.h и подробно остановимся на описании каждого из них:
/*----------------------------------------------------------------------------*/ |
Устанавливается в 1 для использования вытесняющего планировщика RTOS, либо в 0 для использования кооперативной многозадачности.
Некоторые варианты портирования имеют два метода для выбора следующей запускаемой задачи - основной метод и платформозависимый метод.
Основной метод:
Платформозависимый метод:
Установливается configUSE_TICKLESS_IDLE в 1 для использования режима "энергосберегающего простоя без тиков, или в 0 для выработки прерываний от системного таймера во всех состояниях. Режим "энергосберегающий простой без тиков" доступен не для всех платформ.
Установите значение 1, если хотите использовать ловушку простоя (idle hook), или значение 0, чтобы не использовать её.
Ядро использует вызов 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_TIMERS и configUSE_DAEMON_TASK_STARTUP_HOOK оба установлены в 1, тогдаприложение может определить функцию-ловушку по шаблону, который приведён ниже. Функция-ловушка будет вызываться ровно один раз, когда задача демона RTOS (так же известная как задача обслуживания таймера) запускается первый раз. В эту функцию-ловушку может быть помещён любой код инициализации приложения, для которого требуется запуск RTOS.
void vApplicationDaemonTaskStartupHook( void );
Устанавливается в 1, если вы хотите использовать ловушку тиков ОСРВ, или в 0, если она не нужна.
Укажите частоту (в Герцах), с которой будет осуществляться внутреннее тактирование, которое управляет периферией, используемой для выработки прерываний тиков - обычно это тот же сигнал, который является тактовым для ядра процессора. Это значение необходимо для корректной настройки периферии таймера.
Проще говоря: укажите частоту тактирования таймера, который используется для выработки прерываний тиков ОСРВ, чтобы была возможность настроить его таким образом, чтобы он отсчитывал нужный период тиков ОСРВ.
Частота повторения прерываний тиков 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_CO_ROUTINE_PRIORITIES.
Каждый доступный приоритет использует ОЗУ внутри ядра ОСРВ, так что не стоит увеличивать количество приоритетов больше, чем реально необходимо для приложения.
Размер стека, используемый задачей ожидания. Как правило это значение не должно быть меньше, чем установленное в файле FreeRTOSConfig.h, предоставляемом в составе демонстрационного приложения для порта, который вы используете.
Как и в параметре размера стека для функций xTaskCreate() и xTaskCreateStatic(), в параметре configMINIMAL_STACK_SIZE размер стека указывается не в байтах, а в словах. Если размер элемента, помещаемого в стек, равен 32 битам, то указание размера стека равным 100 будет означать выделение под него 400 байт (каждый 32-битный элемент стека занимает 4 байта).
Максимально допустимая длина описательного имени, присваиваемого задаче при её создании. Длина указывается в количестве символов, включая завершающий байт NULL (0x00).
Устанавливаем в 1, если хотим использовать дополнительные поля структуры и вспомогательные функции для визуализации и отслеживания выполнения.
Установите в 1 configUSE_TRACE_FACILITY и configUSE_STATS_FORMATTING_FUNCTIONS для включения в сборку функций vTaskList() и vTaskGetRunTimeStats(). Если значение установить в 0, эти функции не будут включены в сборку.
Время измеряется в "тиках" - это количество раз, сколько вызывалось прерывание тиков ОС с момента старта ядра. Количество тиков хранится в переменной, имеющей тип TickType_t.
От значения настройки configUSE_16_BIT_TICKS зависит размер этой переменной. Если 1 - TickType_t определён (typedef) как 16-битное беззнаковое значение. Если 0 - как 32-битное беззнаковое.
Использовние 16-битного типа счётчика существенно улучшит производительноть на 8- и 16-битных архитектурах, но ограничит максимально значение величиной 65535 тиков. Поэтому например при частоте тиков 250 максимальное время, на которое задача может задержаться (delay), либо быть заблокирована, составит 262 секунды. Для сравнения: в случае 32-битного счётчика это время будет 17179869 секунд.
Этот параметр управляет поведением задач, имеющих приоритет простоя. Он имеет значение если:
Задачи, которые имеют одинаковый приоритет, переключаются с использованием алгоритма циклического перебора с выделением времени. Каждая задача будет в порядке выбираться для перевода в запущенное состояние, но может оставаться запущенной не весь квант времени ОС. Например, задача может быть вытеснена процессом с бОльшим приоритетом, может уступить процессорное время, может перейти в заблокированное состояние раньше следующего прерывания тика ОС.
Если значение параметра configUSE_TIME_SLICING установлено в 1 (или не определено), то задачи, имеющие одинаковый приоритет, будут иметь одинаковый временной интервал для использования процессорного времени. Если при этом ни одна задача не была вытеснена, то можно предположить, что каждой задаче с данным приоритетом будет выделено одинаковое количество процессорного времени - и если приоритет выше чем приоритет простоя, то это действительно так.
Если же задачи имеют приоритет простоя, поведение может немного отличаться. Если configIDLE_SHOULD_YIELD установлен в 1, то задача простоя будет немедленно завершена, если любая другая задача с приоритетом простоя будет готова к запуску. Это гарантирует, что на задачу простоя будет затрачено минимальное количество процессорного времени, если есть задачи, готовые к запуску. Однако такое поведение может иметь некоторые нежелательные эффекты (в зависимости от потребностей вашего приложения), как показано ниже:
Рисунок выше иллюстритует схему выполнения четырёх задач, которые запущены с приоритетом простоя. Задача A, B и C - это задачи приложения. Задача I - это задача простоя (idle task). Переключение контекста выполняется с постоянным периодом в моменты времени T0, T1, ..., T6. И когда задача простоя уступает процессорное время, запускается задача A - но задача простоя уже использовала часть текущего кванта времени ОС. В результате задачи I и A делят один и тот же квант. Следовательно задачи B и C получают больше процессорного времени, чем задача A.
Чтобы избежать этого:
Установка configIDLE_SHOULD_YIELD в 0 предотвращает уступание процессорного времени задачей простоя до завершения кванта времени ОС. времени активизацию задачи простоя пока не закончится очередной интервал. Это гарантирует, что всем задачам с приоритетом простоя будет выделяться одинаковое количество процессорного времени (если задачи не будут вытесняться процессами с бОльшим приоритетом). Обратная сторона медали - для задачи простоя выделяется большая доля общего времени обработки.
Если значение параметра configUSE_TASK_NOTIFICATIONS установлено в 1 (или не определено), в сборку будет включён функционал уведомлений и функции API для работы с уведомлениями.
Если значение параметра configUSE_TASK_NOTIFICATIONS установлено в 0, функционал уведомлений и функции API для работы с ними не будут включены в сборку.
Каждая задача использует 8 дополнительных байт ОЗУ, если уведомления включены в сборку.
Установка этого параметра в 1 включает функционал мьютексов в сборку. Если установить в 0, мьютексы не будут добавлены к сборке. Будьте внимательны: как следует изучите различия между мьютексами и бинарными семафорами, и как они используются во FreeRTOS.
Установка этого параметра в 1 добавляет в сборку функционал рекурсивных мьютексов, и наоборот, установка в 0 убирает рекурсивные мьютексы из сборки.
Установка этого параметра в 1 добавляет в сборку функционал счётных семафоров. И наоборот, установка в 0 убирает счётные семафоры из сборки.
Установка в 1 включает в сборку 'альтернативные' функции работы с очередями, и наоборот, установка в 0 исключает из сборки эти функции. Функции альтернативного API описаны в заголовочном файле queue.h. Эти функции устарели, и не должны использоваться в новых проектах.
Подробное описание использования этого параметра приведено на странице "проверка переполнения стека".
Реестр очереди имеет два предназначения, оба из которых связаны с отладкой с поддержкой ядра ОС: The queue registry has two purposes, both of which are associated with RTOS kernel aware debugging:
Реестр очереди не имеет смысла, пока вы не используете отладчик с поддержкой ядра 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 в целом.
Установка этого параметра в 1 добавляет в сборку функционал набора очередей (queue set) (возможность блокировки, или ожидания, на нескольких очередях и семафорах), установка в 0 исключает из сборки этот функционал.
По-умолчанию (если configUSE_TIME_SLICING не определён, или configUSE_TIME_SLICING установлен в 1) FreeRTOS использует приоритетный вытесняющий планировщик с квантами времени. Это означает, что планировщик всегда будет запускать задачу с наивысшим приоритетом из числа находящихся в состоянии готовности, и будет переключаться между задачами с одинаковым приоритетом при каждом прерывании тика ОС. Если же configUSE_TIME_SLICING установлен в 0, то планировщик всё равно будет запускать задачу с наивысшим приоритетом, которая находится в состоянии готовности, но не будет переключать между задачами с одинаковым приоритетом просто потому, что произошло прерывание по тику ОС.
Если параметр configUSE_NEWLIB_REENTRANT установлен в 1, то при использовании библиотеки newlib для каждой задачи будет выделена своя структура для обеспечения реентерабельности.
Если configUSE_NEWLIB_REENTRANT установлен в 1, то для каждого созданного задания будет выделена структура повторного запуска newlib.
Примечание: поддержка newlib включена по многочисленным просьбам, но при этом не используется самими разрабочиками FreeRTOS. И FreeRTOS не несёт ответственности за результат работы newlib. Пользователь должен хорошо знаком с этой библиотекой и самостоятельно предоставлять общесистемные реализации необходимых заглушек. Имейте в виду, что на момент написания текущая версия newlib реализует общесистемный вызов malloc(), который должен быть снабжён блокировками.
Заголовочный файл FreeRTOS.h содержит набор макросов #define, которые сопоставляют имена типов данных, используемых в версиях FreeRTOS до версии 8.0.0, с именами, используемыми в версиях FreeRTOS начиная с 8.0.0. Эти макросы позволяют обновлять FreeRTOS до версии начиная с 8.0.0 без внесения изменений в код приложения. Установка configENABLE_BACKWARD_COMPATIBILITY в 0 в файле FreeRTOSConfig.h исключает эти макросы из сборки, и при этом разрешает проверку на неиспользование имён типов данных, использовавшихся до версии 8.0.0.
Устанавливает количество индексов в массиве локального хранилища каждой задачи.
Не осознал. Пока оставляю оригинал. Sets the number of indexes in each task's thread local storage array.
Если параметр 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_DYNAMIC_ALLOCATION установлен в 1, объекты ОС могут создаваться используя ОЗУ, которое автоматически выделяется из кучи FreeRTOS.
Если параметр configSUPPORT_DYNAMIC_ALLOCATION установлен в 0, объекты ОС могут быть расположены только в ОЗУ, предоставляемом разрабочиком приложения.
Если параметр configSUPPORT_DYNAMIC_ALLOCATION не определён, его значение устанавливается по умолчанию в 1.
Дополнительную информацию можно найти на странице "Статическое или динамическое выделение памяти".
Общий объём ОЗУ, доступный в куче FreeRTOS.
Это значение будет только использовано если параметр configSUPPORT_DYNAMIC_ALLOCATION установлен в 1, и приложение использует один из примеров схем распределения памяти, предоставляемых в составе исходных кодов FreeRTOS. Детальная информация предоставлена в разделе "конфигурация памяти".
По-умолчанию куча 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 ];
Этот параметр описан на странице "Run Time Statistics".
Установка в 1 добавляет в сборку функционал сопрограмм, установка в 0 убирает его из сборки. Для добавления сопрограмм файл croutine.c должен быть включён в проект.
Количество приоритетов, доступных созадачам приложения. Любое количество созадач может использовать один и тот же приоритет. При этом задачи отдельно распределяются по приоритетам - см. параметр configMAX_PRIORITIES.
Установка в 1 добавляет в сборку функционал программных таймеров, установка в 0 убирает его из сборки. Полная информация находится на странице "Программные таймеры во FreeRTOS".
Устанавливает приоритет демона/сервисной задачи таймеров. Полная информация находится на странице "Программные таймеры во FreeRTOS".
Устанавливает длину очереди команд программных таймеров. Полная информация находится на странице "Программные таймеры во FreeRTOS".
Устанавливает глубину стека, выделенного для службы/демона задачи программных таймеров. Полная информация находится на странице "Программные таймеры во FreeRTOS".
Порты ОС для 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, как указано:
Пример конфигурации приоритетов прерываний.
Эти конфигурационные параметры позволяют реализовать очень гибкую схему обработки прерываний:
Чтобы использовать эту схему в приложении необходимо придерживаться следующего правила: любые прерывания, использующие вызовы функций 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() такое же, как и у стандартного макроса Си 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 используется только 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_FunctionName
... где FunctionName указывает функцию API (или набор функций), которую при желании можно исключить. Чтобы включить функцию API, установите значение в 1, чтобы исключить функцию установите макрос в 0. Например, чтобы использовать функцию API vTaskDelete(), используйте макроопределение:
#define INCLUDE_vTaskDelete 1
Для исключения из сборки vTaskDelete() используйте макроопределение:
#define INCLUDE_vTaskDelete 0