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

в 8:10, , рубрики: Программинг микроконтроллеров, программирование микроконтроллеров, метки:

Тема данного поста образовалась почти случайно, в процессе легкой дискуссии по поводу подходов к разработке програмного обеспечения в частности и устройств на МК в общем. Желающие могут ознакомится с самой дискуссией 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 имеется в свободном доступе.

Наверное, такое решение имеет неочевидные для меня минусы, поскольку не было реализовано разработчиками фирмы, пост которой и породил дискуссию. Буду рад с ними ознакомиться, поскольку это несомненно расширит мой кругозор как разработчика.

PS. Не знаю, как добавить опрос следующего содержания:
1. Не следует разжевывать очевидные вещи, здесь не детский сад.
2. Не следует пропускать неочевидные вещи, не все их знают.
3. Ну ладно, так и быть, сойдет.

Подскажите в личку, плиз.

Автор: GarryC

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js