Мультизадачность на ядре ESP32-D0WD-V3

VAF

✩✩✩✩✩✩✩
15 Июл 2023
49
1
Москва
Проблема не запустить задачу как таковую, а освоить работу с двумя ядрами в открытую. Все работает, мотор вертится туда-сюда, а ЕнКодер ожидает изменения контактов. Обнаружено искажения показаний ЕнКодера. Иногда при вращении ЕнКодера пальцами направление вращения определяется не верно, естественно, происходит сбой подсчета. Возможный намёк содержится у poty влияние Serial, но исключение print из секции мотора, сбои не устраняет.
В скетче для одного ЕнКодера многократно проверено, что при вращении пальцами все отображается правильно.
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,974
633
45
Обнаружено искажения показаний ЕнКодера. Иногда при вращении ЕнКодера пальцами направление вращения определяется не верно, естественно, происходит сбой подсчета.
Используйте прерывания.
 

vortigont

★★★★★★✩
24 Апр 2020
1,022
542
Saint-Petersburg, Russia
Проблема не запустить задачу как таковую, а освоить работу с двумя ядрами в открытую.
судя по тому какую ерунду вы написали в скетче на предыдущей странице осваивать 2 ядра вам рановато. Вы воспринимаете ядра как монопольный процессор под один лично ваш бесконечный цикл, типа вы его забрали себе и крутите. Это так не работает.
Таски в ртос создаются таким образом что бы они обрабатывали события и засыпали в ожидании следующего события от системы. Если вы создали таску как бесконечную петлю, которая не засыпает, вы этим самым создали холостого пожиратели квантов времени работы планировщика и планировщих начнет хаотично крешить систему если каким-то другим таскам долго не достанется времени на работу (креш по таск вотчдогу). Сама бесконечная петля в таске бессмысленна, если вы думаете что этим монопольно забрали себе ядро - это неверно. РТОС может в любой момент прервать вашу таску переключив контекст по какому-то событию/прерыванию и начать выполнять другой тред. Т.е. вы и свою задачу не решили и РТОСу мешаете нормально работать. Наличие конструкций с millis() внутри таска абсурдно - это попытка сделать собаку на сене "и мне не надо и другим не дам", при этом не понимая что когда "надо" система всё равно ваш тред тормознёт, а когда "не надо" сломает другой тред.
Грамотно написаной многопоточной программе не важно на скольких ядрах она выполняется, на одном или на нескольких - операционная система сама распеределит доступные вычислительные мощности в зависимости от потока событий и ожидающих исполнения тредов. Привязка потоков к ядрам нужна в спецефичных случаях для оптимизации или для тупых задач которые не умеют нормально квантоваться.
 
Изменено:

VAF

✩✩✩✩✩✩✩
15 Июл 2023
49
1
Москва
Окончание этого обсуждения в 2023 году для меня завершилось тем, что заработала двух-ядерная или, точнее ,двух-задачная программа, в одном ядре измерения, в другом Веб. Кроме того использовалась система esp_now для сбора информации с удаленных точек. Все работало до смены версии, чего (библиотеки или ядра) я не уследил произошедшей для меня внезапно. После чего все рассыпалось. Попытка вернуть версии назад не прошли. Пришлось заново восстанавливать библиотеки. esp_now и запрос времени восстановились, но с разделением на две задачи не получается. Проблему использования millis неоднократно упоминали ранее. Сейчас у меня она проявляется при использовании if(millis вместо delay как периодический перезапуск скетча , тогда как при использовании delay все работает правильно. Перезапуск в простейшем двух ледовом скетче к нарушению ритма моргания.
В приложенном скетче символы /* и */ определяют исполняемый вариант.
Код:
/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/
 
long last2,last14; int per2=1000,per14=700, Hi1=1, Hi14=1;

TaskHandle_t Task1;
TaskHandle_t Task2;
 
// Определяем пины светодиодов
const int led1 = 2; // Это синий на плате №3
const int led2 = 14;
 
void setup() 
{
  Serial.begin(115200); 
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
 
  //создаем задачу, которая будет выполняться на ядре 0 с максимальным приоритетом (1)
  xTaskCreatePinnedToCore(
                    Task1code,   /* Функция задачи. */
                    "Task1",     /* Ее имя. */
                    10000,       /* Размер стека функции */
                    NULL,        /* Параметры */
                    1,           /* Приоритет */
                    &Task1,      /* Дескриптор задачи для отслеживания */
                    0);          /* Указываем пин для данного ядра */                  
  delay(500); 
 
  //Создаем задачу, которая будет выполняться на ядре 1 с наивысшим приоритетом (1)
  xTaskCreatePinnedToCore(
                    Task2code,   /* Функция задачи. */
                    "Task2",     /* Имя задачи. */
                    10000,       /* Размер стека */
                    NULL,        /* Параметры задачи */
                    1,           /* Приоритет */
                    &Task2,      /* Дескриптор задачи для отслеживания */
                    1);          /* Указываем пин для этой задачи */
    delay(500); 
} // The end of setup
 
//Task1code: мигает светодиодом раз в секунду
void Task1code( void * pvParameters )
{
  Serial.print("Task1 running on core ");
  Serial.println(xPortGetCoreID());// НЕ Печатается Serial
 
  for(;;)
  {
/*     if(millis()-last2>=per2)
    {
      last2=millis();
      Hi1=1-Hi1;
    digitalWrite(led1, Hi1); //led1=2
   // delay(1000);
   // digitalWrite(led1, LOW);
    }; //delay(1000);
    */
    
    digitalWrite(led1, HIGH);
    delay(1000);
    digitalWrite(led1, LOW);
    delay(1000); 
  } 
}
 
//Task2code: мигает светодиодом раз в 0,7 секунды
void Task2code( void * pvParameters )
{
  Serial.print("Task2 running on core "); // Печатается Serial
  Serial.println(xPortGetCoreID());Serial.println(" ");
 
  for(;;)
  { /*
     if(millis()-last14>=per14)
    {
      last14=millis();
      Hi14=1-Hi14;
     digitalWrite(led2, Hi14);
     } */
     
     digitalWrite(led2, HIGH);
    delay(700);
    digitalWrite(led2, LOW);
    delay(700); 
    
  }
}
 
void loop() 
{
  
}
 

bort707

★★★★★★✩
21 Сен 2020
3,066
914
Сейчас у меня она проявляется при использовании if(millis вместо delay как периодический перезапуск скетча , тогда как при использовании delay все работает правильно
Вы бы почитали ответ @vortigont прямо перед своим нынешним сообщением. Судя по коду, вы проигнорировали его советы.
Миллис и РТОС это два разных подхода организации многозадачности. Их не надо смешивать.
 

VAF

✩✩✩✩✩✩✩
15 Июл 2023
49
1
Москва
Ткните меня носом, где в приведенном мною скетча происходит эта путаница. И как ее распутать?
Что касается предыдущего сообщения, то сообщения, начинающиеся со слов про ерунду и времени, то дальше этих слов читать нельзя. Мы ищем ответов, а не поучений. За никами скрываются подчас достойные люди. Простите за резкость. Я всегда следовал советам Ивана Андреевича, не сдержался, нарушил.
 

bort707

★★★★★★✩
21 Сен 2020
3,066
914
сообщения, начинающиеся со слов про ерунду и времени, то дальше этих слов читать нельзя.
Я еще по прошлому году заметил, что вы вроде как за помощью пришли, но ведете себя как-то насмешливо - пренебрежительно, как будто вы - директор, а мы ваши подчинённые. Возможно в жизни вы "большой человек", только в этой дискуссии это значения не имеет. Тут мы оцениваем вас по вашему коду и высказываниям. И если код - ерунда, то так и говорим.
Если вам надо учителя, который не будет вас критиковать и будет дарить конфетку за каждую правильную запятую - то вы ошиблись адресом, найдите персонального коуча.
 
  • Лойс +1
Реакции: vortigont

VAF

✩✩✩✩✩✩✩
15 Июл 2023
49
1
Москва
Может быть подскажите работающий пример с двумя задачами и использованием if(millis . Только надо показать пример со всеми прибамбасами, так как например ссылка на Streaming.h приводит к 404.

Некоторое время назад я обнаружил пример с темя задачами. Две в task и одна в loop/ Все работают с if(millis . С некоторыми незначительными изменениями приведен в прицепленном. Плата назначена ESP32 DEV MODULE
 

Вложения

Старик Похабыч

★★★★★★★
14 Авг 2019
4,267
1,303
Москва
у меня есть проект (мой, закрытый, не открою) с пультом ру для нрф24 на нано. Там отсеживается нажатие 8-ми кнопок, 4-х потенциомтеров и энкодера, с выводом служебной информации на дисплей по i2c и отправкой данных по радиоканалу. Это многозадачность же ?

Если же речь идет о параллельном выполнении задач, то количество таких задач будет равно числу ядер, которое есть. Никак не больше. Можно посмотреть видео:
 

VAF

✩✩✩✩✩✩✩
15 Июл 2023
49
1
Москва
Это все ясно. Как всегда дьявол кроется в деталях. Почему первый пример с if(millis перезапускается так, что работать по большому нельзя. А второй пример работает и с delay и с if(millis . Насколько принципиально использование Streaming, или это свойство библиотеки "esp32-hal.h". Кстати третья задача из лууп портит красоту вывода. Строки не допечатываются и иногда слипаются. Без третьей задачи красота! Но прежде чем переходить от иллюстраций, хотелось бы понять детали работы delay и millis при двух ядерной программе
 

vortigont

★★★★★★✩
24 Апр 2020
1,022
542
Saint-Petersburg, Russia
Детали я вам объяснял еще год назад, но вы пропустили мимо "ушей". А теперь у вас вылезли случайные ребуты о которых я и писал, правда?
Делей дает возможность усыпить тред на какое-то время и дать поработать другим тредам
 

VAF

✩✩✩✩✩✩✩
15 Июл 2023
49
1
Москва
Ссылки на прошлое не конструктивны. Конструктивен был бы конкретный совет или работающий пример с пояснениями. За отсутствием желаемого пришлось поиграть с примером DualCore, в котором попытка отказаться от delay всегда приводила к частым перезапускам. Оказалось что если в одну из задач вставить delay(1), то все идет без перезапусков, но если вставить delay в обе задачи, то перезапуски возникают. Вывод: идет конкуензия задач за таймер millis, избежать можно, если использовать разные таймеры для каждой из задач. Но у меня после смены версии (см. выше) не работает
hw_timer_t
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
476
137
@VAF,
Вы читали, про принципы работы FreeRTOS ? Это был один из первых ответов - и помеченный вами как решение.
Если нет, то конструктивный совет - прочитать и понять.
"Хорошую" ссылку дать не могу, т.к. зависит от уже имеющихся знаний.
Очень кратко есть например в http://easyelectronics.ru/freertos_manual.html
(это не лучшая, а просто одна из первых ссылок)
 

VAF

✩✩✩✩✩✩✩
15 Июл 2023
49
1
Москва
Спасибо! Я конечно посмотрю, но сейчас для меня более важно вернуть мою систему к состоянию, в котором выполняются старые скетчи. Для обсуждаемой темы delay millis в двух ядерной системе это работа команды hw_timer_t . Ранее работала.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
476
137
@VAF,
В таком случае, возможно проще будет установить portable версию Arduino IDE 1.8.xx со старой "рабочей" версией ядра ESP, и возможно старыми версиями библиотек.
 

VAF

✩✩✩✩✩✩✩
15 Июл 2023
49
1
Москва
Попробую, такая мысль была, я даже пытался найти 1.8.4. Некоторое время у меня стояло и 1.8.4 и 2.0.2 и 2.1.1. Но, наверное, почистил. Сейчас нашел на дичка директорию с 2.02, но при попытке запустить запускается 2.1.1.
Посмотрел предложенное, но это по идее понятное и известное не то, что я хотел. Я хочу прямо в лоб использовать два ядра ESP32
 

bort707

★★★★★★✩
21 Сен 2020
3,066
914
Я конечно посмотрю, но сейчас для меня более важно вернуть мою систему к состоянию
Забавно, год прошел - но вы опять хотите быстрого результата без усилий.
Вы все еще не поняли, что пара дней, потраченная на ПОНИМАНИЕ принципов работы - позволит вам сэкономить месяцы в будущем.
 
  • Лойс +1
Реакции: vortigont

VAF

✩✩✩✩✩✩✩
15 Июл 2023
49
1
Москва
Странно, что вы видите в моих текстах то, чего там нет и наоборот. Усилий на понимание того, что я хочу, я затратил примерно 3-4 рабочих по 6 часов дня. Понимание принципов, никогда не помогало, надо знать детали, в том числе ноу-хау. Здесь вы правы, детали очень разнообразны и найти и освоить их чертовски трудно. Здесь особенно ценна помощь опытного человека, тренера.
 

bort707

★★★★★★✩
21 Сен 2020
3,066
914
Слушайте, "ваши старые скетчи" это г-внокод, который работал только случайно. Они написаны вообще без понимания, о чем я вам писал еще год назад. То что они сейчас "сдулись" - совершенно закономерно. А вы хотите вставить в них какие-то костыли и реанимировать. Это абсолютно бессмысленное занятие.
Наймите уже себе программиста и пусть напишет вам код от начала и до конца, если сами не можете, а учится не хотите.

На этом ставлю вас в игнор, надоели.
 
Изменено:

vortigont

★★★★★★✩
24 Апр 2020
1,022
542
Saint-Petersburg, Russia
Конструктивен был бы конкретный совет или работающий пример
всё нижеследущее не стоит воспринимать как ответ адресно товарищу VAF, не ради него распинаюсь, ибо адекватной способности вести конструктивный диалог он за год так и не продемонстрировал. Возможно эти комментарии помогут другим будущим читателям топика прояснить для себя моменты работы с тредами в RTOS "для ардуино" и не идти по тупиковому пути товарища @VAF. Это очень удачный пример того как "не надо делать".

я (да и не я один) вам подробно расписал почему ваш код - ерунда. Даже не сам код, а весь подход ерунда полная! Никакими примерами это исправить нельзя пока вы не измените архитектуру целиком. Вы исходите из неверных предпосылок изначально и совершаете всё больше и больше ошибок в попытках преодолеть фундаментальные проблемы с помощью малопонятной магии. Если строить замок на песке, то не важно сколько в нем подпорок и насколько толстые стены вы сделаете, он в любом случае расползётся рано или поздно. Если повезёт то позже, в вашем случае на год хватило. А вы всё ждёте пример рабочего костылика (почему-то называя это "ноу-хау") что бы абы как заработал ваш целиком корявый подход и обижаетесь как кисейная барышня на "неконструктив". Уж не знаю какими регалиями и бородой вы обладаете в реальной жизни, но ваша гордыня мешает вам использовать свою голову по назначению.

Вывод: идет конкуензия задач за таймер millis
Основы логики: Для недедуктивного логического рассуждения посылки делают вывод рационально убедительным, не гарантируя его истинность.
Неразобравшись в основах, вы сделали неверный вывод и залезли в дебри еще больше. Использовать какие-либо таймеры для таска это я даже не знаю как описать... насколько неправильно. Ну пусть будет как завести будильник звонить каждую секунду и всю ночь пялиться на часы проверяя не пора ли вставать вместо того чтобы спокойно спать выставив его сразу на 7 утра. Все таски УЖЕ работают от таймера через планировщик by design.


Год назад я вам написал:
Грамотно написаной многопоточной программе не важно на скольких ядрах она выполняется
вы это тоже "прошляпили". А вывод, который нужно было сделать - то что вы пытаетесь раскидать задачи по "ядрам" чтобы они работали независимо и монопольно говорит о том что вы не умеете квантовать свои задачи. Не решив это в рамках одного ядра, вы никогда не добьётесь цели на многоядерной системе ибо закончите, как вам уже говорили, с дизайном - одно ядро на каждую функцию.
1) Вы не смогли построить свой код внутри ардуино loop() ни на миллис ни на делеях и полезли в Task'и в надежде решить свои проблемы некими "отдельными" задачами.
2) внутри таска вы потащили за собой те же подходы что у вас не получилось в loop() - миллисы и делаи, понавтыкали костылей и в итоге потерпели вполне закономерное фиаско. И даже теперь вместо того чтобы вернуться к пересмотру изначально корявого дизайна вы продолжаете искать ноу-хау для костылей с миллис

Открою секрет (который на самом деле вовсе не секрет) - ардуиновский loop() это и есть RTOS Task привязаный к конкретному ядру. То что вы хотите сделать уже давно сделано. Вы переизобретаете велосипед, при том весьма кривой.
Я мог бы написать вам пример как использовать if(millis) внутри таска что бы он не падал еще год назад, но не стал этого делать потому что это неверный подход и, зная как вы это будете использовать, приведёт только к дальнейшим проблемам. И я не хочу что бы эти копипасты расходились потом то там то сям через такие "ноу-хау". Внутри ардуиновского loop() работает if(millis) и delay - подумайте как и почему в качестве "домашки".

Ардуиновский луп под многоядерный есп32 специально создали таким образом что бы не дать начинающим "ардуино-программистам", обученным на атмеговских пошаговых "скетчах," выстрелить себе в ногу. Ибо скетчеписатели вытворяют внутри луп что хотят - блокируют его, задерживают вводом, крутят бесконечные циклы и т.п. из-за того что банально не умеют квантовать задачи. В таких условиях wifi и пр под капотом работать не сможет. Поэтому весь ртос "спрятали" и оставили привычный "пошаговый" луп жестко привязаный к одному ядру - резвитесь там как хотите в этой клетке, максимум нагрузите одно ядро и поломаете свой же код. Остальное подкапотное добро в худшем случае сможет работать на другом ядре. А сетевой стек и много чего еще на самом деле вовсе не привязаны к 0-му ядру (по крайней мере далеко не всё), а вообще не имеет никакой привязки и может исполняться на любом ядре в зависимости от того куда РТОС закинет тред, обработчик прерываний и пр.
И вот тут приходит товарищь ВАФ, не сумев отквантовать свои параллельные задачи в рамках лупа и сломав там самому себе всё что можно он решает - а чего сидеть в клетке, одно ядро я забил но есть же и второе! Можно вылезти в РТОС и понаделать еще тредов (тасок) чисто под МОЁ очень важное монопольное добро! А система, да пёс с ней, пусть сама выкручивается... И вот в эти таски он тащит такой же кривой неквантуемый код использующий те же плохие пошаговые подходы что и ранее. Логично портя своим кривым, жрущим кванты времени, таском уже и всё остальное в системе от чего его так заботливо отгородили в луп треде. А дальше начинается поиск "ноу-хау" и как мне сделать что бы оно "работало как раньше"...

подитоживая:

- если вы нашли где-то "экзамплы" где в ртос таски вставлен вызов ардуиновского delay() - выбросите этот экзампл, он написан безграмотно
- если вы нашли где-то "экзамплы" где в ртос таски вставлена конструкция if (millis() - что-то там) - выбросите этот экзампл, он написан безграмотно
- если вы нашли где-то "экзамплы" где ртос таски используются для "разделения по ядрам чего-либо что бы не тормозило" (тут у меня кнопки, а тут я независимо рулю мотором или что-то считаю) - выбросите этот экзампл, он написан безграмотно
- если вы не готовы управлять таском/тредом с помощью ртос семафоров, очередей, нотификашек или хотя бы саспенд/резюм/делей_тилл - то вам НЕ нужен таск от слова совсем. Вы не получите никаких преимуществ перед таким же кодом, просто засунутым в loop()
- если с помощью тасков пытаетесь "разрулить" проблему, которую вы не смогли так или иначе решить в рамках loop() - вы ничего не решите, только добавите себе малообъяснимые и трудно диагностируемые проблемы
 

VAF

✩✩✩✩✩✩✩
15 Июл 2023
49
1
Москва
Не лень писать такие длинные тексты! Дали бы конкретный ответ-решение, а то возникает мысль о под тексте ваших советов. Резумирую, я не хочу иметь дело с эмулятором многозадачности. Я хочу явно использовать два ядра. Я свел проблему к необходимости использовать различные таймеры для разных ядер. Но, к сожалению, состояние моего инструмента ArduinoIDE не нормальное. Программы с таймерами не компилируются, ни в версии 2.1.1 ни в 2.0.2 ни в 1.8.18. Все они используют один и тот же набор библиотек из arduino15. Как вернуться в прошлое я пока не знаю. Вы такие опытные, все в звездах, помогите.
 

VAF

✩✩✩✩✩✩✩
15 Июл 2023
49
1
Москва
Пытался, то что я сейчас имею и результат этих попыток. Возможно играет роль выбор ESP32 for Arduino или ESP52 by Espressiv
 

VAF

✩✩✩✩✩✩✩
15 Июл 2023
49
1
Москва
Вы правы, восстановиться полностью не удалось. Поэтому и мучаю всех вопросами. Код я не делаю, все это примеры из интернета, которые раньше использовались и работали.