Содержание

Порт TNKernel для PIC24/dsPIC и PIC32

Скачать

Актуальная версия



Предыдущие версии

Настоятельно рекомендую обновиться




























Thread-Metric Test Suite


Документация


Почему TNKernel?

TNKernel (http://www.tnkernel.com) - вытесняющая RTOS, изначально разработанная для микроконтроллеров с ядром ARM7, имеющая ряд достоинств по сравнению с аналогичными некоммерческими и коммерческими продуктами. TNKernel распространяется по FreeBSD-like лицензии и написана в основном на языке Си, что сделало возможным ее портирование как на 16-битную архитектуру Microchip PIC24/dsPIC (для компилятора Microchip C30) так и на 32-битные PIC32 (архитектура MIPS32 M4K, компилятор Microchip C32)

При выборе RTOS для применения в проектах с PIC24/dsPIC рассматривались различные варианты: uC/OS-II, как наиболее распространенная коммерческая RTOS для однокристалльных контроллеров, freeRTOS - широко известная и бесплатная RTOS. Рассматривались варианты портирования ThreadX (оригинального порта тогда еще не было) и других платных и бесплатных "легких" планировщиков. Операционные системы с кооперативным планировщиком (Salvo, jacOS) были откинуты сразу, так как даже первые линейки PIC24/dsPIC имели достаточный объем оперативной памяти для реализации вытеснения.

Основные критерии выбора были следующие:

TNKernel изначально удовлетворяла всем критериям, поэтому и была выбрана за основу, несмотря на то что оригинальная версия разработана для контроллеров с ядром ARM7.

Наличие исходных текстов

Существует большое количество коммерческих и бесплатных "легких" RTOS для однокристальных контроллеров, исходные коды которых либо выложены в свободном доступе (freeRTOS), либо доступны только для ознакомительных целей (uC/OS-II), либо можно найти в файлообменных сетях (ThreadX).

TNKernel распространяется по лицензии, допускающей модификацию исходников и коммерческое использование при сохранении копирайта. Это стало одним из решающих аргументов.

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

Простое портирование, понятный код

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

Под "простым" портированием я понимаю четкое разделение собственно ядра системы (которое должно быть написано на С/С++) и модулей, зависящих от архитектуры (переключение контекста, работа с прерываниями и т.п.). Большинство известных RTOS для однокристальных контроллеров имеют как большое количество портов, так и сформировавшуюся структуру, которая позволяет быстро порты добавлять.

На момент выбора системы порты для 16-битных контроллеров Microchip имели только freeRTOS и uC/OS-II. Однако, порт для uC/OS-II не работал (ошибка в ассемблерном модуле - первый релиз, спишем на это), а в порте freeRTOS был найден комментарий типа "в этом месте может зависнуть, почему - пока не понятно…". Все это ставило под сомнение использование этих систем (тем более, что uC/OS-II еще и коммерческая). Сейчас ситуация изменилась - выходят обновления портов, обновления самих систем. Поэтому выбор может быть не столь очевидным, и, возможно, даже не в пользу TNKernel (если вы, например, уже используете freeRTOS).

Понятный код - еще один момент на котором стоит остановиться. Несомненно, что каждый программист или коллектив имеет сложившийся стиль, поэтому трудно оценивать чужой код - понятный он или нет. Мне наиболее ближе TNKernel - по такому критерию это несомненный лидер.

Наличие дополнительных библиотек

В этом случае явным лидером является uC/OS-II, так как имеет огромное количество дополнительного софта (за дополнительные же деньги): файловую систему, стек tcp/ip, библиотеку обслуживания USB, GUI и т.д. freeRTOS может включать в себя порт открытого tcp/ip стека uIP и большое количество примеров, построенных на его основе.

Оригинальная версия TNKernel имеет библиотеку USB Bulk Firmware для контроллеров NXP LPC2100 и урезанный порт Nano-X GUI. Если первое не может использоваться совместно с 16-битными контроллерами Microchip в силу понятных причин, то второе вполне можно успешно применять в проектах на PIC24/dsPIC и PIC32. Недавно автором TNKernel был выпущен TCP/IP стек, который, возможно будет работать и на PIC32.

Используемые ресурсы

По этому критерию TNKernel вне конкуренции - uC/OS-II и freeRTOS требовали почти в два раза больше программной памяти и в полтора раза больше ОЗУ (не считая стеков задач). Возможно сейчас ситуация изменилась, но в начале это произвело впечатление.

Следует заметить, что и uC/OS-II и freeRTOS требуют компиляции в составе проекта, а линкер Microchip C30 пока не умеет игнорировать неиспользуемые секции кода, подключая на выход целиком весь объектный файл, даже если из него используется одна функция, лежащая в отдельной секции. Поэтому в проект с использованием freeRTOS и uC/OS-II будет включаться весь исполняемый код RTOS.

Конечно это не является недостатком вышеназванных RTOS - это проблема компилятора Microchip C30. Частично она решается заголовочными файлами конфигурации, в которых указано, какие сервисы и объекты будут использоваться. Тем не менее даже полный вариант TNKernel использует меньше программной памяти чем freeRTOS или uC/OS-II.

Компилятор Microchip C32 основан на новой версии GCC и умеет игнорировать неиспользуемые функции в объектном файле, однако для совместимости с портом для PIC24/dsPIC структура системы оставлена прежней.

Время реакции

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

Оценить время реакции и другие "скоростные" параметры RTOS, можно используя набор тестов известного производителя Express Logic Corp. (автора ThreadX), который называется Thread-Metric Test Suite. Результаты тестов для наиболее известных RTOS для PIC24/dsPIC приведены в таблице.

Cooperative Scheduling Preemptive Scheduling Interrupt Processing Interrupt Preemption Message Processing Sync Processing Memory Processing
TNKernel (1) 4,139,983 7,784,007 3,179,511 5,721,174 13,621,698 9,746,870
AVIX 9,069,625 5,100,589 7,400,858 3,293,937 5,020,698 19,030,131 10,609,717
ThreadX 11,848,815 5,032,710 7,342,967 3,132,150 7,354,317 17,592,956 14,413,455
uc/OS-II (1) 3,909,085 5,259,998 (1) 7,387,612 10,293,318 6,814,817
FreeRTOS (2) 3,717,913 1,881,892 2,400,967 0,484,691 1,989,999 (1)
AVA (1) 1,724,948 5,207,762 1,260,190 2,761,154 7,514,799 10,235,182

(1) Функция или объект не поддерживается
(2) Ошибка выполнения теста

Проект с тестовым приложением для TNKernel можно скачать по ссылке.

В таблице присутствуют RTOS, которые раньше не упоминались, поэтому дадим краткую характеристику каждой из них:

Тестирование TNKernel и AVIX можно повторить самостоятельно, скачав проекты. Остальные результаты взяты с форума microchip.com. Результаты тестов так же опубликованы на сайте AVIX, однако они устаревшие и неполные.

Если за первое место в тесте начислять 3 балла, за второе - 2 балла и за третье - 1 балл, то AVIX займет лидирующую позицию, ThreadX - второе место, а TNKernel - третье.

Самая популярная freeware RTOS для однокристальных микроконтроллеров - freeRTOS оказалась по совокупности результатов на одном из последних мест. По просьбе автора, freeRTOS удалена из таблицы сравнения на странице AVIX - по его утверждению результаты тестов сильно отличаются от реальности. Однако, до сих пор результаты автор freeRTOS не привел, поэтому в этом документе опубликовано то, что было получено в изначальной дискуссии. Вполне возможно, что на самом деле freeRTOS ведет себя гораздо лучше…

Таким образом, можно сказать, что TNKernel является лучшим из вытесняющих планировщиков, распространяемых с открытыми исходными кодами и допускающих использование в коммерческих разработках.

Отличия TNKernel для PIC24/dsPIC и PIC32

Исходные коды

Структура исходных текстов TNKernel значительно изменена по сравнению с оригинальной. Основное отличие - каждая функция находится в отдельном файле. Таким образом обходится проблема линкера C30, который не может игнорировать неиспользуемые секции кода.

При сборке проекта в исполняемый файл линкер добавляет только те функции, которые используются в пользовательском приложении. Это позволяет значительно сократить объем программной памяти, используемый ядром. Например, все сервисы требуют порядка 15 кБ программной памяти, тогда как в среднем приложении ядро RTOS занимает примерно 6-7 кБ.

Кроме разделения исходных кодов на файлы была предпринята попытка сделать TNKernel еще более портируемой - все основные типы переопределяются, все машинозависимые функции вынесены в отдельные модули (префикс port_). Это позволило в свое время достаточно просто добавить порт для PIC32.

Итак, скачав архив с проектом вы увидите католог source в котором и находятся исходные тексты TNKernel для PIC24/dsPIC. Файл _build_mchp_c30.bat предназначен для сборки библиотеки. Его можно отредактировать для сборки файла с требуемыми параметрами - другим уровнем оптимизации, моделью памяти и пр. Текущая версия командного файла собирает четыре библиотеки - две для PIC24 с оптимизацией Os и форматом coff и elf и две для dsPIC. То же самое и для PIC32, командный файл называется _build_mchp_c32.bat

Для сборки необходимо, чтобы в системе был прописан путь к исполняемому файлу компилятора.

Порт для PIC24/dsPIC

Компания Microchip имеет две основные линейки 16-битных контроллеров: PIC24 - микроконтроллеры общего назначения и dsPIC - контроллеры цифровой обработки сигналов. По сути PIC24 являются усеченной версией dsPIC - в них отсутствует DSP ядро и специальные методы адресации.

Изначально TNKernel портировалась как под PIC24, так и под dsPIC, причем в версии для последнего в стеке задачи кроме всего прочего, сохранялся контекст DSP-ядра. Но как выяснилось это не имело большого смысла, потому, что полностью восстановить контекст DSP простыми способами невозможно - большинство статусных флагов DSP-ядра имеют доступ только для чтения, да и с аппаратным циклом DO все не так просто. Поэтому от отдельного порта для dsPIC было решено отказаться - в следующих вариантах TNKernel для PIC24/dsPIC DSP-ядро было предложено рассматривать как разделяемые ресурс и использовать для доступа к нему из разных задач мютекс.

Но как выяснилось напрасно. Благодаря камраду qas был найден серьезный баг, который мог однозначно порушить систему при использовании модульной или бит-реверсивной адресации DSP-ядра. Баг исправлен, но опять появилось две версии TNKernel - для PIC24 и для dsPIC.

Тем не менее ситуация с DSP-ядром прежняя - его контекст не сохраняется и его следует рассматривать как разделяемый ресурс, используя для доступа из разных задач мютекс.

Порт для PIC32

Порт для PIC32 был реализован весной 2010 года по просьбам трудящихся. По сути он мало чем отличается от порта для PIC24/dsPIC. Начиная с версии 2.5.600 в комплекте идет пример, который может быть скомпилирован как под PIC24 так и под PIC32 без изменений.

Основные отличия от оригинальной версии

1. Типы данных

Все стандартные типы данных (кроме void) переопределены:

TN_CHAR
для всех архитектур соответствует signed char. Под char в данном случае подразумевается 1 байт.
TN_UCHAR
для всех архитектур соответствует unsigned char
TN_WORD
для PIC24/dsPIC (компилятор C30) соответствует signed int, то есть 16-битному целому со знаком
для ARM (Keil RV) и PIC32 (C32) соответствует signed int, то есть 32-битному целому со знаком
TN_UWORD
размер машинного слова. Этот тип рекомендуется использовать для объявления стеков задач
для PIC24/dsPIC (компилятор C30) соответствует unsigned int, то есть беззнаковому 16-битному целому
для ARM (Keil RV) и PIC32 (C32) соответствует unsigned int, то есть беззнаковому 32-битному целому
TN_SYS_TIM_T
тип счетчика системного времени. Для PIC24/dsPIC это 32-битный счетчик, для ARM/PIC32 - 64-битный
TN_TIMEOUT
тип таймаута
для PIC24/dsPIC (компилятор C30) соответствует unsigned int, то есть беззнаковому 16-битному целому
для ARM (Keil RV) и PIC32 (C32) соответствует unsigned int, то есть беззнаковому 32-битному целому

Рекомендуется употреблять эти типы для объявления переменных и массивов, связанных непосредственно с системой - стеков задач, блоков памяти фиксированного размера, очередей сообщений и др.:

TN_UWORD task_1_stack[128] TN_DATA;

2. Приоритеты задач

В оригинальной версии TNKernel задачи могут иметь приоритет от 1 до 30 (0 и 31 приоритет имеют системные задачи). В версии TNKernel для PIC24/dsPIC пользовательские задачи могут иметь приоритет от 1 до 14 (0 и 15 приоритет имеют системные задачи). Это связано с разрядностью слова контроллера и стремлением сократить время поиска следующей задачи, т.е. по сути время переключения контекста.

Следует сказать, что такого количества приоритетов вполне достаточно, так как опционально TNKernel обеспечивает карусельное (round-robin) переключение между задачами с одинаковым приоритетом.

В версии TNKernel для PIC32 задачи могут иметь такие же приоритеты как и в оригинальной: 1 до 30.

3. Инициализация системы

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

Вызов:

void tn_start_system (TN_UWORD *timer_task_stack,
                      TN_UWORD  timer_task_stack_size,
                      TN_UWORD *idle_task_stack,
                      TN_UWORD  idle_task_stack_size,
                      void      (*app_in_cb)(void),
                      void      (*cpu_int_en)(void),
                      void      (*idle_user_cb)(void)
                     );

Разрешен вызов:

В контексте задачи

Параметры функции:

timer_task_stack
указатель на стек системной задачи таймера
timer_task_stack_size
размер стека системной задачи таймера (в машинных словах)
idle_task_stack
указатель на стек системной задачи простоя
idle_task_stack_size
размер стека системной задачи простоя (в машинных словах)
app_in_cb
указатель на функцию инициализации приложения. Эта функция вызывается после того как системные задачи будут созданы, а планировщик запущен
cpu_int_en
указатель на функцию конфигурации прерываний. Эта функция вызывается сразу после функции app_in_cb
idle_user_cb
указатель на функцию, циклически вызываемую из задачи простоя. В этой функции можно, например, инкрементировать счетчик загрузки или уводить контроллер в состояние пониженного энергопотребления (Sleep или Idle)

Возвращаемые значения:

нет

Пример вызова:

#define TMR_TASK_STACK_SIZE    128
#define IDL_TASK_STACK_SIZE    128
 
TN_UWORD stk_tmr[TMR_TASK_STACK_SIZE] TN_DATA;  /* стек задачи таймера */
TN_UWORD stk_idl[IDL_TASK_STACK_SIZE] TN_DATA;  /* стек задачи простоя */
 
void appl_init(void);
void intr_init(void);
void idle_user(void);
 
int main (void)
{
    tn_start_system(stk_tmr,
                    TMR_TASK_STACK_SIZE,
                    stk_idl,
                    IDL_TASK_STACK_SIZE,
                    appl_init,
                    intr_init,
                    idle_user
                   );
}
 
void appl_init (void)
{
    /* инициализация */
}
 
void intr_init (void)
{
    /* инициализация и разрешение прерываний */
}
 
void idle_user (void)
{
    /* когда нечего делать мы тут */
}

Функции app_in_cb и cpu_int_en заменяют tn_app_init() и tn_cpu_int_enable() в оригинальной версии TNKernel.

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

По сути в точке входа приложения - функции main() должен вызываться только сервис tn_start_system().

4. Создание задачи

Изменен вызов сервиса создания задачи tn_task_create():

TN_RETVAL tn_task_create (TN_TCB    *task,
                          void     (*task_func)(void *param),
                          TN_UWORD  priority,
                          TN_UWORD  *task_stack_start,
                          TN_UWORD  task_stack_size,
                          void      *param,
                          TN_UWORD  option
                         );

Параметр task_stack_start указывает на вершину (младший адрес) стека задачи, тогда как в оригинальной версии, task_stack_start указывает на старший адрес стека. Это связано с тем, что в PIC24/dsPIC стек растет от младшего адреса к старшему.

В версии TNKernel для PIC32 в функцию создания задачи так же должен передаваться адрес вершины стека, несмотря на то, что у MIPS32 стек растет от старшего адреса к младшему.

Нововведения

1. Критические секции

Добавлены функции tn_sys_enter_critical() и tn_sys_exit_critical(), которые аналогичны используемым в оригинальной версии tn_disable_interrupt() и tn_enable_interrupt(). Функции используются следующим образом:

/* ... */
 
tn_sys_enter_critical();
    /*
      критическая секция кода, в которой запрещено переключение контекста
    */
tn_sys_exit_critical();
 
/* ... */

Названия функций отражают их назначение - выделение части кода в критическую секцию в которой запрещено переключение контекста. tn_disable_interrupt() и tn_enable_interrupt() - не совсем корректное название для PIC24/dsPIC, которые имеют векторный приоритетный контроллер прерываний.

В версии TNKernel PIC32 функция tn_sys_enter_critical() запрещает все прерывания!

2. Новые сервисы

Добавлены следующие сервисы:

3. Атрибут задачи

Функции задач могут объявляться с атрибутом TN_TASK. Этот атрибут сообщает компилятору о том, что функция имеет бесконечный цикл и выхода из нее не будет. В большинстве случаев это позволяет уменьшить размер стека задачи. Пример:

void TN_TASK Task (void *par)
{
    for (;;)
    {
        tn_task_sleep(10);
    }
}

4. Атрибут данных

Объекты и стеки задач могут объявляться с атрибутом TN_DATA. По сути он размещает переменные в отдельной секции ОЗУ - это позволяет контролировать объем памяти, занимаемой объектами RTOS и стеками задач. Для этого в скрипт линкера необходимо добавить следующие строки (см., например, файл ..\example1\p24FJ128GA006.gld):

.tnk_data :
{
      *(tnk_data);
} > data

Пример использования атрибута:

TN_SEM   Sem_From_IRQ TN_DATA;
TN_DQUE  que_test     TN_DATA;

Все сервисы TNKernel размещаются в отдельную секцию кода. Это позволяет контролировать объем программной памяти, которую занимает ядро. Для этого в скрипт линкера необходимо добавить следующие строки (см., например, файл ..\example1\p24FJ128GA006.gld):

.tnk_code :
{
      *(tnk_code);
} >program

В версии TNKernel для PIC32 именованные секции кода пока не поддерживаются.

5. Отладка

Если в заголовочном файле tnkernel_conf.h не объявить TN_DEBUG, внутренняя структура всех объектов будет скрыта от пользователя, и структура объектов в окне Watch отладчика будет отображена в виде байтового массива.

Если TN_DEBUG будет объявлен, структуры объектов будут раскрыты. Это позволит отлаживать приложение контролируя значения полей структур.

6. Варианты сервисов без проверки параметров

В порте TNKernel для PIC24/dsPIC и PIC32 имеется два набора сервисов - с проверкой параметров и без проверки параметров. Естественно, последние будут занимать меньше программной памяти и будут быстрее выполняться.

Объявление TN_NO_ERROR_CHECKING в файле конфигурации системы tnkernel_conf.h позволяет использовать более компактные и быстрые варианты сервисов без проверки параметров.

7. Контроль переполнения стеков задач

Микроконтроллеры PIC24/dsPIC имеют аппаратный механизм контроля переполнения стека, который полностью задействован в TNKernel для PIC24/dsPIC. Для того чтобы контролировать переполнение, необходимо объявить в коде исключение (trap) по ошибке стека:

void __attribute__((interrupt, no_auto_psv)) _StackError (void)
{
    for (;;);   /* при переполнении стека задачи попадем сюда */
}

В версии TNKernel для PIC32 контроль переполнения стека не поддерживается

8. Код возврата TERR_EXS

Любой сервис, создающий объект (tn_task_create(), tn_sem_create(), tn_queue_create(), tn_event_create(), tn_fmem_create() и tn_mutex_create()), проверяет состояние объекта (уже создан или нет) и, либо продолжает работу, либо (если объект уже создан) возвращает код ошибки TERR_EXS.

Наличие проверки состояния объекта не зависит от типа вызываемого сервиса (с проверкой или без проверки параметров).

9. Получение ревизии TNKernel

Добавлен заголовочный файл tnkernel_rev.h, в котором присутствуют следующие определения:

Пример использования:

TN_UWORD  tn_revision = __TNKERNEL_REVISION;
char     *tn_data     = __TNKERNEL_REVISION_TIME_STRING;
char     *tn_build    = __TNKERNEL_BUILD_TIME_STRING;
 
#if (__TNKERNEL_VERSION == 2.5)
    #if (__TNKERNEL_REVISION == 977)
        /* ... */
    #endif
#else
    /*...*/
#endif
 
printf(tn_data);

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

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

11. Файл конфигурации

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

Добавление пути поиска заголовочных файлов

Использование прерываний

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

Будем называть прерывания в которых вызываются сервисы системными, а все остальные прерывания - пользовательскими.

В TNKernel для PIC24/dsPIC системные прерывания должны иметь приоритет, равный TN_INTERRUPT_LEVEL (приоритет 1). Вызов сервисов RTOS в обработчике прерывания с другим (более высоким) приоритетом (т.е. в ISR пользовательского прерывания) запрещен - это приведет к краху системы. В текущей версии TNKernel защита от вызова системных сервисов в пользовательском прерывании не реализована.

В TNKernel для PIC32 системные прерывания должны иметь одинаковый приоритет, но не обязательно равный TN_INTERRUPT_LEVEL. Однако для совместимости кода рекомендуется использовать приоритет 1, как и в версии TNKernel для PIC24/dsPIC.

В TNKernel для PIC24/dsPIC и PIC32 не реализована вложенность системных прерываний. С одной стороны это может привести к задержке обработки прерывания, с другой - экономит стек задачи, что на самом деле более важно, особенно для PIC32. Если задержка входа в прерывание недопустима, можно использовать пользовательское прерывание с приоритетом большим чем TN_INTERRUPT_LEVEL. Однако, не нужно забывать, что вызов сервисов RTOS в пользовательском прерывании запрещен, поэтому задачи должны взаимодействовать с пользовательским прерыванием с помощью глобальных переменных. Это некрасиво и по большому счету неправильно, но другого выхода нет…

Системные прерывания объявляются с помощью макроса tn_sys_interrupt, аргументом которого является зарезервированый псевдоним вектора прерывания:

/* PIC24/dsPIC */
tn_sys_interrupt (_INT0Interrupt)   /* системное прерывание, источник INT0 */
{
    IFS0bits.INT0IF = 0;
    tn_queue_isend_polling(&que_test, transceived_buff);
}
 
/* PIC32 */
tn_sys_interrupt(_CHANGE_NOTICE_VECTOR)
{
    INTClearFlag(INT_CN);
    /* обработка прерывания */
}

Пользовательские прерывания объявляются обычным для C30/C32 способом.

Одно из системных прерываний всегда должно быть зарезервировано для системного таймера. Как правило это прерывание от аппаратного таймера с периодом 1-10 мс:

/* PIC24/dsPIC */
tn_sys_interrupt (_T2Interrupt)     /* системное прерывание, источник TMR2 */
{
    IFS0bits.T2IF = 0;
    tn_tick_int_processing();
}
 
/* PIC32 */
tn_sys_interrupt(_CORE_TIMER_VECTOR)   /* системное прерывание, источник - системный таймер MIPS32 */
{
    Sys_Tmr_Int_Handler();
    tn_tick_int_processing();
}

Сервис tn_tick_int_processing() должен вызываться только из системного прерывания.

Внимание!!! Если в обработчике прерывания вызывается серсив tn_tick_int_processing(), то вызов других сервисов RTOS в этом прерывании запрещен!

Следует заметить что сервисы tn_sys_enter_critical() и tn_sys_exit_critical() запрещают системные прерывания, в то время как прерывания с приоритетом, большим TN_INTERRUPT_LEVEL остаются активными - только для PIC24/dsPIC. Для PIC32 эти сервисы запрещают ВСЕ прерывания.

Отличия порта для PIC32 от порта для PIC24/dsPIC

  1. tn_sys_enter_critical() запрещает все прерывания, а не только с приоритетом TN_INTERRUPT_LEVEL
  2. данные и код не размещаются в именованные секции
  3. системные прерывания могут иметь приоритет отличный от TN_INTERRUPT_LEVEL, однако приоритет должен быть одинаковым для всех системных прерываний
  4. приоритеты задач - от 1 до 30
  5. переполнение стека не контролируется!