Содержание

TNKernel : Системные сервисы

Введение

Системные сервисы не относятся напрямую к каким-либо объектом RTOS, они позволяют управлять системой в целом или получать текущие параметры системы. К системным сервисам относятся функция запуска tn_start_system(), функция управления карусельным планированием tn_sys_tslice_ticks(), функция обработчика системного таймера tn_tick_int_processing(), функции реализации критической секции tn_sys_enter_critical() и tn_sys_exit_critical(), функции обслуживания системного времени tn_sys_time_set() и tn_sys_time_get().

Запуск системы

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

В порте TNKernel для контроллеров PIC24/dsPIC в функцию передается несколько параметров, позволяющих более гибко настроить систему (выбрать размеры стеков системных задач и т.п.). В оригинальной версии функция запуска параметров не имеет.

Диаграма запуска TNKernel изображена на рисунке:

Сервис запуска tn_start_system() как правило вызывается из функции main().

Системные прерывания должны быть запрещены до момента вызова tn_start_system().

Функция tn_start_system() создает две системные задачи tn_idle_task() и tn_timer_task() и запускает задачу tn_timer_task(), которая при старте последовательно вызывает две callback-функции - appl_init_callback() и cpu_interrupt_enbl_callback(). Указатели на эти функции передаются в систему в вызове tn_start_system().

Функция appl_init_callback() служит для инициализации системного таймера, периферийных модулей, создания необходимых задач. В функции cpu_interrupt_enbl_callback() разрешается прерывание от системного таймера и после выхода из нее система начинает нормальное функционирование.

Системный таймер

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

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

Функция tn_tick_int_processing() должна вызываться только в обработчике прерывания.

Управление Round-Robin

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

В TNKernel включен сервис tn_sys_tslice_ticks(), позволяющий настраивать длительность кванта выполнения для каждого приоритета или отключать карусельное планирование.

Карусельное планирование отключено по умолчанию для всех приоритетов.

Запрещение переключения контекста

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

Один из способов защиты критической секции - это использование мютекса. Однако часто мютекс является избыточным объектом для реализации критической секции и в этом случае используют парные функции запрещения и разрешения переключения контекста.

В TNKernel для PIC24/dsPIC переключение контекста запрещает функция tn_sys_enter_critical() и разрешает функция tn_sys_exit_critical().

Вызов функций tn_sys_enter_critical() и tn_sys_exit_critical() может быть несимметричным и вложенным. Например, допустимо следующее:

void foo (void)
{
    tn_sys_enter_critical();
    /* ... */
}
 
void TN_TASK task_1 (void *param)
{
    for (;;)
    {
        /* ... */
 
        tn_sys_enter_critical();
        foo();
        tn_sys_exit_critical();
 
        /* ... */
    }
}

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

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

Системное время

Под системным временем подразумевается беззнаковая целая переменная, инкрементируемая каждый системный тик. Значение переменной может быть получено путем вызова функции tn_sys_time_get() и установлено с помощью вызова tn_sys_time_set().

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

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

void TN_TASK task_1 (void *param)
{
    for (;;)
    {
        foo();
        tn_task_sleep(FOO_PERIOD);
    }
}

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

Используя системное время проблему можно решить следующим образом:

void TN_TASK task_1 (void *param)
{
    TN_SYS_TIM_T t;
 
    for (;;)
    {
        t = tn_sys_time_get();
        foo();
        t = tn_sys_time_get() - t;
 
        if (t < FOO_PERIOD)
            tn_task_sleep(FOO_PERIOD - t);
        else
            tn_task_sleep(1);
    }
}

Системные сервисы

TNKernel имеет следующий набор системных сервисов:

Сервис Описание Свойства
Основные сервисы
  tn_start_system() Запуск системы до начала работы системы
  tn_tick_int_processing() Обслуживание системного таймера Разрешен вызов только в прерывании Может привести к переключению контекста
  tn_sys_tslice_ticks() Управление round-robin планированием Разрешен вызов только в контексте задачи
  tn_sys_context_get() Получение текущего контекста системы Разрешен вызов в контексте задачи и в прерывании
Запрещение переключения контекста
  tn_sys_enter_critical() Вход в критическую секцию Разрешен вызов только в контексте задачи
  tn_sys_exit_critical() Выход из критической секции Разрешен вызов только в контексте задачи
Системное время
  tn_sys_time_get() Получение системного времени Разрешен вызов в контексте задачи и в прерывании
  tn_sys_time_set() Установка системного времени Разрешен вызов в контексте задачи и в прерывании