Programming microcontrollers
May 2014 16

Опыт одного инженерного расследования

Тема данного поста образовалась почти случайно, в процессе легкой дискуссии по поводу подходов к разработке програмного обеспечения в частности и устройств на МК в общем. Желающие могут ознакомится с самой дискуссией habrahabr.ru/company/coolrf/blog/222801. Хотя обе стороны явно остались при своем мнении, тем не менее определенный вызов был брошен. Я вызовов не боюсь, любой челлендж уже сам по себе хорош, поскольку отвечая на него, ты в чем-то меняешься и, как правило, в лучшую сторону (вариант типа «а слабо выпить 10 литров пива за раз», который очевидно меняет человека НЕ в лучшую сторону, в моем возрасте уже не прокатывает). Итак, мы начинаем.

Имеется некоторая разработка диммера (устройства регулирования освещения), который должен получать управляющие сигналы от некоторого устройства по беспроводному каналу, конкретно ZigBee (далее ЗИГ). И вот в процессе проектирования данного устройства выяснилось, что основная программа собственно обеспечения диммирования не может сосуществовать на одном МК с библиотекой организации стека протоколов беспроводного интерфейса. Надо честно признаться (и я это сделал в комментариях), что на момент начала дискуссии я имел всего лишь общее представление о ЗИГ (к данному моменту это уже не вполне верно), но мой предыдущий инженерный опыт категорически возражал против принципиальной возможности существования подобного неразрешимого конфликта.

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

Набросаем псевдокод простенькой реализации алгоритма поциклового димирования с задержкой включения:

while (1) {
  Запрет_прерываний;
   timer=Коррекция_дребезга; while (timer) { if ~signal() {  timer++}; timer--;}; // определяем момент перехода через 0
   timer=Задержка_включения; while (timer) { timer--}; // делаем задержку включения
   Включение; Задержка_на включение; Выключение;
   Разрешение прерываний;
   timer=Задержка_ожидания; while (timer && ) { timer--}; // пауза перед началом очередного цикла
};


При такой реализации критическими секциями являются вторая и третья строка ( ну и четвертая) основного цикла, поскольку соблюдение времени их исполнения определяет точность позиционирования включающего импульса относительно начала цикла, поэтому контролируем эти времена путем запрета прерываний. То есть у нас есть довольно-таки продолжительный интервалы времени, в течении которых прерывания запрещены, и мы не сможем общаться с периферийными устройствами, в том числе и с ЗИГ. Какие тут возможны проблемы? Совершенно не исключено (еще раз подчеркну что с конкретикой ЗИГ я на момент написания поста не знаком), что некоторые операции обмена по радио-интерфейсу требуют жестких ограничений на временные параметры. Кандидатом на такие операции могут быть разного рода «рукопожатия» (подтверждения операции). И действительно, беглое знакомство с описанием библиотеки показывает, что там есть требование по вызову 65 мксек. Поскольку прерывания у нас запрещены на более длительное время, обеспечить выполнение данного требования мы не можем, что и приводит к коллизии. Прежде, чем мы приступим к поиску путей решения проблемы, необходимо выяснить, действительно ли она имеется.

Предположим, что мы действительно не сможем обеспечить требуемую обработку ЗИГ. Ну и что? Стандарт разрабатывался неглупыми людьми (всегда считай собеседника не глупее себя, пока он не докажет тебе обратное, и даже в этом случае ты можешь ошибаться), которые прекрасно знают, что такое эфир в диапазоне 2,4 Ггц, и я никогда не поверю, что в этом стандарте не предусмотрены меры по повторной передаче и коррекции сбоев, в том числе по временным параметрам. Поэтому чем нам грозит пропуск сообщения об изменении параметров свечения лампы? Тем что мы его примем в следующем цикле, когда прерывания будут разрешены, либо в следующем и так далее. То есть задержка изменения свечения лампы может составить (я щедрый) до 10 циклов работы, то есть 10*1/50/2=1/10 секунды. Я не очень понимаю, каким образом такая задержка может быть отмечена пользователем.

Теперь предположим, что используемая нами библиотека (от фирмы ATMEL, между прочим) сделана криворукими программистами (хотя это и противоречит моим принципам, но что не сделаешь в порядке мысленного эксперимента), и она действительно падает, если ее не вызвать в течении 65 мксек после прихода сообщения. То есть мы не сможем гарантировать длительность исполнения строк 1 и 2 при приеме управляющей информации от ЗИГ. Ну и что? То есть при получении информации об необходимости изменения светимости лампы мы можем неправильно выдать очередной цикл управления (мы можем укоротить период свечения вплоть до полного выключения). Если информация передается только, когда ее надо изменить, то опять-таки я не представляю себе пользователя, который заметит изменение светимости лампы, вызванное подобным редким сбоем.

Теперь предположим, что все по настоящему плохо, то есть информация падает к нам достаточно часто и мы обязаны обработать ее в кратчайшие сроки после приема, то есть время выполнения нашего псевдокода становится совершенно непредсказуемым (в сторону увеличения длительности). Ситуация действительно неприятная, и нам не остается ничего другого, кроме как отказываться от применяемой простой и понятной реализации. Что же мы можем сделать, не ставя рядом дополнительный МК (<сарказм>). Ну для начала вспомнить о существовании таких вещей как прерывания, таймеры и связанные с таймером ШИМ модуляторы (всего этого в данном МК есть в избытке). Я предлагаю следующее решение: определяем длительность цикла и настраиваем один из таймеров на соответствующую длительность в режиме автозагрузки или в режиме однократном (на время несколько короче времени цикла). Настраиваем режим ШИМ и выходной сигнал используем для управления симистором. Осуществляем синхронизацию работы таймера с циклом сетевого напряжения. Заводим сигнал о переходе через 0 на прерывание и сажаем на него подпрограмму коррекции длительности таймера (для автозагрузки) либо перезапуска таймера (для однократного). Поскольку этот обработчик очевидно несложен и недолог (длительные операции по вычислению истинного времени прихода прерывания (не забываем про режим захвата), вычисления среднего и так далее могут быть отнесены в нижнюю половину обработчика), требования по запуску библиотеки мы выдерживаем. В общем, все довольны, все смеются.

Тем не менее я бы серьезно подумал о применении в будущем библиотеки, выдвигающей столь жесткие требования к разработке совместно используемого программного обеспечения. Единственно, что приходит в голову: все-таки такие ограничения не заложены в библиотеку разработчиками, а явились следствием не вполне корректной интерпретации ее описания теми программистами, которые ее использовали. Я бы оценил соотношение вероятностей первого и второго вариантов как 2 к 8, особенно если учесть упоминание в описании МК расширенного режима функционирования аппаратуры, который «снижают требования к допустимым задержкам». Но тут мы вступаем на зыбкую почву догадок и предположений, хотя меня тема ЗИГ заинтересовала, и я подумываю о более глубоком ее изучении с написанием соответствующей библиотеки. Правда, несмотря на заявления некоторых участников дискуссии, такая библиотека (для случая простого устройства — это термин ЗИГ) в исходных кодах от фирмы ATMEL имеется в свободном доступе.

Наверное, такое решение имеет неочевидные для меня минусы, поскольку не было реализовано разработчиками фирмы, пост которой и породил дискуссию. Буду рад с ними ознакомиться, поскольку это несомненно расширит мой кругозор как разработчика встроенных устройств.
уровень детализации
21.1% Не следует разжевывать очевидные вещи, здесь не детский сад. 18
55.2% Не следует пропускать неочевидные вещи, не все их знают. 47
42.3% Ну ладно, так и быть, сойдет 36
85 users voted. 54 users abstained.
+7
9.9k 31
Comments 23
Top of the day