понедельник, 17 апреля 2017 г.

Raspberry Pi 3, работа с GPIO в Linux и DALI

см. ранее Освещение на протоколе DALI и его компоненты

Raspberry привлекает не только как маленький и дешевый компьютер, но и наличием GPIO - цифровых интерфейсов ввода-вывода, и с первого взгляда похож на мощный микроконтроллер, вроде замены, Arduino, вкупе с Linux-сервером. Заманчиво, заманчиво...

Я приобрел Raspberry в качестве сервера заботливой ("умной") квартиры, имея ввиду подключение к нему шины управления светом DALI через простой самодельный адаптер, вероятных цифровых датчиков, вроде температуры, видеокамер, как датчиков движения и охраны, ну, и тому подобное.
И вот теперь, начиная писать под Raspbian (официальный Linux для Raspberry), я понимаю свое заблуждение про универсальность.

В общем, Raspberry с Raspbian производит приятное впечатление: работает сразу после копирования системы на SD-карту и подключения hdmi, загружается быстро. Замечая отсутствие хорошей документации, известную медленную работу с SD, пока не пошаманишь и слабый Wi-Fi, начинается понимание, что Raspberry - не зрелый продукт серьезной фирмы, а неплохая реализация неплохой идеи, но, "на коленке". Нет, я только "за" и поддерживаю кошельком, я скорее про завышенные ожидания.

Итак, возвращаясь к настоящей задаче - добавлению квартирному серверу функции управления освещением по интерфейсу DALI.

адаптер собран, к Raspberry подключен (2xGPIO и питание)

Для приема данных DALI нужно уметь считывать состояние цифрового входа не реже 1/2400 секунды или раз в 0,4 мс. Эта простейшая задача для любого копеечного микроконтроллера, однако, под Raspbian сталкивается с серьезными трудностями. Все дело в работающих параллельно моей программе процессах Linux kernel (даже при отсутствии других запущенных программ). Из-за них процесс, читающий состояние GPIO или, что правильнее, вызываемый по прерыванию на фронт сигнала, получает управление нерегулярно и с задержками. Для человека задержка процесса на 2 мс не заметна, и она допустима для настольных многозадачных систем, но для чтения сигнала скоростью более 250 бит/c - почти фатальна.

Начиная программировать на C под Raspbian я узнал, что встроенной в систему поддержки работы с GPIO как бы и нет. И нашел стороннюю библиотеку bcm2835. С ее помощью я проверил, что адаптер работает и сигналы DALI видит. Попытка написать процедуру чтения данных DALI разбилась о тот факт, что bcm2835 не поддерживает прерывания. Вообразите мое разочарование: любой микроконтроллер о шести ножках за 30 центов поддерживает прерывания и GPIO, а Raspberry Pi под официальной Raspbian с официальной поддержкой GPIO, не работает из коробки не только с прерываниями, но и с GPIO.

Новые поиски библиотеки работы с цифровыми входами навели на wiringPi, с прерываниями. И новый опыт показал затруднения программной работы с DALI из-за случайных задержек, описанных выше: при появлении на входе сигнала выставляется флаг прерывания, однако, при параллельно работающих процессах ядра, которые сами активно управляют прерываниями, моя функция периодически вызывается с задержкой, из-за которой часть данных DALI оказывается "не услышана". Если говорить о реальных тестах, то на Raspbian, где работает только программа прослушивания DALI, я получаю 5% ошибок из-за задержек до 2 мс (из которых 2% вполне реально исправить алгоритмом).

Третья по счету библиотека - pigpio - работает с GPIO через DMA (процесс работы с памятью, реализованный аппаратно, поэтому прерывания и другие сложности в ядре процессора ему не должны мешать). Библиотека обещает точность временных интервалов порядка 5 мкс. Такие времена вполне подходят для декодирования DALI. Только нужно понимать, что задержки в вызове программы никуда не денутся. Она будет получать все биты с цифрового входа и точное время появления каждого бита, но получать их с опозданием. Поэтому возможность реализации процесса, где после получения данных требуется ответить за определенный интервал времени, остается под вопросом, благо, в DALI такое поведение необходимо только исполнительным устройствам, но не мастер-контроллеру.

8 комментариев:

  1. Здравствуйте! А почему бы не использовать для приема и передачи DALI банальный UART. Я в свое время написал для ARM обмен с 1Wire на UART.

    ОтветитьУдалить
  2. DALI физически несовместим с UART, начиная от напряжения (порядка 22 V против 3.3 или 5), способа формирования логических уровней (у DALI это замыкание линии через резистор, нормальное напряжение - высокое) и, заканчивая, почти уверен, способом формирования последовательности бит из перепадов уровней.

    ОтветитьУдалить
  3. Естественно физику надо конвертировать, это ежу понятно.

    ОтветитьУдалить
  4. Тогда не понятно, какой смысл конвертить ее в UART, если использованный мной, фактически, конвертер уровней, проще в реализации?

    ОтветитьУдалить
  5. Конвертор уровней останется. Принимать и передавать будет UART.

    ОтветитьУдалить
  6. Хорошо. В чем смысл использования UART против GPIO, пусть даже фрейм DALI можно будет принять UART-ом (не очень ясно, как: фрейм может быть 8, 16 или 24 бита, причем старт и стоп биты одинарные)? В чем выгода?

    ОтветитьУдалить
  7. http://ww1.microchip.com/downloads/en/AppNotes/90003200A.pdf

    Меньше напрягаем процессор, минимизируем ошибки...

    ОтветитьУдалить
  8. Насколько я понял, указанный UART модуль (TB3200) производит MC. В Raspberry 3 стоит SoC Broadcom BCM2837. Применимо ли описание TB3200 к Raspberry 3?

    ОтветитьУдалить