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

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

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

    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

    уровень детализации

    Поделиться публикацией

    Комментарии 23

      +2
      Мне кажется, алгоритм, который вы приводите
      while (1) {
      Запрет_прерываний;
      // определяем момент перехода через 0
      // делаем задержку включения
      // Включение; Задержка_на включение; Выключение;
      // Разрешение прерываний;
      // пауза перед началом очередного цикла
      };
      — это пример несложной задачи и ее неоптимального решения. То, что вы упираетесь в последствия неоптимальности — это нормально, и связано с нормальным ростом требований к устройству.

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

      И не ожидайте, что любой DIY алгоритм может быть перенесен в серийное устройство без глубокой переработки.

      Я думал, вы решение проблемы ищете…
        0
        Спасибо, конечно )
        Все же хотел бы заметить, что второе — то есть увеличение мощности (смена) платформы представляется автору коментария предпочтительным на фоне необходимости оптимизации алгоритма.
        Весь пафос поста и заключался в том, что многие из современных разработчиков избегают решений, связанных с глубоким проникновением в суть процесса, который и необходим для оптимизации хоть алгоритма, хоть библиотек, поскольку, прежде чем что-либо улучшить, надо разобраться, как оно работает.
        Может, конечно, раньше трава была зеленее, но мы такими не были.
          +2
          Кстати, я не очень понял итоговую посылку поста —
          • если требуется ответ коллективного разума на вопрос «можно ли совместить фазовое управление мощностью с ограничением задержки в 65мкс» — то ответ «ДА» (но это и в посте написано).
          • если требуется ответ на вопрос «как конкретно реализовать совместную работу фазового управления и уложиться в 65мкс задержек» — то мой опыт — аппаратный детектор нуля на выпрямителе, потом прерывание с контролем правильности длительности полупериода (упрощенный подавитель дребезга), в котором взводится таймер на заданную длительность импульса на открытие триака.
          • если требуется ответ «обоснован ли отказ от семейства микроконтроллеров из-за недостатка опыта программирования в условиях поджимающих сроков» — ответ для менеджера проекта — «ДА, но программиста пора менять», ответ для программиста — «НЕТ, ты занимаешься этим в том числе для того, чтобы приобрести опыт».

          А голосование в конце поста меня окончательно сбило с толку. Короче, ответьте, чего в итоге хочет автор?
            0
            Вы абсолютно верно поняли основную мысль поста — необходимо думать разработчику, а не тупо перебирать МК и библиотеки в надежде, что все само как нибудь получится.
            А голосование в конце — это ко всем моим постам независимо от содержания — пытаюсь понять уровень детализации изложения. Наример, в этом не удержался и дал коротенькое описание методов димирования, вот и пытаюсь понять — не зря ли, может все всё про него и так знают.
              +1
              Тогда поставлю на полях отметку «крик души».

              Вот, кстати, еще парочка замечаний:
              При выборе платформы (ну, в данном случае было наоборот, взяли готовую заготовку, но вы понимаете, о чем я) нужно же закладывать некоторый запас по ресурсам? Так вот, запас по «latency» — такой же ресурс как объем памяти или MIPS. И нужно помнить об этом запасе при рассмотрении каждого нового требования или хотелки. Это, кстати, через годик становится весьма ценным куском опыта, т.к. появляется возможность до начала реализации фичи прикинуть в уме (по нескольким ранее реализованным или отклоненным) и сказать на раннем этапе — «мы не помещаемся в запас по latency», сэкономив немножко времени на прототипировании. Даже один такой аргументированный ранний отказ — это конкретный профит и он обычно приветствуется окружающими.
              Появляется и дополнительный аргумент для неиспользования кривых алгоритмов — если алгоритм пожрал 80% запаса по какому-то из ресурсов (как, например, в приведенном псевдокоде — пожрал 100% latency), то, ясен перец, второй подобный алгоритм уже не запихаешь, да и более скромные алгоритмы уже не добавишь.
                0
                Да, пожалуй, «крик души» это в тему.
                Просто смотрю на подобные проекты, потом вижу на хабре пост про какой нить центр для самоделкиных в Китае и в памяти всплывает незабвенное " Пока мы спим, АЛЕНИ качаются".
            +1
            Где-то мы пересекли тот тонкий момент перехода с дорогого железа и дешевого времени на дешевое железо и дорогое время. Сейчас время разработчика значительно дороже железа, поэтому такой подход.
            Темболее в современных реалиях тотального усложнения искать решение проблемы может оказаться неоправданным расточительством когда проще и дешевле решить проблему хорошо прогнозируемыми методами.
              0
              Ну в приведенном мной идее реализации нет НИЧЕГО сложного. То есть вообще ничего, что потребовало бы более 1 дня работы. То есть сейчас разработчик НАСТОЛЬКО дорог?
              Не говоря уж о том что главный капитал — а именно опыт разработки, при моем подходе только возрастает. И, все таки, не будем выпускать из вида то, что решение проблемм стандартными методами никогда разработчика не выведет на уровень переднего края, где действительно нужно выжимать ВСЕ из железа и софта, а наоборот, постепенно низведет до уровня индусского программера.
                0
                Ну, 1 день это очень оптимистичная оценка… такое время в более-менее сложном проекте уйдет только на «оценку ущерба». Цель ведь не сделать любыми средствами, а сделать так чтобы не развалилось в коде который полностью не умещается в мозгу одного человека.
                  0
                  Один день — это восемь часов. Если не читать хабр, не запускать птичек и не спорить на тему «а можно ли так сделать, а нельзя ли сделать по другому, а не лучше ли перейти на другой МК и тд» и знать МК, для которого реализуешь предлагаемый алгоритм (а иначе что мы тут делаем), то этого вполне достаточно. Ну по крайней мере для меня, не буду говорить за других. И что тут может не уместиться в мозгу одного человека, в этом данном конкретном случае, описанном в посте?
                    0
                    Вот мне интересно, откуда в вас столько желчи? :) Так и плещет в комментариях. Я бы на вашем месте бы аккуратнее в выражениях. Здесь желчи обычно не терпят.

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

                    Плюс важный момент — лично мне хочется как аппаратные, так и программные разработки по проекту делать открытыми народу. Для этого они не должны перешагивать определенного порога сложности, по двум причинам: 1) чтобы можно было легко донести их до людей без вашего многодесятилетнего опыта разработки и 2) если вложить в разработку софта одного диммера 100-200 тыс рублей (а это не самая большая ставка профессионального разработчика за 1,5-2 месяца фултайма) личных денег, то у меня рука уже не поднимется просто взять и выложить это для всех. Не рационально.

                    Этот «порог» по зигби уже четко понятно, что будет перешагнут. Плюс идея нашего проекта в том, чтобы у людей было удобное решение для кастомизации «по своему велению». В зигби по факту для кастомизации готовой прошивки потребуется недюжая квалификация. Тоже мимо.

                    Мы делаем «ардуино» в области умного дома — это вам совсем не понятно?
                      +1
                      Что то я не понял — вы от ЗИГ отказались?
                      Если не отказаллись, то как совместить применение закрытой бибилиотеки с желанием сделать разработки открытыми народу?
                      Если имеется в виду, что проект должен быть понятен с точки зрения легкого допиливания, то это один подход.
                      А если ВЕСЬ проект должен быть понятен и модифицируем, то это другой подход, и, конечно, другие затраты.
                      Что касается нерациональности выкладывания результатов… вся концепция открытого софта на этом базируется и неплохо себя чувствует. Не скажу, что все, что я видел в опен, представляет собой шедевр, но есть и вполне приличные разработки, и люди ими реально делятся с другими.
                      Ну и чуть в сторону. На мой взгляд, одна из проблем индустрии встроенного ПО в нашей стране в том, что у нас нет профессионального сообщества, как в других странах. Лично я с завистью читаю сообщения о ивентах разработчиков даже не в Штатах и Европе, а в Бразилии, например. Если бы оно существовало, то просто для получения определенного статуса в глазах близких тебе по духу людей многие делились бы своими достижениями (в соответствии с пирамидой потребностей). Не знаю, как другие авторы, но я пишу именно для этого. Ну нельзя все выгоды сводить только к монетизации знаний, неправильно это.
                      Насчет желчи… со стороны, конечно, виднее, но я думал, что выражаю свою глубокую озабоченность состоянием дел в индустрии, которой отдал большую часть своей жизни. Причем такое состояние не только у нас, если верить тематическим иноязычным сайтам. А что касается аккуратности в выражениях, то я свое мнение (часто саркастическое) по поводу отдельных аспектов окружающей нас «объективной реальности, данной нам в ощущениях» (интересно, сколько хабровчан узнают автора цитаты) не скрывал и в те времена, когда это действительно было небезопасно, а уж в наше время — «минусов бояться, честно не писать » — так, что ли?
                      Ну и в заключение — если предложение поработать 8 часов в день приравнивается к троллингу, значит все еще хуже, чем я думал.
          0
          </сарказм> Не благодарите :)
            0
            А все равно спасибо ).
            0
            Интересно, хватит ли свободных ресурсов, чтобы сделать программный ФАПЧ с приемлемой точностью (например, 5 градусов) на частоту 50Гц?

            Например, оцифровывать аналоговый сигнал напряжения сети (достаточно будет порядка пары десятков измерений за период 20 мс), исходя из оцифрованных значений вычислять текущую частоту и фазу, и соответственно предсказывать переходы через ноль и соответственно заряжать PWM таймер на периодическое срабатывание с нужной скважностью? Нужен будет еще один свободносчитаемый таймер для временной оси (необязательно завязанный на прерывания), с него программно можно считывать показания в обработчике прерывания АЦП, сохраняя пары (время: значение)

              0
              Интересное предложение, но потребует АЦП и делителя.
              Хотя делитель входного напряжения в устройстве уже наверняка есть, хотя бы для питания.
              Мне кажется, что даже детектора больше/меньше при длительности циклов в 100-200 ( а это 1-2 секунды) должно хватить для начальной настройки.
                0
                Если мне не изменяет память там блок питания на гасящем конденсаторе так что делителя для вычисления уровня напряжения питающей сети в БП нету, а есть ли он отдельно… у меня большие сомнения, скорее всего переходом через ноль ограничились.
                  0
                  А там и питающей сети нет, питается устройство через нагрузку. Так что измеренное напряжение на входе — «бабушка надвое сказала», особенно при 100% яркости.
                  0
                  Еще можно отдать расчет момента включения на откуп аналоговой части — заряжать конденсатор через резистор от выпрямленного мостовым выпрямителем сетевого напряжения (приведенного к диапазону АЦП естественно) — тогда напряжение на конденсаторе примерно будет пропорционально площади (то есть мощности), «отрезаемой» от полного периода сигнала части. Если на кристалле есть компаратор с программно-устанавливаемым порогом, то нужно просто рассчитать его величину соответственно необходимой мощности в нагрузке, а выход компаратора соединить с управлением симистора. Если же компаратора нет, а есть просто АЦП — то тогда обрабатывать по прерываниям в однократном режиме, и проверять значения программно. Нужно только как-то обеспечить, чтобы после выдачи управляющего сигнала конденсатор оставался зашунтированным, готовым к интегрированию напряжения в следующем цикле (в двухполюснике, которым является ваш выключатель, такое условие соблюдалось бы автоматически, если бы не двухполупериодный выпрямитель, который не даст разрядиться конденсатору через открытый симистор)
                  +1
                  Насколько я знаю, в атмеловских контроллерах есть возможность задать таймеру частоту переполнений одним из регистров сравнения, вторым можно задавать скважность, по прерыванию перехода через ноль сравнивать «остаток» таймера и корректировать его скорость — это буквально несколько строчек на ассемблере.
                  основная проблема это в оффлайне пересчитывать значение регистра сравнения под необходимую скважность — это задача более сложная, но может подождать решения до 2-3 полупериодов.
                  В одном проекте на PICe лет 10 назад вообще ничего такого небыло — ШИМ был программный на таймере, таймер считал время от начала сетевого периода и программно отсчитывалась точка полупериода который не получилось поймать — в том камушке очень скромные возможности по прерываниям, можно было поймать либо только фронт либо спад но не оба одновременно. И что же… на 4Мгц тактовой частоте все работало и не шуршало. А тут, как я понимаю мегагерцы частоты, быстрый конвеер исполнения инструкций и «ничего не работает»?
                  +3
                  Для ответа на «почему вы братцы просто не умеете их готовить» — чОтко.
                  Для «вызов принят» — не хватает кода.
                  Тут просто нужен PoC. Про себя я скажу так — у меня тиристорное управление + математика + довольно нагруженный протокол по UART работают без проблем на ADuC 847 на 6 мгц
                    0
                    Ну главная идея реализации правильного метода изложена — написать еще и код было бы, на мой взгляд, перебором, надо же читателю оставлять место для фантазии ).
                    И Ваш пример подтверждает главную мысль поста — делайте все аккуратно и не придется переходить на другой МК. Рад, что не все современные разработчики перешли в «кое-какеры».
                    0
                    Кстати, подскажите в личку, плиз, как результаты голосования по опросу посмотреть?
                    А то затеял оценку уровня сложности, а результатами воспользоваться не могу ((.
                    Уже нашел )))).

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.