ESP32 Различное время вызова прерывания

На вход 27 ESP32 подаю импульсы частотой 9 Гц. Решил померить сколько тактов процессора составляет длительность этих импульсов. Запустил программу и она почти всегда замеряет правильно.

unsigned long     Fref = 40; //Частота работы процессора (240,160,80,40) мГц.                         //
const    int      interruptPin = 27; // GPIO pin where the interrupt will be configured               //
volatile bool     start_gate=1;                                                                       //
volatile uint32_t c1_new,c1_old;                                                                      //
volatile uint64_t tik,led;                                                                            //
volatile uint64_t N=0,n1=0,s1=0;                                                                      //
volatile uint64_t c2,M1,M2;                                                                           //
//----------------------------------------------------------------------------------------------------//
void IRAM_ATTR buttonTick()                                                                           //
{                                                                                                     //
   c1_new = esp_cpu_get_cycle_count();                                                                //
   c2     = c2+c1_new-c1_old;                                                                         //
   if (c1_new<c1_old) c2=c2+4294967296;                                                               //
   c1_old=c1_new;                                                                                     //
   N=N+1;                                                                                             //
   if (start_gate==1    ) {M2=c2;N=0;start_gate=0;}                                                   //
   if ((c2-M2)>=40000000) {n1=N;s1=c2-M2;N=0;start_gate=1;}                                           //
}                                                                                                     //
//----------------------------------------------------------------------------------------------------//
void setup()                                                                                          //
{                                                                                                     //
  setCpuFrequencyMhz(Fref);                                                                           //
  Serial.begin(115200);                                                                               //
  pinMode(interruptPin, INPUT); // Configure the pin as an input with an internal pull-up resistor    //
  attachInterrupt(interruptPin, buttonTick, RISING); // Configure the interrup                        //
}                                                                                                     //
//----------------------------------------------------------------------------------------------------//
void loop()                                                                                           //
{                                                                                                     //
  //---Начало режима индикации------------------------------------------------------------------------//
  tik = esp_timer_get_time(); //количество микросекунд с момента запуска базового таймера             //
   Serial.print(" N= ");Serial.print(n1);Serial.print(" Q= ");Serial.println(s1);                     //
   delay(1000);                                                                                       //
  //---Конец режима индикации-------------------------------------------------------------------------//
}                                                                                                     //

Вот данные монитора порта. Последняя цифра почти не меняется. Но есть скачки в несколько сотен.

 N= 10 Q= 44442630
 N= 10 Q= 44442630
 N= 10 Q= 44442629
 N= 10 Q= 44442629
 N= 10 Q= 44442629
 N= 10 Q= 44442031
 N= 10 Q= 44442031
 N= 10 Q= 44442587
 N= 10 Q= 44442630
 N= 10 Q= 44442629
 N= 10 Q= 44442630
 N= 10 Q= 44442629
 N= 10 Q= 44442629

Немного изменим условия Loop вывода на экран. Строка 28 и ниже.

unsigned long     Fref = 40; //Частота работы процессора (240,160,80,40) мГц.                         //
const    int      interruptPin = 27; // GPIO pin where the interrupt will be configured               //
volatile bool     start_gate=1;                                                                       //
volatile uint32_t c1_new,c1_old;                                                                      //
volatile uint64_t tik,led;                                                                            //
volatile uint64_t N=0,n1=0,s1=0;                                                                      //
volatile uint64_t c2,M1,M2;                                                                           //
//----------------------------------------------------------------------------------------------------//
void IRAM_ATTR buttonTick()                                                                           //
{                                                                                                     //
   c1_new = esp_cpu_get_cycle_count();                                                                //
   c2     = c2+c1_new-c1_old;                                                                         //
   if (c1_new<c1_old) c2=c2+4294967296;                                                               //
   c1_old=c1_new;                                                                                     //
   N=N+1;                                                                                             //
   if (start_gate==1    ) {M2=c2;N=0;start_gate=0;}                                                   //
   if ((c2-M2)>=40000000) {n1=N;s1=c2-M2;N=0;start_gate=1;}                                           //
}                                                                                                     //
//----------------------------------------------------------------------------------------------------//
void setup()                                                                                          //
{                                                                                                     //
  setCpuFrequencyMhz(Fref);                                                                           //
  Serial.begin(115200);                                                                               //
  pinMode(interruptPin, INPUT); // Configure the pin as an input with an internal pull-up resistor    //
  attachInterrupt(interruptPin, buttonTick, RISING); // Configure the interrup                        //
}                                                                                                     //
//----------------------------------------------------------------------------------------------------//
void loop()                                                                                           //
{                                                                                                     //
  //---Начало режима индикации------------------------------------------------------------------------//
  tik = esp_timer_get_time(); //количество микросекунд с момента запуска базового таймера             //
  if ((tik-led)>=1000000)                                                                             //
  {                                                                                                   //
   Serial.print(" N= ");Serial.print(n1);Serial.print(" Q= ");Serial.println(s1);                     //
   led=tik;                                                                                           //
  }                                                                                                   //
  //---Конец режима индикации-------------------------------------------------------------------------//
}                                                                                                     //

Результат гораздо хуже.

 N= 10 Q= 44443013
 N= 10 Q= 44442627
 N= 10 Q= 44442109
 N= 10 Q= 44442899
 N= 10 Q= 44442647
 N= 10 Q= 44442292
 N= 10 Q= 44442292
 N= 10 Q= 44442582
 N= 10 Q= 44442301
 N= 10 Q= 44442719
 N= 10 Q= 44442667
 N= 10 Q= 44442667

Нашел пока только одну статью на эту тему.

Просьба помочь по данному вопросу. Надо убрать большое изменения количество тактов процессора во втором варианте программы.

Делей убрали, теперь менеджер РТОС будет чаще задвигать ваше прерывание на второй план

Пересадить таску на свободное ядро с повышенным приоритетом.

UPD: там ISR, оказывается. Тогда подожду практикующих есп-шников

По превышению уровня прерывания нашел несколько ссылок. Но не знаю что из этого можно применить в моем случае? Есть правда еще вариант это попробовать отключить те приложения, которые вызывают высокоуровневые прерывания. Например отключить
wifi или блютуз.

https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/hlinterrupts.html

последовательные периоды 9Гц сигнала чисто математически не могут занимать одинаковое количество тактов на ядре, работающем на частоте 80, 160 или 240 МГц (помоему там такие варианты в esp-idf менюконфиге). просто разделите то что больше на то что меньше и там будет дробное число, ибо сумма цифр не делится на 9. вспомните третий класс школы.
вторая причина - количество посчитанных тиков всегда будет целым.
третья причина - FreeRTOS не гарантирует одинаковое время выполнения и выделение одинаковых ресурсов одной и той же таске при ее итерациях.
ну и вдобавок, на мой личный взгляд, методика замера неверна. ИМХО замерять надо снаружи осциллоскопом со счетчиком импульсов +тестируемую нагрузку ни в коем случае не собирать в ардуино, юзать рекомендуемое решение от производителя чипа.

1.Интересно а почему не могут занимать одинаковое количество тактов? А речи про делении большого на меньшее вообще нет. И тем более там нет деления на 9.
2.Полностью согласен. У меня количество тактов процессора целое число.
3. Вот третью проблему и надо решить.
4. А чем неверна методика измерения? И как я понимаю осциллоскоп не позволяет измерить длительность импульса 0.1 секунды с точностью 4 нС. И где взять рекомендуемое решение от производителя чипа для измерении длительности событий?

  1. частота чипа 160 МГц. Частота период которой вы меряете - 9Гц. таким образом, за один период на частоте 9Гц пройдет нецелое количество тактов ядра: 160000000 / 9 = 17777777,(7).
  2. Далее, количество тактов процессора, которые он может посчитать, описываются переменной целочисленного типа, и таким образом не могут быть нецелым числом.
  3. решайте. сообщите как решите и ваш код появится в esp-idf.
  4. неверна тем, что средство измерения и объект измерения в данном случае одно и то же.
  5. рекомендованное решение - VS Code + ESP IDF Plugin.

едит: судя по вашим результатам, ваш чип работает на частоте 400 МГц ( 44442630 * 9)

эта цифра суммарная за 10 циклов

40МГц? 80? как вы думаете поцчему такое значение и в чем бок у товарища?

он вроде хочет 40 МГц

обратил внимание, что он печатает число циклов

тогда цифры 40МГц, 9 Гц и 44442629 вполне бьются между собой

1 лайк

Ну, так а ответ где? Вопрос то у меня простой. Как сделать так, чтобы цифры результата Q менялись не более 1-2 единиц. А сейчас они меняются на 300 единиц тактов процессора.

в стране Оз.

  1. Частота чипа 40 мГц. Вы в коде где нибудь увидели деление 40000000 на 9? И я не измеряю частоту периода, я считаю сумму тактов процессора.
  2. Решение я жду от вас. Как я могу вам сообщить решение с кодом если это я задаю в качестве вопроса.
  3. И где это решение взять? Куда строки “VS Code + ESP IDF Plugin” вставить в программу?

Ну а зачем тогда столько писали если решение в стране Оз. Вы, как я понимаю наверное из России.

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

не надо только меня за это осуждать)

сумма десяти проходов на системе с РТОС воспроизводилась с точностью до 1-2 тактов контроллера? - фантастика, по-моему

Напомните, в какой задаче это вам нужно?

1 лайк
  1. Аддон для аруино построен на idf, те моменты, которые не реализованы в аддоне - это очень “глубинные” вещи, никак не касающиеся задачи.
  2. При измерении 9 Гц на ЛЮБОМ устройстве, даже самом фантастически идеальном, длина периода будет плавать. На сколько? - зависит от генератора. Фронт импульса размазывается даже просто на линии передачи, да сам фронт по стабильности какой? Например при генерировании меандра на дешевом ОУ LM358 длина фронта около 10 мкс. Чтобы обеспечить крутой фронт на “несколько тактов процессора” нужен фронт в 25-50 нс. Удачи в создании генератора.
  3. Так что перестаньте чушь нести. Автору следует сформулировать цель. Возможно ему нужно среднее, или он наоборот - изучает отклонение генератора. Всё это считается.
1 лайк
  1. На сколько будет плавать. Вот вам любимый Datasheet. На 1 странице смотрим. Правда там по английски - будем считать джитер обещают 0.07 нсек. Время нарастания максимальное 1.5 нсек. Уже все создано до нас.
  2. Цель простая посчитать сколько тактов процессора по длительности будет пачка из 10 импульсов с частотой 9 Гц. С точностью до 1 такта процессора. Поскольку генератор выдает импульс с длительностью фронта 1.5 нсек.

https://docs.yandex.ru/docs/view?tm=1727793862&tld=ru&lang=en&name=Si5351-datasheet.pdf&text=si5351%20datasheet&url=https%3A%2F%2Fdownload.mikroe.com%2Fdocuments%2Fdatasheets%2FSi5351-datasheet.pdf&lr=972&mime=pdf&l10n=ru&sign=d06fd3574a656db377e644bf17382281&keyno=0&serpParams=tm%3D1727793862%26tld%3Dru%26lang%3Den%26name%3DSi5351-datasheet.pdf%26text%3Dsi5351%2Bdatasheet%26url%3Dhttps%253A%2F%2Fdownload.mikroe.com%2Fdocuments%2Fdatasheets%2FSi5351-datasheet.pdf%26lr%3D972%26mime%3Dpdf%26l10n%3Dru%26sign%3Dd06fd3574a656db377e644bf17382281%26keyno%3D0

это не цель
@Buldakov может все-таки поясните, зачем это надо?
А то ситуация характерная складывается, печально знакомая большинству из долгожителей - новичок, который только вчера с трудом с помощью форума запустил простейший счетчик - сегодня заявляет о необходимости измерения интервалов с наносекундной точностью.
В таких случаях почти всегда оказывается, что ничего подобного новичку не нужно было…

Вы же, вроде, железячник? Вспомните правило - если схема требует выдерживать номиналы элементов с точностью в доли процента - это плохая схема.

Так что обрисуйте РЕАЛЬНУЮ ПРОБЛЕМУ, может вам подскажут, как ее решать адекватно, без необходмости ловить такты процессора.

ЗЫ
ЕСП32 - обязательно? Из-за наличия неубираемого РТОС и радиоблока на втором ядре это далеко не лучший выбор для точных измерений.

  1. Посчитать 10 импульсов это цель данной темы.
  2. Или мне сразу спрашивать как мне сделать готовый проект того что я хочу.
  3. Пишу в разделе для новичков, чтобы не захламлять тему программирования. И кстати данный форум только недавно создан (года 2 назад) поэтому все на этом форуме новички.
  4. По поводу долей процентов в схеме. Всегда есть исключения: например аналоговая вычислительная машина или хроматограф или параллельный ЦАП или АЦП. Для получения 16 битного ЦАП необходимо резисторы с точностью лучше 0.01%. Так получается, что все ЦАП после 8 бит это плохие ЦАП? А также всеми любимая OPA637 где осуществляется лазерная подгонка резисторов на каждом кристалле. Это наверное очень дорого, но почему то производитель это делает?
  5. ESP32 использовать не обязательно. У вас есть какие другие предложения? STM32F411 у меня библиотека не ставится на компьютере. PR2040 таймер не измеряет время меньше 1 мкс.