• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ESP8266 и аппаратный таймер hw_timer

pvvx

Активный участник сообщества
Вот девиация длительности входного импульса (голубой) с периодом 100 Гц и выход (желтый):
1607385101476.png
 

pvvx

Активный участник сообщества
Ну и время срабатывания от фронта, с рассогласованием тактовых, т.е. джиттер срабатывания (ESP на 80MHz):
1607385842853.png
и кривая работа выхода GPIO на светодиод на модуле :) как ему бедному тяжко пересилить через резистор (диффузионную) емкость светодиода...
 

pvvx

Активный участник сообщества
Тяжко ему на формирование 5 us импульс, на 10 тоже, т.к. прибавка 1.1..1.8 us на обработку входа в прерывание таймера...
1607386972212.png
 

pvvx

Активный участник сообщества
Для индикаторного масенького (чтоб моргания не видны были) светодиода диммер пойдет... Не более.
 

nikolz

Well-known member
Вот такая запись меня и смущает. Допустим сейчас у меня в основном цикле ничего нет. И я подберу длительность Delta. Далее я решил добавить функционал и подключил 4 датчика Ds1820, у меня изменится длительность loop? Значит опять нужно подбирать значение переменной Delta?
ЗЫ: Делал диммер на AVR с частотой 16 МГц, и никаких проблем. Здесь имеем проц 80 или 160 МГц, и не получается сделать импульс 20 мкс
Нельзя объять необъятное.
------------------
Попробуйте мыслить в рамках решаемой задачи,
а не пытаться придумать случаи, когда диммер перестанет им фактически быть.
------------------------
когда Вы будете разрабатывать устройство, например, управления самогонным аппаратом ( там есть и датчики температуры и диммер) ,
то будете составлять алгоритм для этого конкретного устройства,
а не переделывать диммер в автомат управления самогонным аппаратом.
------------
Есть такое понятие -технология разработки устройства.
----------------------
Прежде чем что-то разрабатывать, Вы должны:

1) сформулировать задачу - т е описать функциональные свойства устройства или, иначе говоря, составить техническое задание.

2) После этого, вы выбираете метод решения задачи,

3) затем разрабатываете алгоритм , реализующий выбранный метод,

лишь после этого Вы пишите этот алгоритм на любом языке программирования затем транслируете компилируете отлаживаете...
---------------
Указанная последовательность действий обладает тем замечательным свойством, что п 1,2,3 - универсальные и не зависят от языка программирования.
Обычно аля-кулибины и самоучки не утруждают себя выполнением этих этапов, так как не умеют их делать.
Но именно эти пункты позволяют на этапе практической реализации сделать все быстро и оптимально.
Написание программы под конкретное железо - это подобно общению на неизвестном языке с помощью словаря.
Именно так и выглядят программы, которые аля-кулибины сразу начинают лепить придумывая на ходу что же они такое лепят.
---------------
Вы не опубликовали свое тех задание, а лишь сообщили название устройства и показали свою программу в которой Вы формируете задержанный от нуля сети импульс.
Я написал Вам простейший алгоритм реализации этого алгоритма - т е диммера для управления яркостью лампочки, либо любой активной нагрузкой.
В диммере лампочки нет надобности высокого быстродействия и высокой точности управления, поэтому нет надобности в железном таймере,
которым в ESP можно формировать импульсы с дискретом на порядок меньше, чем требуется в диммере лампочки.
----------------------
Поэтому прежде чем писать программу сделайте указанные шаги 1 2 3. После этого можно решать надо таймер или нет.
Иначе так и будете гадать, что будет, если Вы чего-то когда-то захотите.
----------------------
Если Вы хотите освоить таймеры ESP, т е освоить управление железом , то причем здесь диммер.
Вам и надо писать тесты железа используя SDK. В этом случае не имеет значение есть датчики температуры или их нет.
----------------------
Пока же Вы все смешали в одну большую кучу
и пытаетесь на ней гадать, а что если...
 

nikolz

Well-known member
Вот такая запись меня и смущает. Допустим сейчас у меня в основном цикле ничего нет. И я подберу длительность Delta. Далее я решил добавить функционал и подключил 4 датчика Ds1820, у меня изменится длительность loop? Значит опять нужно подбирать значение переменной Delta?
ЗЫ: Делал диммер на AVR с частотой 16 МГц, и никаких проблем. Здесь имеем проц 80 или 160 МГц, и не получается сделать импульс 20 мкс
эта проблема решается просто.
Вводите два коэффициента A и В, которые позволяют Вам нормировать величину задержки
Dimmer= A*Delta+B.
А в loop вместо Dimmer-- (вычитание 1) делаете вычитание константы C, что обеспечивает управление квантом изменения задержки.
--------------
в ЗЫ -виновато зеркало
 

nikolz

Well-known member
и еще...
Ваш вопрос (рассуждения) про активную и реактивную нагрузку - не имеет отношение ни к таймеру ни к железу ни к программированию
Это вопрос выбора метода решения задачи.
----------
Для этого надо изучать электротехнику, на не пытаться сформировать на ESP импульс в 20 мкс.
И ваш опыт программирования на AVR вообще не поможет.
-------------
А если захотите управлять самогонным аппаратом, то придется изучать и ПИД регулятор.
-------
А пока наслаждайтесь картинками pvvx.
Созерцание их увлекательно, но бесполезно.
 

Melandr

Member
Доброе утро!
pvvx , не могли бы код, которым формировались вышеуказанные осциллограммы, выложить в тему. Хочу проверить, почему у меня не получилось получить такую маленькую длительность импульса. Пробовал также менять частоту процессора на 160 МГЦ, памяти на 40 МГц, но при 50 мкс в коде, на выходе было минимум было 70 мкч
 

pvvx

Активный участник сообщества
Доброе утро!
pvvx , не могли бы код, которым формировались вышеуказанные осциллограммы, выложить в тему. Хочу проверить, почему у меня не получилось получить такую маленькую длительность импульса. Пробовал также менять частоту процессора на 160 МГЦ, памяти на 40 МГц, но при 50 мкс в коде, на выходе было минимум было 70 мкч
Код только этот https://esp8266.ru/forum/threads/esp8266-i-apparatnyj-tajmer-hw_timer.5369/post-76642
а на вход, для теста его, работает программируемый генератор.
 

pvvx

Активный участник сообщества
Генератором + осел и снял основные параметры выложенного "диммера" при работе ESP на 80MHz:
Задержка от фронта выходного импульса от входного перепада в вверх - 1.8..2.7 us
  • Минимальная формируемая длительность импульса - 5..7 us
  • Максимальная формируемая длительность импульса - 1677721.4 us
  • Джиттер по длительности формируемого импульса - до 0.8 us
  • Дополнение длительности импульса к счетчику в тиках 0.2 us - около 1.1 us
В итоге максимальная частота обработки при самой малой длительности выходного импульса - примерно 70 кГц (процу надо оставить время на обработку других функций :))
И если прикинуть, что формируемый минимальный сигнал не должен дрожать более чем на 1%, то получаем предел в что-то около 10 кГц.
На 100 Гц у нас ждиттер (в 0.9us) будет составлять одну десятитысячную.
 

pvvx

Активный участник сообщества
Для этого надо изучать электротехнику, на не пытаться сформировать на ESP импульс в 20 мкс.
Вы о чем там бубните? ESP через GPIO может формировать импульс в 2/26000000=0.0000000769 сек и кратные ему. Если надо меньше - есть i2s, SPI.
Но это всё убивается проприетарщиной от Espressif - её закрытым кодом и сИкретной документацией на чип.
И ваш опыт программирования на AVR вообще не поможет.
Никакой разницы, только ESP более убог по части таймеров и прочего, особенно по кол-ву багов.
Не пудрите людям мозг своими недоразумениями.
 

pvvx

Активный участник сообщества
Доброе утро!
pvvx , не могли бы код, которым формировались вышеуказанные осциллограммы, выложить в тему. Хочу проверить, почему у меня не получилось получить такую маленькую длительность импульса. Пробовал также менять частоту процессора на 160 МГЦ, памяти на 40 МГц, но при 50 мкс в коде, на выходе было минимум было 70 мкч
Для данного кода в среде Arduino вот минимальная длительность следования NMI по фронту включающего выходной импульс и NMI по таймеру отключающему импульс:
1607417199395.png
ESP на 160 MHz. В таймер грузится 5 us, осел говорит что выходной импульс имеет длительность 5.26..5.75 us. Меньше незя - переполнение стека.
В Arduino процедуры обработки прерываний (сохранения контекста) очень длинные и кривые (до калбаков и обратный выход) - тем и определяется минимальная длительность следования NMI прерываний до переполнения стека.
Все джиттеры относительно импульса сигнала с генератора c периодом в 100 кГц видны на картинке.
Так-же видно как не справляется GPIO2 с отключением штатного светодиода на модуле ESP12 - фронт искажен, при включении не дотягивает до нуля...
Остальное - это сопли от проводов с железными китайскими пимпками в разъемы 2.54 платы ESP12E DEVKIT к которым подключен осел и генератор...

В коде измена только эта строка:
uint32_t pulse_in_0us2 = 5 * 5; // in 0.2 us (0x007fffff max)
 

pvvx

Активный участник сообщества
Ну и побаловаться можно:
C++:
uint32_t volatile pulse_in_0us2 = 5 * 5; // in 0.2 us (0x007fffff max)
....
void loop() {
  uint32_t tmp = pulse_in_0us2;
  if (++tmp > 10000 * 5)
    tmp = 5 * 5;
  pulse_in_0us2 = tmp;
}
1607418653086.png
Всё - модуль ESP отправляется в его нормальное место обитания - в коробку с хламом. "Скетч" вам накалякал - хватит - балуйтесь :p
 

Melandr

Member
pvvx, доброй ночи!
Спасибо за Ваш пример. Разобрался с работой GPIO ESP8266. Хотел бы еще у Вас поинтересоваться. В своем примере Вы объявляете обработчик таймера такой функцией:
ets_isr_attach(ETS_FRC_TIMER1_INUM, hw_test_timer_cb, NULL);
Я использовал и находил в примерах вот такое объявление обработчика аппаратного таймера:
hw_timer_set_func(hw_test_timer_cb);
В чем разница и какое правильное? По поиску не нашел ничего. Заранее спасибо!
 

pvvx

Активный участник сообщества
pvvx, доброй ночи!
Спасибо за Ваш пример. Разобрался с работой GPIO ESP8266. Хотел бы еще у Вас поинтересоваться. В своем примере Вы объявляете обработчик таймера такой функцией:
ets_isr_attach(ETS_FRC_TIMER1_INUM, hw_test_timer_cb, NULL);
Я использовал и находил в примерах вот такое объявление обработчика аппаратного таймера:
hw_timer_set_func(hw_test_timer_cb);
В чем разница и какое правильное? По поиску не нашел ничего. Заранее спасибо!
ets_isr_attach() находится в ROM и всегда есть. А hw_timer_set_func() - это из какой-то либы.
И приведенный пример будет работать в любой среде - ему не нужно ничего кроме описания уже имеющегося в ESP8266.
 

pvvx

Активный участник сообщества
В примере задействуется только внешняя процедура вектора прерывания. Если оно вам нужно и более короткая по времени исполнения, то есть тут:
В итоге для данного примера не нужно даже SDK. Нужен всего транслятор СИ в коды. :)
 

pvvx

Активный участник сообщества
Но не забывайте главного - описанные характеристики не будут обеспечены при работе совместно с WiFi.
с WiFi вы получите ужасный джиттер, и использование программного прерывания, пусть даже NMI, вам не поможет, т.к. реализация многих процедур в ROM разрешает прерывания и в любой момент может быть вызвана процедура драйвера WiFi, что повлечет за собой дичайший джиттер. А переписывать всё вам не даст закрытый код WiFi, т.е. проприетарщина от Espressif.
В итоге реализовать диммер на ESP8266 возможно только используя два чипа ESP8266 - один работает с WiFi, а другой диммером.
И учитывая кол-во глюков самого чипа и кода от Espressif - овчинка выделки не стоит.
Возьмите какой другой чип, а не это г...но.
 

Melandr

Member
И учитывая кол-во глюков самого чипа и кода от Espressif - овчинка выделки не стоит.
Возьмите какой другой чип, а не это г...но.
согласен с Вами на 100%. Попробовал, использую работу напрямую с регистрами сделать импульс 50 мкс. Так у меня спады импульса перемещаются на 10 мкс. Уже возникают мысли поставить ATmega8 для реализации диммера, а ESP использовать в роли вэб-сервера. Но хочу все-таки довести до реализации диммер на ESP, и посмотреть что получится. Хотел еще спросить, в Вашем примере для настройки пинов как вход и выход используется такая конструкция:
gpio_output_set(0, 0, (1 << GPIO_OUT), (1 << GPIO_IN));
GPIO_OUT - используем как выход
GPIO_IN - используем как вход.
А если стоит задача использовать еще один пин как вход, допустим GPIO_IN_1
То как правильно записать?
Так
gpio_output_set(0, 0, (1 << GPIO_OUT), (1 << GPIO_IN) || (1 << GPIO_IN_1));
 

pvvx

Активный участник сообщества
согласен с Вами на 100%. Попробовал, использую работу напрямую с регистрами сделать импульс 50 мкс. Так у меня спады импульса перемещаются на 10 мкс. Уже возникают мысли поставить ATmega8 для реализации диммера, а ESP использовать в роли вэб-сервера. Но хочу все-таки довести до реализации диммер на ESP, и посмотреть что получится. Хотел еще спросить, в Вашем примере для настройки пинов как вход и выход используется такая конструкция:
gpio_output_set(0, 0, (1 << GPIO_OUT), (1 << GPIO_IN));
GPIO_OUT - используем как выход
GPIO_IN - используем как вход.
А если стоит задача использовать еще один пин как вход, допустим GPIO_IN_1
То как правильно записать?
Так
gpio_output_set(0, 0, (1 << GPIO_OUT), (1 << GPIO_IN) || (1 << GPIO_IN_1));
Извините, но современный большой ящик-комп с полу-киловаттными чипами не может шевелить ножками быстрее чем 15 кГц на ядро. Запуск задачи-потока-приложения (переключение контекста и перераспределение ресурсов родителя к потомку в kernel) обслуживают не более 15 тысяч в сек (в среднем на сегмент используемых компов, не сильно устаревших). Если в задачах будете обрабатывать и передавать меж ними по одному байту то это и есть предельный средний трансфер у современных компов - к 15 килобайтам в сек.
 

Melandr

Member
Добрый день! чтобы не плодить новые темы, решил спросить в этой же. Вопрос касается hw_timer. Нашел интересный перевод из FAQ Espressif

Опорной для FRC1 является частота 80 МГц. Коэффициент деления (DIV) может быть сконфигурирован в 1, 16 и 256. Различные коэффициенты деления будут влиять на длительность каждого тика.
FRC1 считает вниз, при этом значение COUNT_VALUE с каждым тиком уменьшается на 1.
FRC1 можно сконфигурировать в режимах auto-feed-mode или non-auto-feed-mode. Auto-feed-mode: когда сработало прерывание, регистр COUNT_VALUE автоматически получит значение из FRC1_LOAD_VALUE, и начнет операцию декрементирования. Non-auto-feed-mode: когда сработает прерывание, регистр COUNT_VALUE будет установлен в максимальное значение 0x7fffff, и операция декремента продолжится.
Могут быть сконфигурированы прерывания FRC от источников FRC1 и NMI interrupt source. Прерывание NMI не может быть маскировано (запрещено) кодом CPU. Прерывание NMI имеет уровень прерывания LEVEL3 в системе прерываний ESP8266, в то время как другие прерывания имеют уровень LEVEL1. Прерывание NMI по приоритету преобладает на любыми другими прерываниями.
Замечание по поводу SDK HW_TIMER: коэффициент деления SDK равен 16, поэтому длительность каждого тика составляет 0.2 мкс. Параметр hw_timer_arm может быть сконфигурирован до микросекунд, с максимальным значением 1677000 мкс.

Вопрос вот в чем. Допустим я инициализировал таймер таким кодом
Код:
  hw_timer_init(FRC1_SOURCE, 0);
  hw_timer_set_func(onTimerISR);
Далее в обработчике внешнего прерывания по входу я постоянно обновляю значение переменной onTimerISR.
Вопрос состоит, как правильно отключить в собственном обработчике прерывание от hw_timer?
Объясню подробнее, как я вижу работу диммера на прерываниях
1. Объявляем два обработчика прерываний.
2. Первый обработчик внешнего прерывания по входу отслеживает переход сетевого напряжения через 0 и подготавливает hw_timer для формирования задержки открытия симистора в начале периода сетевого напряжения.
3. После срабатывания прерывания от hw_timer, проверяем на каком этапе мы находимся (формирование задержки включения симистора, формирование импульса открытия симистора, ожидание прерывания внешнего прерывания по входу), переводим выход управления симистора в высокий уровень (для формирования импульса открытия), и далее из обработчика мы должны запустить hw_timer с временем, необходимым для открытия симистора. Допустим 10-20 мкс.
4. При следующем вызове обработчика прерывания от hw_timer, проверяем что импульс открытия симистора уже был и теперь необходимо ожидать опять переход через "0". Для этого необходимо отключить прерывание от hw_timer. Как это правильно сделать? Задать заведомо больший интервал, чтобы гарантировано раньше пришло внешнее прерывание по входу и в нем уже изменить значение счетного регистра функцией hw_timer_set_func(onTimerISR);
 
Сверху Снизу