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

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Not every ESP32 program is ignoring half the chip, because “ESP32” names a family that includes both single-core and dual-core SoCs. On a dual-core ESP32 or ESP32-S3, however, a sketch that creates one application task may leave useful parallel capacity untapped. The safe way to use it is through FreeRTOS tasks: assign work to Core 0, Core 1, or leave it eligible for either, then measure the result on your actual board.

A second core is capacity, not an automatic speed button. Wi-Fi, Bluetooth, framework services, task priorities, blocking calls, shared data, and the build’s single-core setting all affect what runs where. Start by identifying the exact chip and framework, then add independent work as a separate task instead of moving an entire sketch blindly.

First check whether your ESP32 actually has two cores

The original ESP32 family is not a single hardware specification. Espressif’s ESP32 Series Datasheet v5.3 describes devices with one or two Xtensa 32-bit LX6 processors. ESP-IDF v5.5 documents ESP32 and ESP32-S3 as dual-core SMP targets, while ESP32-S2 and ESP32-C3 are examples of single-core targets.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Target example Core configuration What that means for your code
ESP32 One or two cores, depending on the SoC variant Confirm the exact module or chip before assigning work to Core 1.
ESP32-S3 Dual-core SMP target in ESP-IDF Tasks can be scheduled on both cores when the build and workload permit it.
ESP32-S2 Single core There is no second application core to use.
ESP32-C3 Single core Core-affinity code for Core 1 is not applicable.

Board names can be less precise than the silkscreen suggests. Check the module marking, board documentation, or the build target selected by your environment. A dual-core ESP32-S3 development board is a suitable category for trying the examples, but a specific board’s availability, price, memory layout, and peripheral wiring must be verified separately.

#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

ESP-IDF runs FreeRTOS and exposes task affinity. A task created with xTaskCreatePinnedToCore() receives an affinity for Core 0 or Core 1. The documented values are:

  • 0: the task may run only on Core 0.
  • 1: the task may run only on Core 1.
  • tskNO_AFFINITY: the task is allowed to run on either core.

The ordinary xTaskCreate() API is also supported. In the documented SMP implementation, a task created that way is unpinned, so the scheduler can move it between cores. Espressif’s guide states: “A thread that is pinned to a particular core is only able to run on that core.” It also states that an unpinned thread can switch between cores during execution.

Core labels describe common arrangements, not permanent ownership. Espressif says protocol-related work such as Wi-Fi and Bluetooth is typically pinned to Core 0 (PRO_CPU), while application work is typically placed on Core 1 (APP_CPU). That is a convention used by the framework; Core 0 is not exclusively a radio core, and user code is not guaranteed to run only on Core 1.

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

The single-core build option can disable the second core

ESP-IDF’s CONFIG_FREERTOS_UNICORE option intentionally runs an application on only Core 0 even when the hardware has multiple cores. For single-core ESP32-S2 and ESP32-C3 targets, this option is always enabled. If a dual-core board behaves like a one-core target, inspect the active SDK configuration before changing task code.

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

Decide whether your workload can benefit

Two cores help when there is independent work that can make progress concurrently. A sensor acquisition loop that must not wait on network activity is a reasonable candidate for a separate task. Two pieces of code that repeatedly touch the same buffer, peripheral, or state machine may instead spend time contending for locks.

  • Good candidates: blocking I/O separated from computation, periodic sensor sampling separated from a user interface, or a producer task feeding a consumer through a queue.
  • Risky candidates: code that manipulates the same peripheral from two tasks, long critical sections, busy loops at high priority, and callbacks that assume they always run on one core.
  • Measure first: record the baseline latency, throughput, missed deadlines, and CPU behavior of the original design before adding another task.

Task priority and blocking behavior matter as much as core count. A high-priority task that never blocks can starve lower-priority work, including framework services. A task that sleeps or waits on a queue gives the scheduler opportunities to run other work.

Use both cores with Arduino-ESP32

The Arduino-ESP32 documentation currently identifies version 3.3.12, based on ESP-IDF 5.5. Check the version installed in your board package before copying an example, because task behavior and configuration menus follow the underlying ESP-IDF release.

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

1. Start with Espressif’s official multithreading example

The official BasicMultiThreading.ino example demonstrates two distinct choices. It creates one task with xTaskCreate() and another with xTaskCreatePinnedToCore(). The sample uses a blink task and an analog-read task, so it demonstrates mechanics rather than promising a particular performance gain.

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.

2. Select a valid running core

The example checks CONFIG_FREERTOS_UNICORE. It defines a running-core value of 0 for a unicore build and 1 for a multicore build, then passes that value to xTaskCreatePinnedToCore(). This conditional matters: hard-coding Core 1 makes a sketch unsuitable for a single-core target or a multicore build configured to run unicore.

3. Create a task for independent work

A minimal pattern looks like this:

#if CONFIG_FREERTOS_UNICORE
#define TASK_RUNNING_CORE 0
#else
#define TASK_RUNNING_CORE 1
#endif

void workerTask(void *parameter) {
  for (;;) {
    // Do independent, bounded work here
    vTaskDelay(pdMS_TO_TICKS(10));
  }
}

void setup() {
  xTaskCreatePinnedToCore(
    workerTask,
    "worker",
    4096,
    nullptr,
    1,
    nullptr,
    TASK_RUNNING_CORE
  );
}

void loop() {
  // Keep the main Arduino activity non-blocking.
  delay(100);
}

The stack size, priority, delay, and work in this illustration are starting points, not universal settings. Match them to the libraries and data structures in your project. Keep each task’s loop bounded and decide how it communicates with the other task before writing the code.

4. Keep shared data synchronized

When one task writes data another task reads, use a FreeRTOS queue, semaphore, mutex, or another synchronization mechanism appropriate to the data flow. Volatile alone does not make a multi-step update atomic, and moving tasks to separate cores can expose races that were hidden when everything happened serially. Protect peripheral access as well: two tasks should not configure or transmit through the same device simultaneously without an agreed ownership rule.

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.

5. Confirm the behavior, not just compilation

Add temporary logging of task names and core IDs, or use the task-inspection facilities available in your framework, to verify that the intended task is running where expected. Then compare the measured workload with the one-task baseline. The example proves that the APIs work; it is not a benchmark for your board, radio configuration, or application.

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

Use task affinity directly in ESP-IDF

In an ESP-IDF project, the same mechanism is available without the Arduino wrapper. Include the FreeRTOS task APIs, write a task function with the required void * argument, and create it from app_main() or another initialization task.

static void sensor_task(void *arg)
{
    for (;;) {
        // Read or process data that can run independently.
        vTaskDelay(pdMS_TO_TICKS(20));
    }
}

void app_main(void)
{
    xTaskCreatePinnedToCore(
        sensor_task,
        "sensor_task",
        4096,
        NULL,
        5,
        NULL,
        1
    );
}

Use affinity 0 or 1 only when you have a reason to constrain placement. Pass tskNO_AFFINITY when either core is acceptable and migration is useful. The standard xTaskCreate() call is the less restrictive option in the documented SMP implementation.

Check the project configuration

Open the project configuration and inspect CONFIG_FREERTOS_UNICORE. On a dual-core ESP32 or ESP32-S3, disabling unicore permits SMP scheduling; enabling it deliberately limits the application to Core 0. Ensure the selected target in the build system matches the physical chip, because an application compiled for a different target can produce misleading affinity errors or unavailable-core assumptions.

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

Choose an assignment pattern

Pattern When it fits Main trade-off
One task, one core Simple sketches, tightly ordered steps, or single-core hardware Least coordination, but no parallel application task.
Two tasks on one core Separating responsibilities while keeping placement predictable Tasks still share one CPU and compete through priorities and time slices.
Pinned tasks on both cores Independent work with a clear reason to reserve placement A pinned task cannot use the other core if its assigned core is busy.
Unpinned tasks Work that can run on either core and does not depend on placement The scheduler may migrate the task, so timing and cache locality can vary.

Compare designs using the actual chip and core count, Arduino or ESP-IDF version, affinity choices, radio and framework load, task priorities, blocking behavior, shared-state synchronization, and measured latency or throughput. The documentation does not provide a universal speedup for a generic sketch; any improvement must be demonstrated on the reader’s hardware and workload.

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
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Important limits and side effects

Floating-point code can force affinity

ESP-IDF documents a special case for floating-point use. If a task uses float directly or through a function in its call flow, the task is automatically pinned to its current core because the floating-point unit state cannot freely migrate between cores. Do not assume that an unpinned declaration guarantees migration when the call path performs floating-point work.

Pinning is not a latency guarantee

Pinning removes one scheduling choice; it does not reserve a quiet processor. The selected core may still run protocol, framework, interrupt, and other application work. A pinned task can also perform worse if its chosen core is congested while the other core is mostly idle.

Shared resources can erase the benefit

Two tasks that immediately take the same mutex, wait on the same peripheral, or exchange tiny messages at very high frequency may add context-switch and synchronization overhead without increasing useful work. Split tasks around meaningful independent operations, not merely to make the task count larger.

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

What the datasheet benchmark numbers do—and do not—tell you

Espressif’s ESP32 Series Datasheet v5.3 lists 539.98 CoreMark for one core at 240 MHz, or 2.25 CoreMark per MHz. It lists 1079.96 CoreMark for two cores at 240 MHz, or 4.50 CoreMark per MHz. Those are datasheet benchmark figures from Espressif Systems, not a prediction for a particular Arduino sketch.

Real results vary with compiler options, memory access, radio activity, interrupts, task synchronization, peripheral waits, and whether the workload can actually run concurrently. Treat the figures as an indication of available processor capacity, not as a guaranteed two-times application speedup.

Measure a two-core change properly

  1. Record a baseline. Measure the original program’s end-to-end latency, sustained throughput, deadline misses, and power or thermal behavior if those matter to the product.
  2. Change one architectural variable. Move one independent operation into a task while leaving data formats, sensor rates, and logging otherwise unchanged.
  3. Verify placement. Confirm the target chip, the CONFIG_FREERTOS_UNICORE setting, and the task’s actual affinity. Do not infer core use from the existence of a task alone.
  4. Exercise realistic contention. Test with Wi-Fi or Bluetooth enabled when the product will use them, with normal message rates and the same peripherals active.
  5. Compare the same metrics. Keep the test duration and workload constant. A faster isolated loop is not an improvement if network latency, dropped samples, or watchdog resets get worse.
  6. Retest failure paths. Include queue-full conditions, disconnected radios, delayed sensors, and reboot or recovery sequences. Concurrency bugs often appear only when a task blocks unexpectedly.

Troubleshooting common problems

“Core 1” is rejected or the task never starts

  • Verify that the board really contains a dual-core target such as ESP32 or ESP32-S3.
  • Check whether CONFIG_FREERTOS_UNICORE is enabled.
  • Confirm that the selected Arduino board package or ESP-IDF target matches the chip.

The second task runs, but the program is not faster

  • Check whether both tasks are blocked on the same peripheral or lock.
  • Lower any priority that creates a busy loop and prevent starvation of framework tasks.
  • Measure queue and mutex wait time; the bottleneck may be I/O or synchronization rather than CPU.
  • Remember that floating-point call paths may pin a task, and that a pinned task cannot borrow the other core.

Wi-Fi or Bluetooth becomes unreliable

  • Do not assume Core 0 is free for application work; protocol tasks are typically placed there.
  • Reduce long critical sections and blocking operations in code that competes with protocol services.
  • Test under the same radio conditions and traffic volume as the final application.

Values occasionally appear corrupted

  • Look for unsynchronized multi-step reads and writes between tasks.
  • Use a queue for ownership transfer or a mutex for protected shared state.
  • Ensure that a peripheral has one clear owner or that every access follows the same lock.

The practical answer to “How do I use both ESP32 cores?”

Identify the SoC first. If it is a dual-core target and the build is not intentionally unicore, create separate FreeRTOS tasks for genuinely independent work. Use xTaskCreatePinnedToCore() with 0 or 1 when placement matters, or use xTaskCreate() and tskNO_AFFINITY when either core is suitable. Keep protocol load, priorities, blocking, floating-point behavior, and shared data in the design, then verify the result with measurements from the real application.

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.

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