четверг, 17 июля 2014 г.

Высокоуровневая прослойка для AVR: реально ли?

Все, конечно же, знают про Arduino. О том, что она максимально проста и понятна даже для неискушённых в вопросах контроллеров программистов. Всё хорошо до тех пор, пока нет необходимости "копнуть глубже", то есть, залезть в сам механизм. Опять же, всё довольно ясно, если библиотека не использует периферию контроллера. Но как только вам вдруг понадобился таймер...

Предыстория


В контроллерах ATmega, которые используются в Arduino, редко встречается больше трёх аппаратных таймеров. Причём часто один из этих таймеров 16-битный, оставшиеся два - 8-битные. Общий функционал, конечно, у них схож - все так или иначе выдают ШИМ-сигнал, имеют блоки сравнения, генерируют прерывания по разным поводам. Красота, казалось бы.

А теперь представим ситуацию (да что представлять, сам видел, когда мои падаваны в лаборатории делали робота на Arduino). Для устройства нам нужно, чтобы на двух ножках генерировался ШИМ-сигнал для моторов постоянного тока, а также на нескольких ножках должны висеть серво-моторы (в родной ардуиновской библиотеке сигнал на все сервомашинки генерируются одним таймером на прерываниях). Нулевой таймер всегда занят для отсчёта uptime, но, по идее, может выдавать ШИМ.

Если нам повезло, и ШИМ-ножки можно выбрать самому, то ситуация легко разруливается. Но в нашем случае нам попался шилд с драйвером движков, на котором они уже выбраны заранее.

Оп-па! И запросто может получиться такая ситуация, когда висящие на таймерах библиотеки начинают конфликтовать, если настроены на работу с одним и тем же таймером. Последняя инициализированная библиотека обычно "отбирает" себе ресурсы таймера, и то, что инициализировалось раньше, остаётся с носом и не работает. В моём случае получилось так, что если не подключать в коде библиотеку servo, то всё работает, а если подключать, то, в зависимости от порядка подключения библиотек серво и движков, отваливается либо первое, либо второе.

Когда-то я думал, что ардуинщики сделали какое-то API для работы с таймерами, которое автоматически разруливает подобные ситуации. Но не тут-то было. Решателя конфликтов таймеров там нет вовсе; более того, я не нашёл каких-либо гайдлайнов насчёт решения этого вопроса. Каждый программист, пишуший библиотеку для Arduino, вправе цапнуть себе любой понравившийся таймер, что, несомненно приводит к подобным фиаско.

Постановка вопроса


Я уже довольно долго размышляю о написании высокоуровневой прослойки для AVR, и уже даже сделал некоторые подвижки в эту сторону (библиотека Cerebellum). Однако, я уткнулся именно в вопрос с таймерами.

В общем-то, моя идея изначально сводилась к тому, что в системе будет работать служба таймеров, которая будет раздавать кучу простейших программных таймеров на базе одного аппаратного. Пусть даже это будет отъедать (а оно обязательно будет) время в контексте прерываний. Вопрос только в том, что я ещё представляю, как сделать такой таймер с дискретностью в 1 мс, чтобы не очень сильно потерять в производительности основного цикла. Но даже прямо сейчас я могу сходу предложить несколько приложений, в которых требуется куда большая дискретность: приём/передача по IR-каналу, шаговые движки, серво-машинки.

Допустим, такую штуку можно развернуть на STM32, на котором можно задрать частоту до сумасшедших мегагерц (для STM32F103 - до 72 МГц, а для серии F4 так вообще до 168). Но у нас в руках AVR-чип, которому по-хорошему не стоит давать что-то больше 16 МГц (даже если поднатянуть до 20 МГц, это сути дела не меняет), в котором нет NVIC (приоритетного контроллера прерываний), всего три-четыре таймера, но зато большая куча амбиций.

Надо подумать над этим.

Комментариев нет:

Отправить комментарий