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

Таймеры

ART_HA

Member
Замена 1000 на 100 в Ticker.cpp дала прекрасный результат. (y)
Но когда я попытался выкрутиться путем включения измененного мною Ticker.cpp в каталог с исходником с соответствующим #include "Ticker.cpp" я получил ошибку компилятора, хотя вроде как такое должно бы работать. Или все-такое вообще нельзя делать?
 

aZholtikov

Active member
Замена 1000 на 100 в Ticker.cpp дала прекрасный результат. (y)
Но когда я попытался выкрутиться путем включения измененного мною Ticker.cpp в каталог с исходником с соответствующим #include "Ticker.cpp" я получил ошибку компилятора, хотя вроде как такое должно бы работать. Или все-такое вообще нельзя делать?
Вызывает ошибку #include "Ticker.cpp". Нужно #include "Ticker.h".
 

ART_HA

Member
А как я тогда подставлю измененный файл без вмешательства в APPDATA?
Мне же нужно как то указать, где он находится.
Ошибку дает вот такую:
exit status 1
Ошибка компиляции для платы NodeMCU-32S.

PS. Ба! Так Ticker.h и Ticker.cpp это на Си++ точно такая же пара, как Ticker.h и Ticker.c на Си?
 

aZholtikov

Active member
А как я тогда подставлю измененный файл без вмешательства в APPDATA?
Мне же нужно как то указать, где он находится.
Создаем в папке lib (или где там Arduino IDE библиотеки держит) папку ART_HA_Ticket (например). Копируем в нее Ticker.h и Ticker.cpp. Переименовываем в ART_HA_Ticker.h и ART_HA_Ticker.cpp (например). Правим их как надо (меняем код + как минимум в ART_HA_Ticker.cpp изменяем #include "Ticker.h" на #include "ART_HA_Ticker.h").
В программе изменяем #include "Ticker.h" на #include "ART_HA_Ticker.h".
Фсё.
 

ART_HA

Member
Вы правы, примерно это я сейчас и пытаюсь сделать. Только я не хочу включать в библиотеку, а просто хочу приложить пару исправленных файлов в каталог с исходником.
 

ART_HA

Member
Как ни странно, всё получилось. Сделал отсчеты таймера по 10 мкс. Работает уверенно. :)
 

ART_HA

Member
Создаем в папке
Появилась небольшая проблема.
У меня сейчас аппаратным прерыванием №1 запускается однократный таймер, который после истечения заданного времени запускает прерывание №2, которое снова запускает этот таймер на другое заданное время, по истечении которого прерыванием №3 заканчивается вся операция, вызванная аппаратным прерыванием №1.
Но из-за не очень высокой стабильности частоты запуска аппаратного прерывания №1 существует риск, что это прерывание произойдет во время исполнения обработчика прерывания №2 или №3. Насколько я понимаю, аппаратное прерывание №1 приоритетнее программных №2 и №3, но недопустимо, чтобы после исполнения вызванной им цепочки прерываний, программа вернулась в обработчик прерванного им прерывания №2 или №3.
Существует ли в ESP32 возможность сброса возможного хода исполнения прерываний №2 и №3 аппаратным прерыванием №1?
 

aZholtikov

Active member
Существует ли в ESP32 возможность сброса возможного хода исполнения прерываний №2 и №3 аппаратным прерыванием №1?
Вопрос интересный... Надо посмотреть...
Но как я раньше говорил - "баловство" с таймерами больше подходит для ESP8266. Для ESP32 намного лучше (ИМХО) использовать FreeRTOS.
 

pvvx

Активный участник сообщества
Как ни странно, всё получилось. Сделал отсчеты таймера по 10 мкс. Работает уверенно. :)
Если в это время выполняется delay(N); и не работает WiFi.
Существует ли в ESP32 возможность сброса возможного хода исполнения прерываний №2 и №3 аппаратным прерыванием №1?
Возможно всё, т.к. прерывания программные, вызывающиеся по таблице от одного таймера в отдельном цикле опроса событий. которому надо отдавать управление.
Но сделать это можно только как через ... гланды... - Перегружать регистры CPU из стека...
В Arduino обработка программных таймеров наверняка вынесена в загружаемую часть кода - процедура из ROM не используется. Но они аналогичны + мелкие поправки. Там и покопайтесь.
 

pvvx

Активный участник сообщества
Если prescaler таймера установлен на 16, тогда пределы работы таймера 0.2..1677721.4 us. Максимальный делитель у таймера 0x007fffff.
Т.е. один шаг = 0.2 us.
Менее 2us при 160MHz CPU - перегрузка системы по WDT.
Код:
#define XS_TO_RTC_TIMER_TICKS(t, prescaler, period)    \
     (((t) > (0xFFFFFFFF/(APB_CLK_FREQ >> prescaler))) ?    \
      (((t) >> 2) * ((APB_CLK_FREQ >> prescaler)/(period>>2)) + ((t) & 0x3) * ((APB_CLK_FREQ >> prescaler)/period))  :    \
      (((t) * (APB_CLK_FREQ >> prescaler)) / period))

#if ((APB_CLK_FREQ>>4)%1000000)
     TIMERx_LOAD = XS_TO_RTC_TIMER_TICKS(us, 4, 1000000);
#else
     TIMERx_LOAD = us * (APB_CLK_FREQ>>4)/1000000; // = us * 5
#endif
APB_CLK_FREQ = 80000000
 

ART_HA

Member
Если в это время выполняется delay(N); и не работает WiFi.
WiFi в этом режиме не запускается, а delay(N) в программе нет вообще.
К таймеру претензий нет.
Есть претензии к тому, что у таймера ESP32 нет аппаратного выхода, поэтому его приходится обеспечивать через прерывание по таймеру, отсюда и проблема.
 

pvvx

Активный участник сообщества
Есть претензии к тому, что у таймера ESP32 нет аппаратного выхода, поэтому его приходится обеспечивать через прерывание по таймеру, отсюда и проблема.
Как вы писали проблема в приоритетах у ваших таймеров.
И задержки у вас большие - десятки мс?
Почему вы не можете создать хоть десять программных таймеров, а используете NMI?
Из 2016 года:
ets_timer_arm_new - это управление программным таймером на основе аппаратного. _new по причине что у аппаратного таймера переключают делитель на счет в us. У ROM-BIOS ets_timer_arm() и расчет идет на другой делитель в аппаратном таймере.
Процедуры ets_timer_arm добавляют в связный список новый программный таймер и вычисляет задержку до срабатывания следующего программного таймера и записывают её в регистр счета аппаратного таймера. Когда будет работать процедура ets_run(), то она определит срабатывание alarm у аппаратного таймера и вызовет код вашего программного таймера... Это упрощенно.
 

pvvx

Активный участник сообщества
Назначенный код программных таймеров (ets_timer_setfn()) выполняется последовательно. И если какие-то проблемы - всегда можно временно отменить любые другие прерывания (ets_intr_lock(), ets_intr_unlock()).
Процедура любого программного таймера может отменить выполнение другого - ets_timer_disarm().
Как переназначено название функций и параметров к ним в Arduino - это ищите сами. Они базовые, т.к. имеют часть кода в ROM чипа.
 

ART_HA

Member
Мне не нужно отменять аппаратное или программное прерывания, мне нужно аппаратным прерыванием аварийно закончить работу обработчика программного прерывания. А еще лучше и обработчика самого себя тоже. :)
 

pvvx

Активный участник сообщества
Мне не нужно отменять аппаратное или программное прерывания, мне нужно аппаратным прерыванием аварийно закончить работу обработчика программного прерывания. А еще лучше и обработчика самого себя тоже. :)
Оно и есть -> ets_timer_disarm(x) останавливает назначенный x софт-таймер и запрещает вызов его кода.
А в параметрах запуска ets_timer_arm[_new](x, период, тип) - тип задает однократное или постоянное срабатывание.
И ваши вопросы и проблемы не понятны. Сами себя путаете используя NMI прерывание и какие-то кривые Arduino таймеры.
PS: когда-то, 2016г, на этих таймерах делал управление переключением направления ModBus RS-485 и вычислением задержек - всё Ok. Беда только с WiFi драйверами, запрещающими все прерывания на долгий срок. Но это происходит не часто...
 

pvvx

Активный участник сообщества
И уж если используете NMI прерывание - то для ESP8266 оно должно выполняться не более 1 us. Иначе происходит нарушение таймингов WiFi. Это потом даже описано в документации...
А в Arduino вы не можете обеспечить такое исполнение из-за C++ и прочих бяк.
 

pvvx

Активный участник сообщества
Короче - вы выбрали плохой алгоритм работы и даже не описали его. B итоге мучаетесь с Arduino.
Имеющиеся в системе ESP8266 софт-таймеры позволяют выводить на GPIO любые сигналы со средним джиттером в 150 us из-за работы WiFi, если подработать его дрова.
 

ART_HA

Member
Для понимая приведу упрощенный пример.
На вход аппаратного прерывания ESP32 подаются короткие импульсы частотой 1 кГц, в ответ на которые ESP32 вырабатывает импульс заданной длительности, например 0,75 мсек.
Это называется одновибратор.
И тут случается проблема: в серии поступающих импульсов появляется периодическая помеха частотой 2 кГц.
Что произойдет в этом случае с нашим ESP32?
 

ART_HA

Member
Вопрос интересный... Надо посмотреть...
Есть идея при поступлении сигнала на вход аппаратного прерывания запускать еще один таймер - для контроля периода входных импульсов.
Но как остановить работу первого прерывания при обнаружении недопустимого повышения частоты входящих сигналов?
 
Сверху Снизу