Introduction to the ESP32 WiFi / Bluetooth Wireless Microcontroller

Published on by John Teel

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 wireless capabilities.

Manufactured by Shanghai based Espressif Systems, the ESP32 costs less than $5. It’s quite popular with the maker community, but is also a good low-cost solution for mass production.

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

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


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

Key Specifications and Features:

Processors:

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.

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)

Memory:

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.

Security:

  • 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)

What exactly is the ESP32?


Figure 2 – Actual ESP32 SoC

As I mentioned before, the ESP32 is a SoC (Figure 2). However, most users will not start by using just the 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 3). This module is made by Espressif itself, and this link shows several versions.

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 3 – 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 4 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 4 – 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 5). 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 5 – Programmer board to download application code to the ESP32 module

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
   ledFlash();
}

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.
    pinMode(LED_BUILTIN, OUTPUT);
    while(1)
        {
           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.

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
  ledTaskSetup(void)
  }

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,
  pinMode(LED_BUILTIN, OUTPUT);
    // Create a separate thread to handle LED flashing
  xTaskCreate(
                    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

Conclusion

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.


Article written by Shawn Litingtun

If you need engineering technical support, coaching, training, connections, referrals, and resources to help bring your new electronic hardware product to market then be sure to check out the Hardware Academy.

The key to success is knowledge of the obstacles that lie in your path and a realistic plan on how to overcome those obstacles. Helping you accomplish this is the goal of the Predictable Hardware Report.

9
Leave a Comment

avatar
5 Comment threads
4 Thread replies
2 Followers
 
Most reacted comment
Hottest comment thread
6 Comment authors
Martin Rissocarlos frondiziCirineu C FernandesPeter DalmarisJohn Teel Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Martin Risso
Guest

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?

John Teel
Admin

Hi Martin,

In higher volumes the module prices approach only a couple of dollars. Very hard to beat their pricing.

Yes they are FCC certified which simplifies certification, but your overall product still needs non-intentional FCC certification.

carlos frondizi
Guest
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

John Teel
Admin

Thanks Carlos for the feedback!

Cirineu C Fernandes
Guest

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:

https://www.linkedin.com/posts/cirineu-carvalho-fernandes-20490a37_a-startup-de-hardware-sirineo-technologies-activity-6600536884508663808-kd5i

John Teel
Admin

Thanks for sharing!

Peter Dalmaris
Guest

Excellent post, thank you Shawn and John.

In addition to Neil’s awesome book, in case readers are interested in learning about the ESP32 with the help of mini and larger projects, I wanted to mention my two courses:

1. ESP32 For Busy People
2. ESP32 Unleashed

For readers of Predictable Designs, I also offer a 25% discount for these courses with coupon RVZKMPDR 🙂

Dmitry Snegiryov
Guest
Dmitry Snegiryov

I can recommend:

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

https://leanpub.com/kolban-ESP32

John Teel
Admin

Thanks Dmitry for the recommendation!


Predictable Designs LLC, 10645 N. Oracle Rd, Suite 121-117, Oro Valley, AZ 85737 USA
[email protected], Phone: (520) 261-1844 (for fastest repsponse please email instead of call)
Copyright 2019 by Predictable Designs LLC

This website uses cookies. By continuing you consent to the use of cookies and the collection of your IP address. See our privacy policy for more information.