====== Порт TNKernel для PIC24/dsPIC и PIC32 ======
===== Скачать =====
==== Актуальная версия ====
* **2.5.908** (16 февраля 2011) {{:tnkernel:tnkernel_2_5_908.rar|скачать}} @ 550 кБ
* Исправлена ошибка в порте Cortex-M3, которая приводила к некорректной работе программы при вызове сервисов ''tn_sys_time_get()'' и ''tn_sys_time_set()''. Спасибо Дмитрию Кривецкову.
\\
----
~~UP~~
==== Предыдущие версии ====
* **2.5.716** (17 сентября 2010) {{:tnkernel:tnkernel_2_5_716.rar|скачать}} @ 550 кБ
* **Добавлен порт для ARM Cortex-M3 (для компилятора Keil RealView)**
* Найдены и исправлены ошибка во внутренних функциях ''try_lock_mutex()'' и ''do_unlock_mutex()''. При использовании мютексов с протоколом увеличения приоритетов мог возникнуть exception (взятие значения по нулевому адресу). Спасибо [[http://www.microchip.su/showthread.php?t=9951|Vanizma]]
* Найдена и исправлена ошибка в порте для PIC32 (смена контекста не защищалась критической секцией). Спасибо Ивану Федотову.
* Все определения, зависящие от архитектуры, под которую производится сборка, перенесены в файлы ''port_defs.h'' каждой архитектуры.
* Переделана структура примера. В пример добавлена задача, использующая UART (работает на Explorer16 как для PIC24, так и для PIC32). Задача принимает 10 байт (с таймаутом 2 мс на скорости 19200 бит/с) и пересылает их обратно. Для разных архитектур используются разные файлы bsp.c
**Настоятельно рекомендую обновиться**
\\
----
* **2.5.601** (14 июля 2010) {{:tnkernel:tnkernel_2_5_601.rar|скачать}} @ 400 кБ
* **Добавлен порт TNKernel для PIC32**
* Рекомендую почитать [[tnkernel:mchp_c30_16bit_port#Отличия порта для PIC32 от порта для PIC24/dsPIC|список отличий]] и пройтись поиском по этой странице. Искать ''PIC32''
* Множество платформозависимых ассемблерных файлов сведено в один ''port.S''
* Переработан пример. Теперь его можно запускать в железе (Explorer 16 + PIC24FJ256GB110 или PIC32MX360F512L) и смотреть как моргают светодиоды, нажимать на кнопку, крутить потенциометр
* Конфигурация сборки (''TN_DEBUG'') определяется во внешнем файле ''tnkernel_conf.h'' - см. пункт [[tnkernel:mchp_c30_16bit_port#11. Файл конфигурации|"11. Файл конфигурации"]]
* Для всех функций //без// проверки параметров добавлена проверка, создан объект или нет. В противном случае можно нарваться на неприятные проблемы, типа отсылки сообщения через очередь, которая еще не создана. Это очень важный фикс, **рекомендую обновиться**.
\\
----
* **2.5.455** (07 апреля 2010) {{:tnkernel:tnkernel_mchp_c30_16bit_2_5_455.rar|скачать}} @ 530 кБ
* Исправлена ошибка в функции [[tnkernel:ref:task:tn_task_exit|tn_task_exit()]]. Неладное заметил и настойчиво просил разобраться [[http://www.microchip.su/showthread.php?t=8710|Daniil]], за что ему большое спасибо.
* Ошибка тянется еще издавна, когда были попытки использовать все приоритеты для реализации системных прерываний. Ошибка проявляла себя только в случае, если после вызова [[tnkernel:ref:task:tn_task_exit|tn_task_exit()]] возникало системное прерывание, которое переключало контекст. Так как сервис ''tn_task_exit()'' вообще не очень популярный, то баг был замечен только сейчас
----
\\
* **2.5.298** (15 января 2010) {{:tnkernel:tnkernel_mchp_c30_16bit_2_5_298.rar|скачать}} @ 530 кБ
* Исправлена ошибка в функциях [[tnkernel:ref:sys:tn_sys_time_get|tn_sys_time_get()]] и [[tnkernel:ref:sys:tn_sys_time_set|tn_sys_time_set()]]. Проблему нашел [[http://www.microchip.su/showpost.php?p=85901&postcount=114|vitalka]], локализовал [[http://www.microchip.su/showpost.php?p=88269&postcount=172|tester]] - гран мерси!
* Использование этих функций разрешено как в задачах, так и в системных прерываниях. Однако функции запрещали и сбрасывали флаг приоритета ядра, не проверяя, в каком контексте находятся. При использовании этих функций в системном прерывании, приоритет ядра сбрасывался на 0
----
\\
* **2.5.182** (15 ноября 2009) {{:tnkernel:tnkernel_mchp_c30_16bit_2_5_182.rar|скачать}} @ 530 кБ
* Исправлена ошибка в макросе ''MAKE_ALIG()'', который используется для выделения пула блоков памяти фиксированного размера. Спасибо **vitalka**!
----
\\
* **2.5.62** (24 июня 2009) {{:tnkernel:tnkernel_mchp_c30_16bit_2_5_62.rar|скачать}} @ 530 кБ
* Тип параметра, передаваемый в функции [[tnkernel:ref:task:tn_task_reference|tn_task_reference()]] и [[tnkernel:ref:task:tn_task_ireference|tn_task_ireference()]] изменен с ''TN_TCB_S'' на ''TN_TCB''
* компилятор выдавал предупреждение о несоответствии типов. Спасибо [[http://www.microchip.su/showpost.php?p=68376&postcount=3|Vanizma]]
----
\\
* **2.5.28** (23 апреля 2009) {{tnkernel:tnkernel_mchp_c30_16bit_2_5_28.rar|скачать}} @ 530 кБ
* Исправлена ошибка в механизме карусельного (round-robin) планирования ([[http://www.microchip.su/showthread.php?t=5760|обнаружил]] **VXDRV**, спасибо)
* Карусельное планирование позволяет выделять задачам с фиксированным приоритетом временные кванты, длительность которых задается с помощью функции [[tnkernel:ref:sys:tn_sys_tslice_ticks|tn_sys_tslice_ticks()]]. Ошибка в системной функции [[tnkernel:ref:sys:tn_tick_int_processing|tn_tick_int_processing()]] увеличивала этот интервал на один системный тик
----
\\
* **2.5.10** (8 декабря 2008) {{tnkernel:tnkernel_mchp_c30_16bit_2_5_10.rar|скачать}} @ 532 кБ
* Обновлено до [[http://www.tnkernel.com/news.html|официальной версии]] **2.5**
* Исправлена ошибка в задаче системного таймера ''tn_timer_task_func()''
* В предыдущих версиях была следующая ошибка - если в момент выполнения задачи таймера ''tn_timer_task_func()'' возникало системное прерывание, в котором разблокировалась одна из задач (устанавливался ожидаемый семафор, и т.п.), то при выходе их этого прерывания запускалась разблокированная задача. Таким образом, в определенных ситуациях, было возможно непроизвольное увеличение таймаутов ожидающих событие задач
* Исправлена ошибка в функции ''task_wait_complete()''
* Ошибка в обработке задач, использующих ceiling мютекс
* Добавлено определение ''%%__TNKERNEL_VERSION%%''
* В связи с переездом на новый SVN хостинг номера ревизий будут меньше чем у предыдущих версий. Введено определение ''%%__TNKERNEL_VERSION%%'', которое будет обозначать номер текущей версии (2.5)
----
\\
* **2.4.1037** (25 июня 2008) {{tnkernel:tnkernel_mchp_c30_16bit_2_4_1037.rar|скачать}} @ 530 кБ
* исправлена ошибка в порте для dsPIC (нашел **Vlad**, спасибо)
* код с библиотекой просто не собирался
----
\\
* **2.4.1034** (20 июня 2008) {{tnkernel:tnkernel_mchp_c30_16bit_2_4_1034.rar|скачать}} @ 494 кБ
* добавлены сервисы получения информации о задаче [[tnkernel:ref:task:tn_task_reference|tn_task_reference()]] и [[tnkernel:ref:task:tn_task_ireference|tn_task_ireference()]]
* добавлен сервис получения текущего контекста системы [[tnkernel:ref:sys:tn_sys_context_get|tn_sys_context_get()]]
* можно использовать в функциях, которые вызываются как из задач, так и из обработчиков прерываний и при этом используют системные сервисы
* введен тип ''TN_TIMEOUT'' для параметров сервисов с таймаутами
----
\\
* **2.4.1000** (17 апреля 2008) {{tnkernel:tnkernel_mchp_c30_16bit_2_4_1000.rar|скачать}} @ 458 кБ
* изменен способ проверки контекста в сервисах
* увеличена скорость выполнения системных сервисов в среднем на 15%
* добавлен [[tnkernel:mchp_c30_16bit_port#10. Системный таймер|системный таймер]] и функции ''tn_sys_time_get()'' и ''tn_sys_time_set()''
* изменен способ нумерации версий
* изменена структура исходников
* начиная с этой версии для использования TNKernel достаточно подключить к проекту библиотеку ''xxx.lib'' и включить в модули, использующие сервисы RTOS файл ''tnkernel.h''. Файл ''tnkernel_rev.h'' должен находиться в одной папке с ''tnkernel.h'', другие заголовочные файлы не требуются
----
\\
* **2.4.977** (8 апреля 2008) {{tnkernel:tnkernel_mchp_c30_16bit_2_4_977.rar|скачать}} @ 550 кБ
* добавлен код возврата [[tnkernel:mchp_c30_16bit_port#8. Код возврата TERR_EXS|TNERR_EXS]] - все сервисы создания объектов возвращают этот код, если объект уже создан
* добавлен файл [[tnkernel:mchp_c30_16bit_port#9. Получение ревизии TNKernel|tnkernel_rev.h]], в котором объявлена текущая ревизия и дата сборки библиотеки
----
\\
* **2.4.780** (6 января 2008) {{tnkernel:tnkernel_mchp_c30_16bit_2_4_780.rar|скачать}} @ 545 кБ
* исправлена [[http://www.microchip.su/showpost.php?p=20225&postcount=57|ошибка]] возникающая в режиме модульной и битреверсивной адресации в dsPIC (спасибо **qas**)
* Если во время выполнения библиотечной функции, которая использует модульную или битреверсивную адресацию возникает системное прерывание, регистры ''MODCON'' и ''XBREV'' не сохраняются и не обнуляются. При этом косвенная адресация по прежнему подчиняется правилам модульной или битреверсивной адресации, что однозначно приведет к краху системы. \\ В ревизии 780 введены два target-а - PIC24 и dsPIC. Для dsPIC в стеке задачи сохраняются регистры ''MODCON'' и ''XBREV''. Соответственно изменены файлы сборки библиотеки. В архиве четыре варианта - PIC24 coff/elf и dsPIC coff/elf с оптимизацией Os. В проект нужно просто подключить соответствующую библиотеку. \\ Тем не менее, ядро DSP до сих пор является разделяемым ресурсом и при его использовании нужно применять мютекс.
* изменен способ проверки контекста в сервисах
* увеличена скорость выполнения системных сервисов на 10-15%
* исправлена ошибка проверки контекста в функции ''tn_task_exit()''
----
\\
* **2.4.653** (7 декабря 2007) {{tnkernel:tnkernel_mchp_c30_16bit_2_4_653.rar|скачать}} @ 442 кБ
* добавлены сервисы [[tnkernel:ref:task:tn_task_iresume|tn_task_iresume()]] и [[tnkernel:ref:task:tn_task_isuspend|tn_task_isuspend()]]
----
~~UP~~
==== Thread-Metric Test Suite ====
* Thread-Metric Test Suite TNKernel для PIC24/dsPIC (17 апреля 2008) {{tnkernel:tnkernel_mchp_c30_16bit_2_4_1000_tms.rar|скачать}} @ 130 кБ
----
~~UP~~
==== Документация ====
* Оригинальная документация TNKernel 2.4 ({{tnkernel:tnkernel_user_guide.pdf|скачать}} @ 390 кБ)
----
~~UP~~
===== Почему TNKernel? =====
**TNKernel** ([[http://www.tnkernel.com]]) - вытесняющая RTOS, изначально разработанная для микроконтроллеров с ядром ARM7, имеющая ряд достоинств по сравнению с аналогичными некоммерческими и коммерческими продуктами. TNKernel распространяется по FreeBSD-like лицензии и написана в основном на языке Си, что сделало возможным ее портирование как на 16-битную архитектуру Microchip [[http://www.microchip.com/16bit/|PIC24/dsPIC]] (для компилятора [[http://www.microchip.com/c30/|Microchip C30]]) так и на 32-битные [[http://www.microchip.com/pic32|PIC32]] (архитектура MIPS32 M4K, компилятор [[http://www.microchip.com/c32|Microchip C32]])
При выборе RTOS для применения в проектах с PIC24/dsPIC рассматривались различные варианты: [[http://www.micrium.com/|uC/OS-II]], как наиболее распространенная коммерческая RTOS для однокристалльных контроллеров, [[http://www.freertos.org|freeRTOS]] - широко известная и бесплатная RTOS. Рассматривались варианты портирования [[http://www.rtos.com|ThreadX]] (оригинального порта тогда еще не было) и других платных и бесплатных "легких" планировщиков. Операционные системы с кооперативным планировщиком ([[http://www.pumpkininc.com/|Salvo]], [[http://jacos.narod.ru/|jacOS]]) были откинуты сразу, так как даже первые линейки PIC24/dsPIC имели достаточный объем оперативной памяти для реализации вытеснения.
Основные критерии выбора были следующие:
* наличие исходных текстов и разрешение на коммерческое использование
* простое портирование на другие архитектуры, понятный и масштабируемый код на языке Си
* наличие дополнительных библиотек - файловой системы, tcp/ip стека и т.п.
* объем программной памяти и памяти данных, используемый ядром
* время реакции на внешнее событие
TNKernel изначально удовлетворяла всем критериям, поэтому и была выбрана за основу, несмотря на то что оригинальная версия разработана для контроллеров с ядром ARM7.
~~UP~~
==== Наличие исходных текстов ====
Существует большое количество коммерческих и бесплатных "легких" RTOS для однокристальных контроллеров, исходные коды которых либо выложены в свободном доступе (freeRTOS), либо доступны только для ознакомительных целей (uC/OS-II), либо можно найти в файлообменных сетях (ThreadX).
TNKernel распространяется по лицензии, допускающей модификацию исходников и коммерческое использование при сохранении копирайта. Это стало одним из решающих аргументов.
Несмотря на то, что лицензия freeRTOS так же допускает изменение исходных кодов и коммерческое использование, freeRTOS не удовлетворяет многим другим критериям (с моей точки зрения).
~~UP~~
==== Простое портирование, понятный код ====
Простое портирование или существование портов для других популярных архитектур - так же очень важный критерий, так как бессмыслено постоянно менять (а значит и осваивать) инструментарий при переходе с одного семейства на другое.
Под "простым" портированием я понимаю //четкое// разделение собственно ядра системы (которое должно быть написано на С/С++) и модулей, зависящих от архитектуры (переключение контекста, работа с прерываниями и т.п.). Большинство известных RTOS для однокристальных контроллеров имеют как большое количество портов, так и сформировавшуюся структуру, которая позволяет быстро порты добавлять.
На момент выбора системы порты для 16-битных контроллеров Microchip имели только freeRTOS и uC/OS-II. Однако, порт для uC/OS-II не работал (ошибка в ассемблерном модуле - первый релиз, спишем на это), а в порте freeRTOS был найден комментарий типа "в этом месте может зависнуть, почему - пока не понятно...". Все это ставило под сомнение использование этих систем (тем более, что uC/OS-II еще и коммерческая). Сейчас ситуация изменилась - выходят обновления портов, обновления самих систем. Поэтому выбор может быть не столь очевидным, и, возможно, даже не в пользу TNKernel (если вы, например, уже используете freeRTOS).
Понятный код - еще один момент на котором стоит остановиться. Несомненно, что каждый программист или коллектив имеет сложившийся стиль, поэтому трудно оценивать чужой код - понятный он или нет. Мне наиболее ближе TNKernel - по такому критерию это несомненный лидер.
~~UP~~
==== Наличие дополнительных библиотек ====
В этом случае явным лидером является uC/OS-II, так как имеет огромное количество дополнительного софта (за дополнительные же деньги): файловую систему, стек tcp/ip, библиотеку обслуживания USB, GUI и т.д. freeRTOS может включать в себя порт открытого tcp/ip стека uIP и большое количество [[http://www.freertos.org/embeddedtcp.html|примеров]], построенных на его основе.
Оригинальная версия TNKernel имеет библиотеку [[http://www.tnkernel.com/usb_bulk.html|USB Bulk Firmware]] для контроллеров NXP LPC2100 и урезанный порт [[http://www.tnkernel.com/tnmw.html|Nano-X GUI]]. Если первое не может использоваться совместно с 16-битными контроллерами Microchip в силу понятных причин, то второе вполне можно успешно применять в проектах на PIC24/dsPIC и PIC32. Недавно автором TNKernel был выпущен [[http://www.tnkernel.com/tn_net_1.html|TCP/IP стек]], который, возможно будет работать и на PIC32.
~~UP~~
==== Используемые ресурсы ====
По этому критерию 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 структура системы оставлена прежней.
~~UP~~
==== Время реакции ====
Под временем реакции будем понимать время, необходимое для входа в задачу ожидающую событие с момента наступления этого события. Как правило это время измеряется следующим образом: в задаче вызывается сервис ожидания семафора, а семафор освобождается в обработчике внешнего прерывания. Временем между возникновением прерывания и выходом из сервиса ожидания и будет время реакции.
Оценить время реакции и другие "скоростные" параметры 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_contest_result.png }}
Проект с тестовым приложением для TNKernel можно скачать по [[tnkernel:mchp_c30_16bit_port#Thread-Metric Test Suite|ссылке]].
В таблице присутствуют RTOS, которые раньше не упоминались, поэтому дадим краткую характеристику каждой из них:
* [[http://www.avix-rt.com/|AVIX]] - коммерческая RTOS специально разработанная для микроконтроллеров PIC24/dsPIC (в начале 2008 г. появился порт для 32-битных контроллеров PIC32). По утверждению автора это первая в мире RTOS для однокристальных контроллеров, которая имеет "нулевую" программную задержку входа в обработчик прерывания, то есть системные сервисы прерывания не запрещают. Кроме того, для контекста прерываний AVIX использует отдельный системный стек.
* [[http://www.rtos.com/|ThreadX]] - порт известной коммерческой RTOS для контроллеров PIC24/dsPIC.
* [[http://www.lassarsystems.com/|AVA]] - еще одна коммерческая RTOS, разработанная специально для 16-битных контроллеров Microchip. Судя по результатам теста и критическим ошибкам в первых релизах ничего хорошего из себя не представляет.
Тестирование TNKernel и AVIX можно повторить самостоятельно, скачав проекты. Остальные результаты взяты с форума [[http://forum.microchip.com/tm.aspx?m=279201&mpage=1&key=|microchip.com]]. Результаты тестов так же опубликованы на сайте [[http://www.avix-rt.com/html/performance.html|AVIX]], однако они [[http://www.reuters.com/article/pressRelease/idUS135644+21-Jan-2008+BW20080121|устаревшие]] и неполные.
Если за первое место в тесте начислять 3 балла, за второе - 2 балла и за третье - 1 балл, то AVIX займет лидирующую позицию, ThreadX - второе место, а TNKernel - третье.
Самая популярная freeware RTOS для однокристальных микроконтроллеров - freeRTOS оказалась по совокупности результатов на одном из последних мест. По просьбе автора, freeRTOS удалена из таблицы сравнения на странице [[http://www.avix-rt.com/html/performance.html|AVIX]] - по его утверждению результаты тестов сильно отличаются от реальности. Однако, до сих пор результаты автор freeRTOS не привел, поэтому в этом документе опубликовано то, что было получено в изначальной дискуссии. Вполне возможно, что на самом деле freeRTOS ведет себя гораздо лучше...
Таким образом, можно сказать, что TNKernel является лучшим из вытесняющих планировщиков, распространяемых с открытыми исходными кодами и допускающих использование в коммерческих разработках.
~~UP~~
===== Отличия 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''
Для сборки необходимо, чтобы в системе был прописан путь к исполняемому файлу компилятора.
~~UP~~
==== Порт для PIC24/dsPIC ====
Компания Microchip имеет две основные линейки 16-битных контроллеров: [[http://www.microchip.com/pic24/|PIC24]] - микроконтроллеры общего назначения и [[http://www.microchip.com/dspic/|dsPIC]] - контроллеры цифровой обработки сигналов. По сути PIC24 являются усеченной версией dsPIC - в них отсутствует DSP ядро и специальные методы адресации.
Изначально TNKernel портировалась как под PIC24, так и под dsPIC, причем в версии для последнего в стеке задачи кроме всего прочего, сохранялся контекст DSP-ядра. Но как выяснилось это не имело большого смысла, потому, что полностью восстановить контекст DSP простыми способами невозможно - большинство статусных флагов DSP-ядра имеют доступ только для чтения, да и с аппаратным циклом DO все не так просто. Поэтому от отдельного порта для dsPIC было решено отказаться - в следующих вариантах TNKernel для PIC24/dsPIC DSP-ядро было предложено рассматривать как разделяемые ресурс и использовать для доступа к нему из разных задач мютекс.
Но как выяснилось напрасно. Благодаря камраду **qas** был найден серьезный [[http://www.microchip.su/showpost.php?p=20225&postcount=57 | баг]], который мог однозначно порушить систему при использовании модульной или бит-реверсивной адресации DSP-ядра. Баг исправлен, но опять появилось две версии TNKernel - для PIC24 и для dsPIC.
Тем не менее ситуация с DSP-ядром прежняя - его контекст не сохраняется и его следует рассматривать как разделяемый ресурс, используя для доступа из разных задач мютекс.
~~UP~~
==== Порт для PIC32 ====
Порт для PIC32 был реализован весной 2010 года по просьбам трудящихся. По сути он мало чем отличается от порта для PIC24/dsPIC. Начиная с версии 2.5.600 в комплекте идет пример, который может быть скомпилирован как под PIC24 так и под PIC32 без изменений.
~~UP~~
==== Основные отличия от оригинальной версии ====
=== 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'' : тип счетчика [[tnkernel:ref:sys:intro#Системное время|системного времени]]. Для 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 стек растет от старшего адреса к младшему.
~~UP~~
==== Нововведения ====
=== 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. Новые сервисы ===
Добавлены следующие сервисы:
* [[tnkernel:ref:task:tn_task_isuspend|tn_task_isuspend()]] - останов задачи в прерывании
* [[tnkernel:ref:task:tn_task_iresume|tn_task_iresume()]] - восстановление задачи из прерывания
* [[tnkernel:ref:sys:tn_sys_context_get|tn_sys_context_get()]] - получение текущего контекста системы
* [[tnkernel:ref:task:tn_task_reference|tn_task_reference()]] - получение информации о задаче
* [[tnkernel:ref:task:tn_task_ireference|tn_task_ireference()]] - получение информации о задаче в прерывании
=== 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'', в котором присутствуют следующие определения:
* ''%%__TNKERNEL_VERSION%%'' - текущая версия (float)
* ''%%__TNKERNEL_REVISION%%'' - текущая ревизия (беззнаковое целое)
* ''%%__TNKERNEL_REVISION_TIME_STRING%%'' - время и дата создания ревизии (строка)
* ''%%__TNKERNEL_BUILD_TIME_STRING%%'' - время и дата сборки библиотеки (строка)
Пример использования:
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. Системный таймер ===
Системным таймером назван счетчик, инкрементируемый каждый системный тик. Для установки и получения значения системного таймера используются следующие сервисы:
* [[tnkernel:ref:sys:tn_sys_time_set|tn_sys_time_set()]] - установка системного таймера
* [[tnkernel:ref:sys:tn_sys_time_get|tn_sys_time_get()]] - получение значения системного таймера
=== 11. Файл конфигурации ===
Пользовательский проект должен включать в себя заголовочный файл конфигурации ''tnkernel_conf.h'', в котором определены (или не определены) дефайны ''TN_DEBUG'' и ''TN_NO_ERROR_CHECKING''. Конечно, в свойствах проекта папка с этим файлом должна быть добавлена в пути поиска заголовочных файлов.
{{:tnkernel:include_search.png|Добавление пути поиска заголовочных файлов}}
~~UP~~
==== Использование прерываний ====
Основное предупреждение: все прерывания должны быть запрещены до момента запуска системы. Для конфигурации источников прерываний и разрешения прерываний предназначена функция ''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 эти сервисы запрещают **ВСЕ** прерывания.
~~UP~~
===== Отличия порта для PIC32 от порта для PIC24/dsPIC =====
- ''tn_sys_enter_critical()'' запрещает все прерывания, а не только с приоритетом ''TN_INTERRUPT_LEVEL''
- данные и код не размещаются в именованные секции
- системные прерывания могут иметь приоритет отличный от ''TN_INTERRUPT_LEVEL'', однако приоритет должен быть одинаковым для всех системных прерываний
- приоритеты задач - от 1 до 30
- переполнение стека не контролируется!