This guide explains how to use both CPU cores of the ESP32 in your Arduino or ESP-IDF project. You’ll learn how to pin tasks to a specific core, how to communicate between cores safely, and how to avoid the common pitfalls that cause crashes or slowdowns. By the end, you’ll have a working template for dual‑core code that you can adapt to your own IoT project.
What You’ll Need
- An ESP32 development board (any model with dual cores, e.g., ESP32-WROOM-32)
- Arduino IDE or ESP-IDF installed and configured for ESP32
- USB cable for programming and serial monitor
- Basic familiarity with Arduino sketches or ESP-IDF components
Step-by-Step
- Identify the cores. The ESP32 has two Xtensa LX6 cores: Core 0 (often called the “protocol core” or “pro CPU”) and Core 1 (the “application core” or “app CPU”). In Arduino, Core 1 is used by default for
loop(), while Core 0 handles Wi‑Fi and Bluetooth stacks. You can run your own tasks on either core, but be careful not to starve the networking stack. - Include the necessary header. In Arduino, add
#include "esp32-hal.h"at the top of your sketch. In ESP-IDF, you’ll use#include "freertos/FreeRTOS.h"and#include "freertos/task.h". - Write a task function. A task is just a function that runs forever (or until deleted). It must have the signature
void taskFunction(void *parameter). Inside, you typically have awhile(1)loop with a delay or avTaskDelaycall to yield the CPU. - Create the task and pin it to a core. In Arduino, use
xTaskCreatePinnedToCore(taskFunction, "TaskName", stackSize, NULL, priority, &taskHandle, coreNumber). The last argument is the core:0or1. In ESP-IDF, the same function is available, or you can usexTaskCreateand let FreeRTOS decide. - Set the stack size and priority. A typical stack size for a simple task is 2048 or 4096 bytes. Priority ranges from 0 (lowest) to 24 (highest) in ESP-IDF; in Arduino, the default is 1. If your task does heavy math or uses large local arrays, increase the stack size to avoid a crash.
- Add a delay inside the task. Without a
delay()(Arduino) orvTaskDelay()(FreeRTOS), the task will hog the core and block lower‑priority tasks. Usedelay(10)orvTaskDelay(pdMS_TO_TICKS(10))to yield. - Communicate between cores safely. Use FreeRTOS queues, semaphores, or mutexes to pass data between tasks. Avoid sharing global variables without protection; a simple
volatileflag is okay for booleans, but for anything larger use a queue or a mutex. - Test with a simple example. Write a sketch that prints “Core 0” from a task pinned to Core 0 and “Core 1” from a task pinned to Core 1. Open the serial monitor and confirm both messages appear.
- Move your time‑critical code to Core 1. Core 1 is less likely to be interrupted by Wi‑Fi or Bluetooth. If your IoT device does sensor reading, PID control, or display updates, pin those tasks to Core 1. Leave Core 0 for the networking stack and background tasks.
Common Mistakes
- Not yielding the CPU. A task without a delay or
vTaskDelaywill starve other tasks on the same core, causing watchdog timeouts and reboots. - Sharing variables without synchronization. Two tasks writing to the same global variable can corrupt data. Use a mutex or a queue.
- Using
delay()inside a FreeRTOS task. In ESP-IDF,delay()is not available; usevTaskDelay. In Arduino,delay()works but it’s better to usevTaskDelayfor consistency. - Setting stack size too small. If your task uses
printfor large local arrays, increase the stack size to 4096 or more. A crash with “Guru Meditation Error” often means stack overflow. - Pinning too many tasks to Core 1. Core 1 is not a magic fast core; it shares the same clock. If you overload it, you’ll see delays. Balance the load.
Tips
- Use
getCoreID()inside a task to print which core it’s running on – helpful for debugging. - For time‑critical loops, use
vTaskDelayUntil()to maintain a precise period, rather thanvTaskDelay()which drifts. - If you only need two tasks, consider using
loopTaskon Core 1 and a single pinned task on Core 0. That’s often enough. - In Arduino, you can also set the CPU frequency with
setCpuFrequencyMhz()to save power, but that affects both cores. - Use
portMUX_TYPEandportENTER_CRITICAL()for very short critical sections, but prefer queues for longer data transfers.
Troubleshooting
- “Guru Meditation Error: Core 0 panic’d” – Usually a stack overflow in a task on Core 0. Increase the stack size in
xTaskCreatePinnedToCore. - Wi‑Fi disconnects or slow response – You may be starving Core 0. Move your tasks to Core 1, or reduce the priority of your Core 0 task.
- Serial monitor shows only one core’s output – Check that both tasks are created correctly and that the core number is 0 or 1. Also ensure the task function has a delay.
- Task not running at all – Verify the task handle is not NULL, and that you didn’t accidentally delete the task immediately after creation.
- Random reboots – Watchdog timeouts often happen when a task blocks forever. Add a delay or yield in every loop.
Frequently Asked Questions
Q: Can I run both cores at different frequencies?
A: No, both cores share the same clock and therefore run at the same frequency.
Q: Which core should I use for my main loop?
A: In Arduino, loop() runs on Core 1 by default. Keep it there unless you have a specific reason to move it.
Q: How do I pass data from one core to another?
A: Use a FreeRTOS queue. Create a queue with xQueueCreate(), send with xQueueSend(), and receive with xQueueReceive().
Q: Is it safe to use Serial.print() from both cores?
A: Yes, but the output may interleave. Use a mutex around the print statement if you need clean lines.
Q: Can I run a task on both cores simultaneously?
A: No, a single task runs on one core at a time. To use both cores, create two separate tasks (or use FreeRTOS’s symmetric multiprocessing features, which are not enabled by default).
Q: What is the maximum number of tasks I can create?
A: It depends on RAM. Each task needs its own stack, so the limit is a few hundred on a typical ESP32 with 320KB RAM.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Campus Tech Innovation Hubs: What They Are
- Poco C51 Airtel Prepaid Locked Variant India?
- Jenkins vs GitHub Actions: Which CI/CD Fits Your Team?
- Turn Off Backup Encryption in iTunes?
- Shared VPS Hosting: Is It Better?
- Disk Defrag Pro: What It Does and Whether You Need It