Command disabled: backlink
 
Available Languages?:

Программирование микроконтроллеров с использованием ОСРВ OSA

Виктор Тимофеев, osa@pic24.ru (февраль, 2009)

(ОСРВ - операционная система реального времени)

Два слова о том, что побудило написать эту статью. Хоть мне и не часто приходят письма с вопросами по ОСРВ OSA (отписываются не более 10 человек за месяц), тем не менее, этого достаточно, чтобы набрать статистику по часто совершаемым ошибкам. Я уже несколько раз отвечал на одни и те же вопросы и давал одни и те же советы, поэтому я решил все это дело обобщить в одной статье и выложить на всеобщее обозрение. Полагаю, что статья окажется полезной не только тех, кто только начинают писать программы с использованием ОСРВ, но и для тех, кто уже имеют некоторый опыт.

Статья разделена на несколько частей:

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

Зачем контроллеру "ось"?

Прежде чем ответить на этот вопрос, попробуем определиться с тем, что мы называем операционной системой реального времени (ОСРВ) применительно к контроллерам.

Четкого определения самого понятия ОСРВ не существует, тем не менее большинство определений схожи в одном: ОСРВ - это операционная система, способная среагировать на событие в заданный промежуток времени. Но даже здесь есть допуск, а именно - разделение ОСРВ на системы мягкого реального времени и жесткого реального времени; первые отличаются от вторых как раз тем, что они допускают неопределенную задержку реакции на событие, в то время как для вторых эта задержка не должна превышать какого-то фиксированного значения (а если превысит, то это будет считаться системной ошибкой).

OSA относится к системам мягкого реального времени, т.к., являясь кооперативной, допускает захват ресурсов низкоприоритетной задачей на длительное время, не давая выполниться более приоритетным, т.е. не давая остальным задачам среагировать на событие в заданный промежуток времени. Этого недостатка лишены вытесняющие ОСРВ, в которых ядро в любой момент может прервать выполнение низкоприоритетной задачи и передать управление готовой к выполнению более приоритетной. Однако, вытесняющая ОСРВ не сможет работать на платформе без программно доступного стека. Контроллеры PIC серий 10, 12, 14 и 16 имеют именно такую платформу. Но зачем же тогда OSA поддерживает и старшие семейства этих контроллеров, если для них уже возможно использование вытесняющих ОСРВ? Здесь есть две причины:

  1. кооперативная ОСРВ требует на порядок меньше RAM-памяти под свои нужды, оставляя программисту большую часть памяти под нужды самой программы;
  2. кооперативная ОСРВ проще в понимании и в организации программ с ее использованием.

Что хорошего дает использование ОСРВ

Так зачем же нужна операционная система в контроллерах? Я бы назвал несколько причин.

Во-первых, ОСРВ предоставляет программисту готовый планировщик - некую подпрограмму, следящую за состоянием выполняемых задач, обеспечивающую поиск наиболее важной на данный момент и передачу ей управления. Поскольку часто на контроллер возлагается выполнение сразу нескольких задач (например, чтение клавиатуры, вывод данных на дисплей и пр.), то программист, создавая очередную программу, так или иначе вынужден каждый раз с нуля писать некий свой планировщик (в простейшем случае - это суперлуп, где все задачи-подпрограммы вызываются по очереди в бесконечном цикле). При этом в большинстве случаев не учитывается важность (приоритет) подпрограмм, вызываемых таким планировщиком, и подпрограмма, требующая больше внимания к себе со стороны планировщика, будет, тем не менее, получать его поровну со всеми остальными. Так вот, ОСРВ обеспечивает программиста уже готовым планировщиком, способным не только самостоятельно запускать все подпрограммы, но еще и определять, нужно ли какую-то конкретную подпрограмму запускать в данный момент, или нет, а также при обнаружении нескольких готовых к выполнению подпрограмм выбирать из них наиболее важную и передавать управление именно ей. (Примечание: в ОСРВ такие подпрограммы называются задачами.)

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

(Примечание: здесь речь, конечно, идет о псевдопараллельности, т.е. когда все задачи выполянются по очереди, быстро сменяя друг друга; порядок очереди определяется приоритетами и готовностью задач к выполнению.)

В-третьих, ОСРВ берет на себя отсчет временных задержек. Часто в программе нужно выдержать паузу (например при записи в EEPROM мы ждем 5-10 мс). Выполняя задержку явно, т.е., зацикливая программу до тех пор, пока какой-нибудь счетчик не достигнет нужного значения, мы блокируем работу всей программы на время выполнения этой задержки. Не страшно, если нам нужно подождать 10 мс после записи одного байта в EEPROM. А если нам нужно записать 100 байт? Придется "вешать" программу на секунду? ОСРВ же дает возможность организовать программу так, чтобы во время выполнения задержки одной задачей могли выполняться остальные задачи. Т.е. отсутствует время пустого простоя системы. Кроме того, часто в программах требуется ожидать некоего события, но так, чтобы была возможность прервать ожидание, если событие не происходит в течение какого-то времени. Простейший пример - набор номера в GSM-модеме и ожидание ответа. Мы не можем ждать вечно, поэтому дополняем программу неким механизмом, который по истечении заданного времени прервет ожидание. Для этого мы заводим отдельный таймер (тактируемый, например, в прерывании) и следим за его значением. В этом есть некоторые неудобства. Во-первых, на время ожидания все остальные задачи блокированы; во-вторых, нужна отдельная глобальная переменная нужной размерности, имеющая осмысленное имя (например, ModemAnswerTimer); в-третьих, нужно не забыть все такие переменные инкрементировать в обработчике прерываний; есть еще в-четвертых и в-пятых, но это уже мелочи. ОСРВ же может обеспечить ожидание события с выходом по таймауту так, что оно будет лишено перечисленных недостатков, особенно - главного из них: система не будет простаивать впустую во время ожидания.

(Комментарий Alex B.) Тут дело даже не в какой-то абстрактной блокировке остальных задач. Очень часто 5 мс это действительно незаметный отрезок. До тех пор, пока во вводных основной проблемой не станет энергопотребление. Несмотря на то, что устройство может быть не автономным, уменьшение интегрального потребления есть серьезный плюс к ТТХ вашего девайса.

В-четвертых. В большинстве случаев подпрограммы, отвечающие за разные функциональные узлы, должны обмениваться между собой информацией. Например, подпрограмма, производящая опрос клавиатуры, должна сообщать остальным подпрограммам, какая кнопка была нажата/отпущена; а подпрограмма, выводящая информацию на экран, должна эту информацию откуда-то получать. Т.е. программа должна иметь какой-то механизм обмена информацией между внутренними функциями. Тут есть несколько вариантов: через аргументы функций, через глобальные переменные, наконец, через сервисы операционной системы (семафоры, сообщения, флаги). А как быть, когда одна задача должна получать данные от нескольких задач сразу, или когда какая-то задача отправляет данные быстрее, чем задача-получатель успевает их обрабатывать? Вот тут на помощь приходит очень полезный механизм ОСРВ - очереди сообщений. Они позволяют задаче-отправителю отправлять следующее сообщение (какую-то полезную информацию), если предыдущее еще не успело обработаться задачей-получателем. Все это, конечно же, можно реализовать и без ОСРВ, но зачем выполнять уже выполненную работу, к тому же уже проверенную и отлаженную.

В-пятых, использование ОСРВ улучшает читабельность и наглядность программного кода. То, что реализуется без ОСРВ в 10-15 строках кода, с ОСРВ может быть записано одной строкой. Здесь я не буду приводить конкретных примеров, пока поверьте мне на слово, а когда дойдет дело до написания программы, сами убедитесь в том, что это так.

Наконец, в-шестых, последний аргумент в пользу применения ОСРВ - удобство написания программы, когда над ней трудятся несколько человек. Применительно к PIC-контроллерам, конечно, это редкость, но тем не менее - это большой плюс.


Что мы теряем, используя ОСРВ

За все выше перечисленные полезности придется платить.

Платим мы в первую очередь памятью контроллера. Сама ОСРВ требует под себя некоторые ресурсы, пусть небольшие, но все-таки. Чем больше параллельных задач, тем больше RAM потребуется для хранения их текущих состояний, адресов возврата и внутренних таймеров. Кроме того, система оперирует еще и своими внутренними переменными, такими как указатель на текущую задачу, лучший приоритет и пр. Ну, естественно, сами системные сервисы и планировщик требуют под себя программную память.

Во вторую очередь мы платим системным временем. Поиск самой важной их готовых к выполнению задач не происходит мгновенно. На это требуется время. Чем больше задач, тем дольше будет выполняться поиск. Это следует учитывать при проектировании программы.

В третью очередь, как ни печально, мы платим непереносимостью программного кода. Т.е. переносимость программы с одной платформы на другую возможна только при том условии, что другая платформа так же поддерживается выбранной ОСРВ. Здесь конкретно для OSA выбор пока ограничен только PIC-контроллерами серий 10, 12, 14, 16, 18, 24, 30 и 33. Расширение планируется, но не сегодня и не завтра. Эта задача на перспективу.

Наконец, опасениями, что "код разработан не мной, а каким-то дядей", и кто знает, что у этого дяди было на уме. Я сам работал с чужими библиотеками и помню, что когда натыкался на какую-то ошибку, всегда в первую очередь грешил на библиотеки. Некоторые идут дальше: не в библиотеке - так в компиляторе, не в компиляторе - так в программаторе, не в программаторе - так в контроллере! И вот уже строчат письмо на support.microchip.com: "Я лажу нашел! В ваших контроллерах RA4 неправильно работает!" Однако, 99% всех ошибок - на совести программиста. Тем не менее, не исключены и ошибки библиотек, компиляторов, программаторов, наконец, самих контроллеров (не случайно ведь появляются документы ERRATA). И ОСРВ здесь - не исключение. Те, кто отписываются мне по OSA, бывает, обнаруживают неправильное поведение системы, помогают отлавливать баги. И чем больше народа отписывается, тем более безглючной становится "ось". После отлова очередного бага (а они все хитрее и все трудноуловимее) всегда кажется, что вот теперь-то багов точно нет. Тем не менее, нет-нет, да обнаружится еще один (еще более хитрый). Поэтому вряд ли я когда-нибудь скажу: "Все, пользуйтесь. Багов нет!" (Да и ни один производитель ПО такого не скажет). Поэтому сидеть и ждать, когда система станет абсолютно безглючной, - это так никогда и не приступить к работе с ней. А попробовать стоит хотя бы из любопытства. Если и решите: "нет, это не для меня", - то хотя бы, я уверен в этом, почерпнете для себя что-то новое.


Можно ли обойтись без ОСРВ?

Ответ однозначный: да, можно. При проектировании программы программист должен предварительно взвесить все выше перечисленные аргументы, свои аргументы, свои предпочтения, элементную базу и пр. и принять решение, что ему будет быстрее/удобнее/дешевле.


Резюме

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

 
osa/articles/rtos_usage_1.txt · Последние изменения: 23.02.2010 23:07 От osa_chief
 
Creative Commons License Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki