Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
FREEDOM251

Freedom251 › Blog › Arduino-ESP32

How to use both ESP32 cores—and when a second core will not help

By Freedom251 Team · · 8 min read

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Not every ESP32 has two cores, and a second core is not an automatic speed button. If your board uses a dual-core ESP32 or ESP32-S3, however, FreeRTOS can schedule independent tasks on both processors. The useful pattern is to verify the SoC, confirm that the build is not forced into single-core mode, assign task affinity deliberately, protect shared data, and measure the actual workload.

Start with the chip, not the board name

“ESP32” describes a family rather than one fixed processor. Espressif’s ESP32 Series Datasheet v5.3 says an ESP32 can contain one or two Xtensa 32-bit LX6 processors. In the ESP-IDF v5.5 FreeRTOS documentation, the original ESP32 and ESP32-S3 are examples of dual-core SMP targets, while ESP32-S2 and ESP32-C3 are single-core examples.

As an Amazon Associate I earn from qualifying purchases.

That distinction determines whether there is a second application CPU to use. A development board marketed as an ESP32 may contain a single-core variant, so identify the exact SoC printed on the module or shown by your board definition before changing task code.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Target or configuration Core arrangement What that means for your program
ESP32 (dual-core configuration) Two LX6 cores Tasks can be pinned to Core 0, Core 1, or left eligible for either core.
ESP32-S3 Dual-core target in ESP-IDF v5.5 FreeRTOS SMP can schedule work across both cores.
ESP32-S2 Single core There is no second application core to use.
ESP32-C3 Single core There is no second application core to use.
Dual-core ESP32 or ESP32-S3 with CONFIG_FREERTOS_UNICORE Hardware has two cores, application runs on Core 0 only Disable the unicore setting only if your project and libraries are ready for multicore scheduling.

For single-core targets, Espressif states that CONFIG_FREERTOS_UNICORE is always enabled. On a multicore ESP32 or ESP32-S3, enabling that option intentionally runs the application only on Core 0.

#1 Best Overall
ESP-WROOM-32 ESP32 ESP-32S Development Board 2.4GHz Dual-Mode WiFi + Bluetooth Dual Cores Microcontroller Processor Integrated with Antenna RF AMP Filter AP STA Compatible with Arduino IDE (3PCS)
  • 2.4GHz Dual Mode WiFi + Bluetooth Development Board
  • Support LWIP protocol, Freertos
  • SupportThree Modes: AP, STA, and AP+STA
  • Ultra-Low power consumption, Compatible with Arduino IDE
  • ESP32 is a safe, reliable, and scalable to a variety of applications

What “using both cores” means in FreeRTOS

You do not switch a processor on with a special dual-core mode in a sketch. The operating system runs tasks, and each task has an affinity policy. In ESP-IDF, xTaskCreatePinnedToCore() accepts an affinity value: 0 for Core 0, 1 for Core 1, or tskNO_AFFINITY for either core. The ordinary xTaskCreate() call is supported as well and is treated as unpinned in the documented SMP implementation.

Espressif’s wording is precise: “A thread that is pinned to a particular core is only able to run on that core.” An unpinned thread may switch between cores during execution. A task is therefore not a core; it is work that the scheduler places according to affinity, priority, readiness, and available CPU time.

On typical dual-core ESP32 systems, protocol-related work such as Wi-Fi and Bluetooth is commonly pinned to Core 0, also called PRO_CPU. Application work is commonly pinned to Core 1, or APP_CPU. These are conventional assignments, not an absolute partition. Core 0 is not exclusively reserved for radio code, and every user task is not guaranteed to run on Core 1.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When a second core is actually useful

Two cores help when the program has independent work that would otherwise compete for time. Examples include reading sensors while processing a data stream, maintaining a user interface while a network task waits for packets, or sampling an input continuously while another task performs filtering.

Two cores do not automatically make one serial loop twice as fast. If one task waits on I/O, holds a lock, shares a slow peripheral, or depends on the previous iteration’s result, another core may add synchronization overhead without improving the result. A second core is capacity; the benefit depends on how much independent, runnable work your application has.

Rank #2
ELEGOO 3PCS ESP-32 Dev Boards, ESP-WROOM-32, USB-C, WiFi Bluetooth 4.2 | Low-power IoT Applications, Smart Devices, Automation, Wireless Communication, GPIO Headers, Simplifying Development
  • Dual-Core Performance Up to 240 MHz: Run sensor processing, wireless communication, automation logic and connected-device tasks on a 32-bit dual-core ESP32 platform designed for responsive embedded and IoT projects
  • Built-in Wi-Fi and Bluetooth 4.2: Connect to 2.4 GHz Wi-Fi networks or use Bluetooth Classic and BLE for wireless sensors, smart devices, remote controls, home automation and other connected projects
  • Flexible Power-Saving Modes: ESP32 power-management features support dynamic clock scaling and low-power operating modes, helping developers reduce energy use in compatible sensing, monitoring and connected-device applications, suitable for battery-powered Internet of Things (IoT) devices.
  • USB-C Programming with CP2102: Connect through USB-C for power, sketch uploads and serial monitoring, while GPIO, UART, SPI and I2C interfaces support sensors, displays, motor drivers and other modules (USB-C cable not included)
  • Over-the-Air Update Support: Configure OTA functionality through a compatible ESP-32 software framework to update deployed firmware over Wi-Fi without reconnecting the board by USB for every revision
Arrangement Strength Main limitation What to measure
One task on one core Simplest timing and synchronization model All application work and system work compete for the same CPU time Loop latency, missed deadlines, CPU idle time
Two tasks on one core Clear separation of responsibilities without cross-core sharing Tasks still share one processor; priorities and blocking determine responsiveness Per-task runtime, queue depth, worst-case latency
Tasks on both cores Independent work can proceed concurrently Shared memory, peripherals, interrupts, radio activity, and affinity constraints complicate timing End-to-end latency, throughput, lock wait, watchdog resets, and power use
Unpinned tasks on a dual-core target Scheduler can place work on either core Execution can migrate, making cache, timing, and debugging less predictable Core placement over time and jitter under realistic load

Arduino-ESP32: a practical two-task pattern

The official Arduino-ESP32 repository includes a BasicMultiThreading.ino example. It creates a blink task and an analog-read task. One task uses xTaskCreate(); the other uses xTaskCreatePinnedToCore(). The example checks CONFIG_FREERTOS_UNICORE, selecting Core 0 for a unicore build and Core 1 otherwise. That makes it a useful demonstration of the API distinction, not a performance benchmark or a universal architecture.

1. Confirm the Arduino core and target

Current Arduino-ESP32 documentation identifies version 3.3.12, based on ESP-IDF 5.5. Select the exact board and verify that it is a dual-core target before expecting Core 1 to exist. If the build enables CONFIG_FREERTOS_UNICORE, both tasks can still run, but only on Core 0.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

2. Define work that can block independently

Keep each task focused. A sensor task can read hardware and place results in a queue; a processing task can consume that queue. Avoid having both tasks directly manipulate the same device without a driver-level locking plan.

3. Create one unpinned and one pinned task

#include <Arduino.h>

void blinkTask(void *parameter) {
for (;;) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
vTaskDelay(pdMS_TO_TICKS(500));
}
}

void sampleTask(void *parameter) {
for (;;) {
int value = analogRead(34);
// Send value to a queue or protected buffer here.
vTaskDelay(pdMS_TO_TICKS(20));
}
}

void setup() {
pinMode(LED_BUILTIN, OUTPUT);

xTaskCreate(
blinkTask,
"blink",
2048,
nullptr,
1,
nullptr
);

#if CONFIG_FREERTOS_UNICORE
const BaseType_t appCore = 0;
#else
const BaseType_t appCore = 1;
#endif

xTaskCreatePinnedToCore(
sampleTask,
"sample",
2048,
nullptr,
1,
nullptr,
appCore
);
}

void loop() {
vTaskDelay(pdMS_TO_TICKS(1000));
}

The example’s task functions must not return. A loop with vTaskDelay() yields CPU time and prevents a task from monopolizing its core. Stack size, priority, GPIO numbers, and queue design must be adapted to your board and workload; the snippet demonstrates placement mechanics rather than a tested application configuration.

4. Treat shared data as a synchronization problem

If one task writes a value while another reads it, use a FreeRTOS queue, semaphore, mutex, or another deliberate ownership pattern. Declaring a variable volatile does not make a multi-step update atomic and does not prevent inconsistent structures. A mutex also cannot make a non-thread-safe peripheral safe if an interrupt or system task accesses it outside that mutex.

Rank #3
ELEGOO ESP-32 Super Starter Kit with Tutorial Compatible with Arduino IDE | Development Board, USB-C Dual Core Microcontroller Support AP/STA/AP+STA, CP2102 Chip, WiFi, Bluetooth, 200+ parts for IoT
  • Powerful ESP-32 Board: Unlock the world of Internet of Things (IoT) and advanced electronics with the heart of this kit: the ESP-32 board. It features a powerful dual-core processor, integrated Wi-Fi and Bluetooth 4.2, making it perfect for building connected, smart devices that communicate with your phone or the cloud. It's fully compatible with the Arduino IDE for easy programming.
  • Super Starter Kit: This kit contains over 35 different modules and electronic components, including sensors, displays, motors, and input devices. From LEDs and buttons to an OLED screen, servo motor, and keypad, you have everything needed to explore a vast range of projects in one box.
  • Step by Step Online Tutorial: Jump right in with our detailed, beginner-friendly tutorial. Access 30+ projects with complete code, clear circuit diagrams, and step-by-step instructions. Learn the fundamentals of electronics, coding, and how to utilize the ESP-32's unique capabilities without any prior experience.
  • Hands-on Learning for All Skill Levels: Perfect for students, makers, engineers, and hobbyists. Start with basic circuits and coding, then progress to intermediate and advanced IoT applications. Build practical projects like weather stations, smart home controllers, remote-controlled devices, and interactive gadgets. The skills you learn are the foundation for real-world innovation.
  • Quality & Great Support: Elegoo is committed to quality. We provide a clear, detailed tutorial guide, refined code, and a well-organized component kit. All modules are carefully selected for reliability and ease of use. Our dedicated technical support team and active online community are ready to help you succeed in your learning journey.

ESP-IDF: choose affinity explicitly

In ESP-IDF, the same affinity choices are available directly. Use xTaskCreatePinnedToCore() when a task must stay on one processor, and use tskNO_AFFINITY when either core is acceptable. The standard xTaskCreate() function creates an unpinned task under the documented SMP behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
static void sensor_task(void *arg)
{
for (;;) {
read_sensor();
vTaskDelay(pdMS_TO_TICKS(10));
}
}

static void processing_task(void *arg)
{
for (;;) {
process_next_sample();
vTaskDelay(pdMS_TO_TICKS(1));
}
}

void app_main(void)
{
xTaskCreatePinnedToCore(
sensor_task, "sensor", 4096, NULL, 5, NULL, 0);

xTaskCreatePinnedToCore(
processing_task, "processing", 4096, NULL, 5, NULL, 1);
}

Use Core 0 and Core 1 only when the selected target actually has both cores and the project is not configured for unicore operation. For work that does not need a fixed location, this alternative leaves placement to the scheduler:

xTaskCreate(processing_task, "processing", 4096, NULL, 5, NULL);

Pinning is a constraint, not an optimization guarantee. A pinned task cannot run on the other core if its assigned core is busy. The ESP-IDF guide also notes that a task using floating-point operations in its call flow is automatically pinned to its current core because floating-point unit state cannot freely migrate. Do not infer lower latency or higher throughput merely from adding an affinity argument.

Check the build setting before debugging task placement

On a multicore ESP32 or ESP32-S3, inspect the FreeRTOS configuration and confirm that CONFIG_FREERTOS_UNICORE is disabled when you intend to use both cores. If it is enabled, the application runs only on Core 0 even though the silicon contains two processors. On ESP32-S2 and ESP32-C3, the option is always enabled because those targets are single-core.

Also check the framework version and board target. Arduino-ESP32 3.3.12 is documented as using an ESP-IDF 5.5 base, while a project built against another framework or older release may have different defaults, APIs, or system-task behavior.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
ESP-WROOM-32 ESP32 ESP-32S Development Board 2.4GHz Dual-Mode WiFi + Bluetooth Dual Cores Microcontroller Processor Integrated with Antenna RF AMP Filter AP STA Compatible with Arduino IDE (1 PCS)
  • 2.4GHz Dual Mode WiFi + Bluetooth Development Board
  • Support LWIP protocol, Freertos;ESP32 is a safe, reliable, and scalable to a variety of applications
  • SupportThree Modes: AP, STA, and AP+STA
  • Ultra-Low power consumption, Compatible with Arduino IDE
  • 1PCS 30Pin ESP32 Development Board 2.4GHz WiFi Dual Cores Microcontroller Integrated with Antenna RF Low Noise Amplifiers Filters
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Measure before claiming a speedup

Espressif’s ESP32 Series Datasheet v5.3 lists 539.98 CoreMark for one core at 240 MHz, or 2.25 CoreMark/MHz, and 1079.96 CoreMark for two cores at 240 MHz, or 4.50 CoreMark/MHz. Those are datasheet benchmark figures. They are not a prediction for your board, radio state, compiler settings, memory access pattern, or application.

For your own comparison, keep the hardware, clock configuration, input rate, and compiler settings constant. Record:

  • End-to-end latency, not just the time spent inside one function.
  • Throughput and dropped samples or packets.
  • Worst-case delays, not only averages.
  • Time spent waiting for mutexes, queues, and peripherals.
  • Watchdog resets, stack overflows, and memory pressure.
  • Behavior with Wi-Fi or Bluetooth enabled if the product uses them.

Compare the original single-task design, two tasks sharing one core, and a dual-core arrangement. If the second-core version does not improve the metric that matters to your product, the added synchronization and debugging complexity may not be justified.

Common failure modes

“Core 1 does not exist” errors or crashes

The board may be an ESP32-S2 or ESP32-C3, the selected board definition may target a single-core chip, or CONFIG_FREERTOS_UNICORE may be enabled. Confirm the SoC and build configuration before changing task code.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The second task starves the first

Check task priorities, long critical sections, busy loops, and missing delays. A high-priority task that never blocks can prevent lower-priority work from running on its core. Replace polling with queues, notifications, or timed blocking where possible.

Best Value
HiLetgo ESP-WROOM-32 ESP32 ESP-32S Development Board 2.4GHz Dual-Mode WiFi + Bluetooth Dual Cores Microcontroller Processor Integrated with Antenna RF AMP Filter AP STA for Arduino IDE
  • 2.4GHz Dual Mode WiFi + Bluetooth Development Board
  • Ultra-Low power consumption, works perfectly with the Arduino IDE
  • Support LWIP protocol, Freertos
  • SupportThree Modes: AP, STA, and AP+STA
  • ESP32 is a safe, reliable, and scalable to a variety of applications

Data becomes inconsistent after splitting tasks

Protect shared state with a mutex or queue, define which task owns each peripheral, and avoid updating a structure in place while another task reads it. Keep lock hold times short and never wait indefinitely while holding a lock needed by the other task.

Floating-point work stays on one core

That behavior is expected under the ESP-IDF rule for floating-point call paths. If the task must remain together with its FPU state, design around that affinity instead of assuming migration will occur.

Performance improves in a trivial test but not in the product

System and protocol tasks also consume CPU time, and scheduling changes with radio activity, priorities, blocking, and memory contention. Test with the real sensor rates, network traffic, and logging enabled. A blink-and-delay demonstration proves task creation, not application-level speedup.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The practical verdict

Many introductory sketches create one visible loop and never explicitly add a second application task, but there is no evidence that every ESP32 program ignores half the chip. Some ESP32-family devices have only one core, some dual-core builds intentionally run in unicore mode, and framework tasks already use CPU time. On a dual-core ESP32 or ESP32-S3, use FreeRTOS tasks to separate genuinely independent work, choose pinned or unpinned affinity based on a reason, synchronize shared resources, and verify the result with measurements from your own hardware.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Arduino-ESP32embedded programmingESP-IDFESP32ESP32-S3FreeRTOSmulticore

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.