Introduction to the ESP32 WiFi / Bluetooth Wireless Microcontroller

Introduction to the ESP32 WiFi / Bluetooth Wireless Microcontroller

Discover why the ESP32 wireless microcontroller is such a fantastic choice for both early prototyping as well as mass manufacturing.

The ESP32 is a very versatile System On a Chip (SoC) that can be used as a general purpose microcontroller with quite an extensive set of peripherals including WiFi and Bluetooth wireless capabilities.

It is manufactured by Shanghai-based Espressif Systems, and costs less than $5. Although the ESP32 is a SoC, most users will not start by using just the ESP32 chip itself.

Figure 1 – Actual ESP32 SoC

While it is possible to design a product using the ESP32 SoC, this is not a common approach. Instead, most ESP32-based designs use pre-made modules that consist of an actual ESP-32 SoC, external flash memory, and a crystal and pre-tuned PCB antenna or an IPEX antenna connector.

The whole assembly is then placed under a shielded can (figure 2). This module is made by Espressif itself, and this link shows several versions.

FREE GUIDE: Introduction to Microcontrollers

One big advantage to using this module instead of designing from scratch is that Espressif has already pre-loaded the low-level device drivers, the wireless protocol stacks for WiFi b, g, n, Bluetooth and BLE, and FreeRTOS as the base OS.

In addition, a bootloader has also been loaded to allow for relatively easy downloading of user applications.

Figure 2 – ESP32 Wroom-32 Module

Another module commonly referred to as an ESP32 is what is more appropriately called an ESP32 Development Module. This is basically an ESP32 module mounted on a board with additional support circuitry such as a voltage regulator and a serial to USB IC.

It allows direct connection to a desktop PC that can then be used to compile, download, and run programs directly on this module. Figure 3 shows two such development modules from different manufacturers.

Note that one has more of the pins of the ESP module available than the other one, and is slightly more expensive. Otherwise, they are very similar. They each allow a direct connection to a desktop development system through a USB cable.

Figure 3 – ESP32 Development Module Examples

Now that you’ve learned about both commonly available ESP32 modules, which one should you use?

The recommended approach is to use the Development Board for Proof of Concept designs since it is fully self-contained. Then, switch to the more compact ESP32 module when the application is more fully developed, and the entire hardware design is ready to be integrated.

The application code can be downloaded to the ESP32 Module using an adapter board (Figure 4). It essentially provides all the functionality of the ESP32 Development Module. But the target is the ESP32 Module without the actual programming interface that is part of the Development Board.

Figure 4 – Programmer board to download application code to the ESP32 module

Key Specifications and Features:


Main processor: Tensilica Xtensa 32-bit LX6 microprocessor

Cores: All versions of the ESP32 series are dual-core except for ESP32-S0WD, which is single-core.

Clock frequency: up to 240 MHz

Performance: up to 600 DMIPS

Ultra low power co-processor: allows you to do ADC conversions, computation, and level thresholds while in deep sleep.

Figure 5 is a functional block diagram of this SoC taken from its datasheet, which is available on the Espressif Website.

Figure 5 – Functional block diagram of the ESP32 from the datasheet

Wireless connectivity:

Wi-Fi: 802.11 b/g/n/e/i (802.11n @ 2.4 GHz up to 150 Mbit/s)

Bluetooth: v4.2 BR/EDR and Bluetooth Low Energy (BLE)


ROM: 448 KB – For booting and core functions

SRAM: 520 KB – For data and instruction

RTC fast SRAM: 8 KB – For data storage and main CPU during RTC Boot from the deep-sleep mode

RTC slow SRAM: 8 KB – For co-processor accessing during deep-sleep mode

eFuse: 1 KBit – Of which 256 bits are used for the system (MAC address and chip configuration) and the remaining 768 bits are reserved for customer applications, including Flash-Encryption and Chip-ID

Embedded flash:

  • 0 MB (ESP32-D0WDQ6, ESP32-D0WD, and ESP32-S0WD chips)
  • 2 MB (ESP32-D2WD chip)
  • 4 MB (ESP32-PICO-D4 SiP module)

Flash memory is connected internally via IO16, IO17, SD_CMD, SD_CLK, SD_DATA_0 and SD_DATA_1 on ESP32-D2WD and ESP32-PICO-D4.

External flash & SRAM: ESP32 supports up to four 16 MB external QSPI flashes and SRAMs with hardware encryption based on AES to protect developers’ programs and data. ESP32 can access the external QSPI flash and SRAM through high-speed caches.

  • Up to 16 MB of external flash are memory-mapped onto the CPU code space, supporting 8-bit, 16-bit and 32-bit access. Code execution from flash is supported.
  • Up to 8 MB of external flash/SRAM memory are mapped onto the CPU data space, supporting 8-bit, 16-bit and 32-bit access. Data-read is supported on the flash and SRAM. Data-write is supported on the SRAM.

Note that ESP32 chips with embedded flash do not support the address mapping between external flash and peripherals.

Peripheral input/output: The ESP32 offers a rich peripheral interface with DMA that includes:

  • Capacitive touch
  • ADCs (analog-to-digital converter)
  • DACs (digital-to-analog converter)
  • I²C (Inter-Integrated Circuit)
  • UART (universal asynchronous receiver/transmitter)
  • CAN 2.0 (Controller Area Network)
  • SPI (Serial Peripheral Interface)
  • I²S (Integrated Inter-IC Sound)
  • RMII (Reduced Media-Independent Interface)
  • PWM (pulse width modulation), and more.


  • IEEE 802.11 standard security features all supported, including WFA, WPA/WPA2 and WAPI
  • Secure boot
  • Flash encryption
  • 1024-bit OTP, up to 768-bit for customers
  • Cryptographic hardware acceleration: AES, SHA-2, RSA, elliptic curve cryptography (ECC), random number generator (RNG)

Developing applications for the ESP32

The usual way to develop any embedded system is to first choose the proper microcontroller, or microcontroller module, that fits the desired hardware requirements and, just as importantly, has the proper software development support.

A prototype hardware platform to test the application code is developed. Then, the application software development process can begin.

Assuming that the ESP32 has been chosen as the microcontroller module, the next step is to actually set up an environment where application code can be developed and tested.

Developing an application for an embedded system is an iterative process that usually requires a setup on a cross-development platform whereby the code can be written, complied, linked, and loaded into the processor.

After hardware testing, the whole process is repeated until you achieve the final performance requirements.

The entire process is usually carried out in an Integrated Development Environment (IDE) that, at a minimum, should provide the following: A text editor to write the application code; a compiler/linker/locater; and a loader to download the compiled binary code to the proper physical address segments in the target processor.

The IDE also typically includes some kind of feature that automates the whole cycle.

The official way of setting up this environment, as recommended by Espressif, and named IDF for IoT Development Framework, is given in this link.

This is quite elaborate, and requires separately installing the file editor and the build tools separately. However, it offers the best performance in terms of being able to write the tightest, fastest code.

For example, it offers full access to the ESP-32 Application Programming Interface (API).

An alternative to using the IDF that should not be discounted is to use Arduino. Whether using the Arduino IDE or some other IDE, developing ESP32 applications in an Arduino framework can accomplish nearly everything that the ESP32 IDF does, but with a less steep learning curve. It also has performance penalties that are acceptable in most cases.

The ESP32 Arduino core is actually built upon the ESP32 IDF. It provides an additional layer of abstraction that in most applications can simplify, and speed up, development.

There are plenty of articles already written about how to install the Arduino IDE, and how to install any board such as the ESP32. There are also plenty of libraries available to help in developing all sorts of applications for the ESP32.

The rest of this article will focus on one aspect of the ESP32 that is not usually exploited by most Arduino applications – the FreeRTOS that is native to the ESP32.

Almost all Arduino applications just have a setup() and a loop() function. Because the ESP32 runs FreeRTOS, it is quite capable of multitasking.

The ESP32 is also quite a powerful, and fast, microcontroller with plenty of flash and SRAM. Running multiple threads is not only quite feasible, but can actually simplify and enhance some application code.

As a trivial example, consider a user who wants a built-in LED to continuously blink while the application is running.

The code sample below shows this attempt. Here, unfortunately, because the code is executed sequentially, the ledBlink() function hogs all of the processor resources, and the running code never exits the setup() function. This means the user application never gets to run.

It is possible to get this to properly run by running the ledBlink() function as part of a timer interrupt. However, dedicating a timer simply to make an LED blink in the background while the main application is running wastes processor resources. Now, imagine if multiple LED’s have to be made to blink at different rates. The part of the code required to do just that can get quite complicated:

void setup()
// Setup code for the user application here ….
// Start the LED flashing

void loop()
// Put user application here ….

// Simple LED flash function
void ledFlash()
// Initialize digital pin LED_BUILTIN as an output. For the ESP32, LED_BUILTIN is usually
// 2, meaning GPIO2.
digitalWrite(LED_BUILTIN, HIGH); // Turn the LED on (HIGH is the voltage level)
delay(1000); // Wait for a second
digitalWrite(LED_BUILTIN, LOW); // Turn the LED off by making the voltage LOW
delay(1000); // Wait for a second

A better approach is to actually run the LED flashing function as a completely separate task. The next few functions show how this is accomplished using the FreeRTOS API that comes for free on the ESP32.

Note that in the setup() function, the task to flash the LED is created. After this point, the task simply runs forever, or until stopped by a call to delete the task using the FreeRTOS vTaskDekete() function.

NOTE: This is a long, very detailed article so here's a free PDF version of it for easy reading and future reference.

With this approach, it is now possible to have more than one LED flashing at different rates, for example. Just create more tasks, following the same approach as used here. Simply choose a different IO port for each LED.

The application will still run completely independently, as its own separate task. It is even possible to choose which of the cores of a dual-core ESP32 will run each task.

If, for example, the application requires no wireless functionality, which typically runs on core 0 of the ESP32, then it can be used to flash the LED’s, and core 1 can be dedicated to run the application. The FreeRTOS API for the ESP32 can be found here.

void setup()
// Setup code for the user application here ….

// Set up the LED flashing as a separate task.
// From this point on, the LED will flash in the background

void loop()
// Put user application here ….
// That’s the LED flash task that will run as a separate thread.
void ledFlash(void *pvParameters)
while(1) // The thread must never exit.
digitalWrite(LED_BUILTIN, HIGH); // Turn the LED on
vTaskDelay(pdMS_TO_TICKS((1000))); // Better version of delay(1000) using FreeRTOS
digitalWrite(LED_BUILTIN, LOW); // Turn the LED off
vTaskDelay(pdMS_TO_TICKS((1000))); // Better version of delay(1000) using FreeRTOS
} // End ledFlash

// Task setup function. Calls xTaskCreate to actually create a new task.
void ledTaskSetup(void)
// Set up digital IO ports to control the LED's,
// Create a separate thread to handle LED flashing
ledFlash, // Function that implements the task.
"LED_Flash", // Text name for the task.
1000, // Stack size in bytes, not words.
NULL, // Parameter passed into the task.
1, // Priority at which the task is created.
NULL); // Used to pass out the created task's handle.
} // End ledTaskSetup


This article is by no means an exhaustive description of the ESP32. but you should now understand some of its important features.

These features, coupled with the wide availability and low cost, make the ESP32 a strong contender for embedded wireless applications where a well-supported, processing platform is needed.

Other content you may like:

3.8 6 votes
Article Rating
Notify of

Oldest Most Voted
Inline Feedbacks
View all comments

There is something that is not very clear to me, the pre-made esp-32 modules already include the programmed bootloader but the SoC itself does not, so I need a debugger to burn the bootloader when I develop my own SoC-based hardware. is this correct or do they both already include bootloader?  thanks in advance!

Reply to  William

Hi William,

If you need to go with an SoC, and not a module, you should consider an ESP32 PICO D4. It has everything, including the flash that is normally an additional chip in the module..

Tim Redfern
Tim Redfern

…One big advantage to using this module instead of designing from scratch is that Espressif has already pre-loaded the low-level device drivers, the wireless protocol stacks for WiFi b, g, n, Bluetooth and BLE, and FreeRTOS as the base OS.

I don’t think this is true. Both the modules and chips come without an application programmed. With ESP32, unlike other IoT devices, drivers are not supplied in ROM, they are compiled from the IDF and flashed along with the application.

Reply to  Tim Redfern

That is true. What I was trying to convey is one does not need to really think about the details when writing the actual application.

Martin Risso

How much do the modules mentioned here cost? Are the modules FCC type approved so that a product using one of the modules is “automatically” FCC type approved?

carlos frondizi
carlos frondizi

Thanks , very good explanation, Im using ESP32 but with Arduino IDE since i started with Arduino boards and dont have the energy to switch to another (maybe better) option

Reply to  John Teel

John, would it be possible for you to show us in an article how to use the Eclipse based IDF?


Cirineu C Fernandes

I developed a project with ESP32 here in Brazil called JARM ESP32 IoT, an advanced hardware for final IoT projects. See a little about him in:

Dmitry Snegiryov
Dmitry Snegiryov

I can recommend:

Kolban’s book on ESP32
Neil Kolban
The definitive guide to programming on the ESP32.

Copyright 2023 Predictable Designs LLC.  Privacy policy | Terms
  10645 N Oracle Blvd, Ste 121-117, Tucson, Arizona 85737 USA