- Переваги багатоядерного процесора
- ESP32 та FreeRTOS
- Пошук ідентифікатора основного ESP32
- Двоядерне програмування ESP32
Модулі ESP популярні завдяки своїм функціоналам Wi-Fi, таким як ESP8266, ESP-12E тощо. Це всі потужні модулі мікроконтролера з функціональними можливостями Wi-Fi. Є ще один модуль ESP, який є потужнішим та універсальнішим за попередні модулі ESP - його назва ESP32. Він має підключення Bluetooth та Wi-Fi, і ми вже пояснювали можливості BLE ESP32 та використовували ESP32 у багатьох проектах IoT. Але мало хто знає, що ESP32 є двоядерним мікроконтролером.
ESP32 має два 32-розрядні мікропроцесори Tensilica Xtensa LX6, що робить його потужним двоядерним мікроконтролером (core0 та core1). Він доступний у двох варіантах: одноядерний та двоядерний. Але двоядерний варіант є більш популярним, оскільки немає суттєвої різниці в цінах.
ESP32 може бути запрограмований за допомогою Arduino IDE, Espressif IDF, Lua RTOS тощо. Під час програмування за допомогою Arduino IDE код працює лише на Core1, оскільки Core0 вже запрограмований для радіочастотного зв'язку. Але ось у цьому підручнику ми покажемо, як використовувати обидва ядра ESP32 для одночасного виконання двох операцій. Тут першим завданням буде блимати вбудованим світлодіодом, а другим завданням буде отримання даних про температуру з датчика DHT11.
Давайте спочатку побачимо переваги багатоядерного процесора перед одноядерним.
Переваги багатоядерного процесора
- Багатоядерні процесори корисні, коли одночасно працює більше 2 процесів.
- Оскільки робота розподіляється між різними ядрами, її швидкість зростає, і кілька процесів можна одночасно закінчити.
- Споживання енергії можна зменшити, оскільки коли будь-яке ядро перебуває в режимі очікування, ніж воно може бути використано для вимкнення периферійних пристроїв, які в цей час не використовуються.
- Двоядерним процесорам доводиться перемикатися між різними потоками рідше, ніж одноядерними процесорами, оскільки вони можуть обробляти два одночасно замість одного.
ESP32 та FreeRTOS
На платі ESP32 вже встановлена прошивка FreeRTOS. FreeRTOS - це операційна система в режимі реального часу з відкритим кодом, яка дуже корисна для багатозадачності. RTOS допомагає в управлінні ресурсами та максимізації продуктивності системи. FreeRTOS має безліч функцій API для різних цілей, і за допомогою цих API ми можемо створювати завдання та змушувати їх працювати на різних ядрах.
Повну документацію щодо API FreeRTOS можна знайти тут. Ми спробуємо використати деякі API в нашому коді для створення багатозадачного додатка, який працюватиме на обох ядрах.
Пошук ідентифікатора основного ESP32
Тут ми будемо використовувати Arduino IDE для завантаження коду в ESP32. Щоб знати Core ID, на якому працює код, існує функція API
xPortGetCoreID ()
Цю функцію можна викликати з функції void setup () та void loop (), щоб дізнатись ідентифікатор ядра, на якому працюють ці функції.
Ви можете протестувати цей API, завантаживши наведений нижче ескіз:
void setup () { Serial.begin (115200); Serial.print ("функція setup (), що працює на ядрі:"); Serial.println (xPortGetCoreID ()); } void loop () { Serial.print ("loop () function running on core:"); Serial.println (xPortGetCoreID ()); }
Завантаживши наведений ескіз, відкрийте послідовний монітор, і ви виявите, що обидві функції працюють на core1, як показано нижче.
З наведених вище спостережень можна зробити висновок, що ескіз Arduino за замовчуванням завжди працює на core1.
Двоядерне програмування ESP32
Arduino IDE підтримує FreeRTOS для ESP32, а API FreeRTOS дозволяють нам створювати завдання, які можуть працювати незалежно від обох ядер. Завдання - це фрагмент коду, який виконує певні операції на платі, такі як миготливий світлодіод, температура надсилання тощо.
Функція, наведена нижче, використовується для створення завдань, які можуть працювати на обох ядрах. У цій функції ми повинні навести деякі аргументи, такі як пріоритет, ідентифікатор ядра тощо.
Тепер виконайте наведені нижче дії, щоб створити завдання та функцію завдання.
1. Спочатку створіть завдання у функції налаштування порожнечі . Тут ми створимо два завдання, одне - на блимання світлодіода через кожні 0,5 секунди, а інше - отримання температури через кожні 2 секунди.
Функція xTaskCreatePinnedToCore () приймає 7 аргументів:
- Назва функції для реалізації завдання (task1)
- Будь-яке ім'я, присвоєне завданням (“task1” тощо)
- Розмір стека, відведений для завдання словами (1 слово = 2 байти)
- Вхідний параметр завдання (може бути NULL)
- Пріоритет завдання (0 - найнижчий пріоритет)
- Дескриптор завдання (може бути НУЛЬНИМ)
- Основний ідентифікатор, де буде виконуватися завдання (0 або 1)
Тепер створіть Task1 для мигання led, надавши всі аргументи у функції xTaskCreatePinnedToCore ().
xTaskCreatePinnedToCore (Task1code, "Task1", 10000, NULL, 1, NULL, 0);
Подібним чином створіть Task2 для Task2 і зробіть ідентифікатор ядра 1 у 7- му аргументі.
xTaskCreatePinnedToCore (Task2code, "Task2", 10000, NULL, 1, NULL, 1);
Ви можете змінити пріоритет та розмір стека залежно від складності завдання.
2. Тепер ми реалізуємо функції Task1code та Task2code . Ці функції містять код необхідного завдання. У нашому випадку перше завдання буде блимати світлодіодом, а інше - піднімати температуру. Тож складіть дві окремі функції для кожного завдання поза функцією налаштування порожнечі.
Функція Task1code для блимання вбудованого світлодіода через 0,5 секунди реалізована, як показано нижче.
Void Task1code (параметр void *) { Serial.print ("Завдання1 працює на ядрі"); Serial.println (xPortGetCoreID ()); for (;;) {// нескінченний цикл digitalWrite (led, HIGH); затримка (500); digitalWrite (у главі, LOW); затримки (500); } }
Подібним чином реалізуйте функцію Task2code для отримання температури.
void Task2code (void * pvParameters) { Serial.print ("Завдання2 працює на ядрі"); Serial.println (xPortGetCoreID ()); for (;;) { float t = dht.readTemperature (); Serial.print ("Температура:"); Serial.print (t); затримка (2000); } }
3. Тут функція void loop залишатиметься порожньою. Як ми вже знаємо, що функція циклу та налаштування працює на core1, тому ви також можете реалізувати завдання core1 у функції void loop .
Тепер частина кодування закінчена, тому просто завантажте код за допомогою Arduino IDE, вибравши плату ESP32 в меню Інструменти. Переконайтеся, що ви підключили датчик DHT11 до контакту D13 ESP32.
Тепер результати можна відстежувати на Serial Monitor або Arduino IDE, як показано нижче:
Складні програми, такі як система реального часу, можна створити, виконуючи одночасно кілька завдань, використовуючи подвійні ядра ESP32.
Повний код разом із демонстраційним відео наведено нижче.