• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Решено Частотомер и WEB

nikolz

Well-known member
Добрый день!
столкнулся с такой проблемой на ESP8266.
Сделал частотомер. алгоритм простой - считаем прерывания по пину.
Максимальная частота 220 кгц.
Без WIFI работает.
при включении WIFI происходит соединение с AP после этого перезагрузка.
-----------------------------------
Проблема в том, как подружить WIFI с подсчетом частоты прерываний.
-----------------------
Если это делать последовательно, т е сначала посчитать частоту,
а потом включить WIFI,
то проблема с WEB.
Данные с ESP браузер запрашивает каждые 1-5 сек
и отключение WIFI на измерение приводит к зависанию браузера на компе(смартфоне)
-------------------------
Знаю, что вопрос сложный и мало надежды, что кто-то знает решение,
но Надежда умирает последней.
---------------
Всем спасибо
 

Сергей_Ф

Moderator
Команда форума
@nikolz у Вас автообновление на странице стоит на 5 секунд? Можно перед измерением поставить обновление на 10, 20 или 30 секунд - сколько надо на замер частоты. Дождаться запроса страницы с этим значением, отключиться и замерить, потом подключится и выдать новую страницу. Не пойдет?
 

tretyakov_sa

Moderator
Команда форума
На ардуино давно делал, там даже библиотека есть. До 8 мегаГерц мерил без проблем. Вот здесь я бы связал atmеga и ESP как это обычно пытаются сделать :)
 

pvvx

Активный участник сообщества
На данный вопрос уже не раз отвечал ранее.
Ищите сообщение, где описан максимум частоты аппаратных прерываний при сохранении работоспособности WiFi и прочего ПО. На память - это до 7 us при затратах на само обслуживание прерывания до 1 us. Если код обслуживания прерывания более и/или пауза между прерываниями меньше, то кранты китай-Espressif-драйверу WiFi или переполнение стека. Данные даны для web-свалки. Для LUA надо помножить минимальную паузу на 1000.
Для контроллера "прерываний по пину" у ESP от Espressif ужасный код. Всегда ведет к переполнению стека при дребезге. Правильно написать подтверждение прерывания для исключения повторного вызова и переполнения стека программеры Espressif не смогли.
 

pvvx

Активный участник сообщества
Спасибо за ответ.
Я пишу на СИ.
У меня код обслуживания прерывания - одна команда инкремент на ассемблере.
Каким образом? А где код подтверждения прерывания и новое назначение для следующего срабатывания "прерывания по пину" в контроллере портов? Там и сидит кака от программеров Espressif.

повторных вызовов нет, так как измерение частоты происходит точно до 240 кгц без WIFI.
Как это нет? Если дребезг на входе, а код прерывания от Espressif разрешает следующее прерывание до завершения выхода и восстановления регистров из стека(!). На пару вхождений стека хватит (но не в LUA - там он и так затирает данные ROM-BIOS где как раз сидят конфиги потров :) и он тут-же доберется до чего совсем критичного), если вы свою часть описали правильно - с возможностью повторного вхождения.
Пример - был запрет прерываний на N миллисекунд (обычное явление в SDK Espressif), за его время ногу дернули сотню раз с 125 кГц, то по разрешению прерываний проц влетит в ваш вектор обработки и если тут-же придет другое аппаратное прерывание - вот оно и повторное. :p
Т е 125 кгц (8 мкс) должно работать. Верно?
Где-то так, но зависит от версии SDK. В последних хуже, особенно если NMI.
Я думаю, что программеры из Espressif не знают как назначить приоритет прерываний и как описывать прочие переключения, связанные с запретами прерываний и атомарностью при некоторых изменениях данных в их процедурах... Система и крушиться от любого чиха... По этому они и давят на RTOS - там для этого есть процедуры по умолчанию, написанные другими и только их они и могут пользовать. Но на RTOS у ESP8266 не хватает ресурсов.
Так что боритесь - всю Espressif SDK всё равно не перепишите. Проще выкинуть ESP.
 
Последнее редактирование:

Юрий Ботов

Moderator
Команда форума
Просто для справки. Если нужна бОльшая точность то проще использовать stm8 а не avr-ки. У stm8 можно аппаратно каскадировать пару 16 разрядных таймеров в один 32 разрядный. Но я понимаю что тиньки - это нечто привычное, а stm8 - весч в себе.
 

pvvx

Активный участник сообщества
Просто для справки. Если нужна бОльшая точность то проще использовать stm8 а не avr-ки. У stm8 можно аппаратно каскадировать пару 16 разрядных таймеров в один 32 разрядный. Но я понимаю что тиньки - это нечто привычное, а stm8 - весч в себе.
Счас в любом MCU есть 32-х битный таймер. На дворе не 2000-ые... Уж десяток лет прошло...
Антиквариат, типа stm8, давно стал дороже чего либо с ядром на 100 MHz.
На RTL871x пока не копал как он там мультиплексируется на GPIO, но GATE таймера переключается на I/O порты... И даже смысла в этом не вижу. Все датчики теперь выпускаются со встроенными ADC и с разными интерфейсами. Оцифровывать что-то или определять частоту не требуется, т.к. с этим лучше справляется встроенный в чип датчика ADC. Там, в его нутре, меньше помех, чем тащить проводами куда-то... И это дешевле. Nikolz у нас почетный некромансер... :)
 
Последнее редактирование:

view24

Member
У Вас целая секунда на измерение частоты. Если по прерываниям не проходит, то можно путем опроса пина с использованием вероятностного подхода.
 

pvvx

Активный участник сообщества
У Вас целая секунда на измерение частоты. Если по прерываниям не проходит, то можно путем опроса пина с использованием вероятностного подхода.
Секунды нет, если не разрывать связь WiFi. Связь с AP в стандарте WiFi устанавливается от 2-х до 5 секунд, в зависимости от роутера и установок соединения. Если глушили (отключили) WiFi, то гарантированно связаться получится условно раз в десяток секунд, с паузой отключения для измерения. Все остальные варианты приведут к глушилке местных сетей WiFi, из-за действий в эфире не по стандарту. Станция при связи должна просканировать эфир, найти свою AP, синхронизоваться с её beacon, по умолчанию посылаемый 10 раз в сек, произвести регистрацию на AP, получить IP, передать данные, произвести отключение от AP по протоколу. На это у стандартных бытовых роутеров и уходит не менее 3-х секунд.
Просто включиться и орать в эфир когда захочется по принципу диктуемому в доп. нестандартных протоколах от Espressif - это значит глушить другие местные соединения WiFi.
Тут проще сразу переписать ПО на ESP8266 на такой вариант: WiFi jammer - YouTube

Если увеличить время следования beacon на роутере, то можно получить увеличенную паузу между ними, объявить станцией что мы спим (пропускаем до 3-х beacon, типа DTIM3). В таком варианте сеть у этого роутера становится "тормозом", но если он служит только для этого соединения, тогда - плевать. Тут главное от станции точно вычислять время между приемами beacon, не терять их. Иначе у станции будут задержки в передаче до приема следующего beacon, определяющего арбитраж.

============
“Вероятностный подход” на ESP8266 будет слишком вероятностным. Любая система, работающая с другой, внешней, должна успевать обслуживать внешние события. В данном случае – это WiFi связь. Т.е. между внешними событиями система должна успеть обработать задачу по ним. Если код написан оптимально, то его время исполнения мало. В случае с SDK Espressif это не так.

Например, имеем, что для поддержания связи по WiFi, пусть за время следования becon (100.24 мс), надо исполнять код в 2 000 000 тактов CPU. За секунду это 20 000 000 тактов (20 МГц). Пусть прерывание по пину отнимает 500 тактов. При штатных 80 МГц CPU имеется всего 80 000 000 тактов. Отнимаем 80 000 000 - 20 000 000 = 60 000 000 свободных. Делим на 500 тактов прерывания – получаем предел в 120 000 Гц. Если более – система рухнет. (Данные взяты с потолка, примерно для моего обрезанного SDK в Web-свалке, для стандартного SDK Espressif они хуже, в Arduino ещё значительно хуже, в LUA, с сиcтемой получения каждого байта данных из Flash по прерыванию защиты - вообще не влезают во время необходимого исполнения роли заявленной поддержки WiFi...)

Это если по прерываниям. Тут вычислять ничего не требуется, кроме деления накопленных за время прерываний и формирования пакета передачи (что тоже требует времени и надо вычесть из общего – это ещё уменьшит максимум частоты прерываний).

По “Вероятностному подходу” вам потребуется переписать всю систему SDK на исполнение в другом треде или по прерываниям, которые будут прерывать ваш цикл опроса. Но, в данном случае у нас не RTOS, приоритеты задач не выставляются и система SDK Espressif не рассчитана на такую работу. Значит вам придется выделять системе время самому, в своем цикле и описать сложную и большую по времени обработки процедуру расчета вероятностей, исполняемую всегда и как можно непрерывнее. Это, обычно, отнимает большее кол-во тактов, чем система работы по прерываниям с целочисленными вычислениями. При вероятностном обязательно потребуются сложные расчеты с плавающей точкой, на что уйдут все "свободные" такты CPU. Как итог всего этого – ужасная выходная точность. Это нормально только для "научного предприятия" :)

При использовании RTOS системе требуются дополнительные такты на обслуживание. Проверить минимум можно простым понижением частоты CPU. К примеру, на RTL871x система связи с WiFi и RTOS с тиком в 1 мс работоспособна и на 4 МГц, при этом ещё как-то обслуживает передачу файлов и прочее через TCP стек LwIP. Выходит, что для его текущего кода и сохранения работоспособности необходим минимум в 4 000 000 тактов в секунду. При максимуме CPU в 200 МГц - это всего 2%. С этого далее можно посчитать и минимальное потребление… (уже давно известно, что оно во много раз менее чем у ESP8266 :)). Если увеличить тик системы RTOS, то получим ещё меньше... Но тут палка о двух концах - будет страдать время реакции... По этому, для связи с WiFi применяют другую политику для уменьшения потребления - спят в паузах между beacon, накапливая стек задач, а во время окна приема beacon включают CPU на максимум CLK и исполняют накопленные задачи, затем опять засыпают до следующего beacon. При этом во время "сна" отключается всё по выбору. Можно например оставить работать CPU на 4 МГц для счета внешних событий, или активными некоторые прерывания. А вот ESP не имеет распределений что и как глушить на время "сна" между beacon... Как итог - никакой гибкости системы в ESP нет и пути уменьшения потребления в ней имеются только с отключением всего и потерей синхронизации любых таймеров и других внутренних устройств.

Все проблемы у ESP чисто программные. Espressif имеет закрытый код SDK, рассчитанный только на одну задачу - их пример IoT со связью с их сервером раз в час по его протоколу с передачей пару данных и исправить эту ситуацию вам не удастся. Всё написанное на него "сообществом" сделано вопреки и в виде дополнительной "нашлепки" увеличивающей время исполнения и общее время реакции системы. Т.е. все они уродские и не представляют никакого интереса для дальнейшего развития направления IoT в целом. Аналогично и с ESP-32S.
 
Последнее редактирование:

pvvx

Активный участник сообщества
Как выяснилось , проблема в том, что возникает иногда зависание ESP при исполнении команды отключения пина.
Т е для работы WIFI я отключаю пин
gpio_intr_init(pinH2,0);
а для измерения включаю
gpio_intr_init(pinH2,GPIO_PIN_INTR_NEGEDGE);
Так вот при отключении ESP иногда зависает после чего рестартует.

Как устанить зависание пока не решил.

eSP вмснет
В моем случае про
Может виснуть обращение к процедурам ROM-BIOS (это процедуры с GPIO), если стек залез в переменные ROM-BIOS. Они там рядом к его концу :)
За глубиной стека в ESP никто не следит и все программы от "сообщества" переполняют допустимый раздел стека.
при этом в колбеке всего одна команда на ассемблере.
Ну это только "калбек", а куча кода подтверждения прерывания и зарядки нового для GPIO где-то в другом месте :)
 
Последнее редактирование:

pvvx

Активный участник сообщества
Если бы это был стек то зависания были бы примерно на одном и том же по счету обращению браузера к ESP
А получается может на 22 -ом зависнуть,
а может и на 4-ом.
Как раз зависнет тогда, когда он будет писать в свой стек :) Ещё надо попасть в сохранение адреса процедуры выхода...
Ну детсад что-ли? Пример: cтек переписал таблицу GPIO для ROM-BIOS. Ну и всем пофигу. Уехал дальше, а тут вызов процедуры, которая пишет в его возвраты... Если попадет куда надо, то проц потом улетит :) А смена данных - это мелкие глюки..
 

pvvx

Активный участник сообщества
Есть способ это проверить или избежать?
Записать всю область стека каким-то ID типа 0xDEAD, в самых глубоких вложениях сделать проверку чтения адреса стека, а в каком-то цикле следить за записанными значениями ID в конце стека. Допустимый адрес стека (область) указана только в web-свалке, в *.ld файле.
LUA и HTTPD на 100% уходит глубже, в переменные ROM-BIOS.
Их писатели считают, что массив на килобайт в стеке - это норма для каждой процедуры :)
Пробуйте включить CLK CPU на 160 МГц - будет меньше вложений по прерыванию I/O - вдруг успеет отработать 240 кГц :)
 
Последнее редактирование:

nikolz

Well-known member
Записать всю область стека каким-то ID типа 0xDEAD, в самых глубоких вложениях сделать проверку чтения адреса стека, а в каком-то цикле следить за записанными значениями ID в конце стека. Допустимый адрес стека (область) указана только в web-свалке, в *.ld файле.
LUA и HTTPD на 100% уходит глубже, в переменные ROM-BIOS.
Их писатели считают, что массив на килобайт в стеке - это норма для каждой процедуры :)
Спасибо, у меня СИ попробую проверить
 

pvvx

Активный участник сообщества
Те времена, что описаны - это для процедуры прерывания от таймера. Она корректная - там всего 2 ввода-вывода на шину регистров. Шина -то тормоз на 26 МГц и ещё с FIFO. Итого там 16 тактов на чтение-запись любого регистра периферии проца при 160 МГц.
А в процедуре обработки прерывания от GPIO - там к десятку обращений к регистрам аппаратуры. Совместно с сохранением-восстановлением регистров CPU и другим процедурам оно значительно длиннее в тактах от прерывания таймера... И т.к. подтверждение прерывания там писано не правильно, то она имеет повторность вхождения, которые вызывают увеличение глубины стека... Убрать это можно, если полностью переписать обработчик прерывания от GPIO.

esp8266web/eagle.rom.addr.v6.ld at master · pvvx/esp8266web · GitHub
В варианте RTOS SDK все процедуры из ROM-BIOS исключены и дублируются в Flash и IRAM с переменными в другой области (rodata, bss, .. самого SDK) . Стек там для каждой задачи распределяет RTOS.
 
Последнее редактирование:

nikolz

Well-known member
Те времена, что описаны - это для процедуры прерывания от таймера. Она корректная - там всего 2 ввода-вывода на шину регистров. Шина -то тормоз на 26 МГц и ещё с FIFO. Итого там 16 тактов на чтение-запись любого регистра периферии проца при 160 МГц.
А в процедуре обработки прерывания от GPIO - там к десятку обращений к регистрам аппаратуры. Совместно с сохранением-восстановлением регистров CPU и другим процедурам оно значительно длиннее в тактах от прерывания таймера... И т.к. подтверждение прерывания там писано не правильно, то она имеет повторность вхождения, которые вызывают увеличение глубины стека... Убрать это можно, если полностью переписать обработчик прерывания от GPIO.

esp8266web/eagle.rom.addr.v6.ld at master · pvvx/esp8266web · GitHub
В варианте RTOS SDK все процедуры из ROM-BIOS исключены и дублируются в Flash и IRAM с переменными в другой области (rodata, bss, .. самого SDK) . Стек там для каждой задачи распределяет RTOS.
Спасибо за инфу
Но меня смущают два факта.
1) рестарт происходит при исполнении этого:
pin_int_type[pin] = GPIO_PIN_INTR_DISABLE;
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin_num[pin]));
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]),GPIO_PIN_INTR_DISABLE);
Т е я сбрасываю маску для пина.
Почему при этом возможно переполнение стека?
------------------------------------
2) При этом рестарт происходит не сразу (полагаю сразу было бы при переполнении стека) а по срабатыванию WDT ( REANSON_WDT_RST = 1, // hardware watch dog reset)
-------------------------
 

pvvx

Активный участник сообщества
Спасибо за инфу
Но меня смущают два факта.
1) рестарт происходит при исполнении этого:
pin_int_type[pin] = GPIO_PIN_INTR_DISABLE;
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin_num[pin]));
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]),GPIO_PIN_INTR_DISABLE);
Т е я сбрасываю маску для пина.
Почему при этом возможно переполнение стека?
------------------------------------
2) При этом рестарт происходит не сразу (полагаю сразу было бы при переполнении стека) а по срабатыванию WDT ( REANSON_WDT_RST = 1, // hardware watch dog reset)
-------------------------
А варианта тогда два:
Вечное прерывание - другого времени проц не отдает системе, а занят вечным входом-выходом в прерывание, т.к. не может его сбросить в аппаратуре или так его вы настроили. Например на уровень пина нуль на входе всегда нуль. :)
Другой вариант - при исполнении gpio_pin_intr_state_set() происходит прерывание и тоже лезет в регистры - итог работы = неизвестен. Обычное нарушение атомарности - считали регистр, прерывание изменило его значение, вернулось в программу и там записали старое значение :)
Поставьте запрет прерываний при изменении установок, влияющих на конфигурацию оборудования прерывания по I/O в своем коде...
Переполнение стека тоже возможно... но это надо вникать в ваш код и код внутренних процедур от Espressif, что делать на ESP я уже не буду - разработка на нем закрыта и это пустая трата времени, т.к. есть альтернатива с полной заменой, но работающая и годящаяся для промышленного применения.
 
Последнее редактирование:

nikolz

Well-known member
А варианта тогда два:
Вечное прерывание - другого времени проц не отдает системе, а занят вечным входом-выходом в прерывание, т.к. не может его сбросить в аппаратуре или так его вы настроили. Например на уровень пина нуль на входе всегда нуль. :)
Другой вариант - при исполнении gpio_pin_intr_state_set() происходит прерывание и тоже лезет в регистры - итог работы = неизвестен. Обычное нарушение атомарности - считали регистр, прерывание изменило его значение, вернулось в программу и там записали старое значение :)
Поставьте запрет прерываний при изменении установок, влияющих на конфигурацию оборудования прерывания по I/O в своем коде...
Переполнение стека тоже возможно... но это надо вникать в ваш код и код внутренних процедур от Espressif, что делать на ESP я уже не буду - разработка на нем закрыта и это пустая трата времени.
Данную операцию я делаю после запрета прерываний в колбеке таймера. Таймер без автозагрузки. Таймер не запущен.
пин работает по фронту.
WIFI при этом выключен.
 

pvvx

Активный участник сообщества
Вот вам пример из LUA:
Код:
      ETS_GPIO_INTR_DISABLE();
#ifdef GPIO_INTERRUPT_ENABLE
      pin_int_type[pin] = GPIO_PIN_INTR_DISABLE;
#endif
      PIN_FUNC_SELECT(pin_mux[pin], pin_func[pin]);
      //disable interrupt
      gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]), GPIO_PIN_INTR_DISABLE);
      //clear interrupt status
      GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin_num[pin]));
      GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[pin])), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[pin]))) & (~ GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE))); //disable open drain;
      ETS_GPIO_INTR_ENABLE();
Но в коде gpio_pin_intr_state_set() есть такое:
Код:
00004d90 <gpio_pin_intr_state_set>:
    4d90:    f0c112           addi    a1, a1, -16
    4d93:    006122           s32i    a2, a1, 0
    4d96:    016132           s32i    a3, a1, 4
    4d99:    026102           s32i    a0, a1, 8
    4d9c:    fc1d45           call0    f74 <ets_intr_lock>
    4d9f:    f08931           l32r    a3, fc4 <ets_set_user_start+0x8> // 0x60000200
    4da2:    0128         l32i.n    a2, a1, 0
    4da4:    a02230           addx4    a2, a2, a3
    4da7:    0020c0           memw
    4daa:    7fac42           movi    a4, 0xfffffc7f
    4dad:    1138         l32i.n    a3, a1, 4
    4daf:    4a2202           l32i    a0, a2, 0x128
    4db2:    113390           slli    a3, a3, 7
    4db5:    100040           and    a0, a0, a4
    4db8:    200030           or    a0, a0, a3
    4dbb:    0020c0           memw
    4dbe:    4a6202           s32i    a0, a2, 0x128
    4dc1:    fc1bc5           call0    f80 <ets_intr_unlock> <-------- разрешение прерываний :)
    4dc4:    2108         l32i.n    a0, a1, 8
    4dc6:    10c112           addi    a1, a1, 16
    4dc9:    f00d         ret.n
Когда пытался сделать счетчик фронтов, то ничего не вышло - вечное повторное срабатывание из-за разрешения прерываний где не попадя в коде Espressif. Просто забил, т.к. переписать всё - время на это тратить нет желания. Поставил не счетчик, а флаг, т.к. считать он не умеет при дребезге и без с переключениями то по положительному, то по отрицательному фронту... Слишком громоздкий код выходит. Пока определите по какому фронту и по какого пина, уже будет другое прерывание, а надо ещё его переназначить или даже просто зарядить на новое исполнение и всё это в прерывании ...:) При этом доков на оборудование - нет.
 
Последнее редактирование:
Сверху Снизу