====== Порт 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 - переполнение стека не контролируется!