From .PlatformIO official document
The goal of this tutorial is to demonstrate how simple it is to use PlatformIO IDE for VSCode to develop, run and debug a simple Wi-Fi project with the Espressif IoT Development Framework framework for the ESP32-DevKitC board.
- Level: Intermediate
- Platforms: Windows, Mac OS X, Linux
Requirements:
- Downloaded and installed PlatformIO IDE for VSCode
- Espressif ESP32 Dev Module
- An external debug adapter (e.g. Olimex ARM-USB-OCD)
Setting Up the Project
- Click on “PlatformIO Home” button on the bottom PlatformIO Toolbar:

- Click on “New Project”, select
Espressif ESP32 Dev Moduleas the development board, Espressif IoT Development Framework as the framework and a path to the project location (or use the default one):
Adding Code to the Generated Project
- Create a new file
main.cin src_dir folder and add the following code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899<span class="cm">/* WiFi softAP Example</span><span class="cm"> This example code is in the Public Domain (or CC0 licensed, at your option.)</span><span class="cm"> Unless required by applicable law or agreed to in writing, this</span><span class="cm"> software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR</span><span class="cm"> CONDITIONS OF ANY KIND, either express or implied.</span><span class="cm">*/</span><span class="cp">#include</span> <span class="cpf"><string.h></span><span class="cp">#include</span> <span class="cpf">"freertos/FreeRTOS.h"</span><span class="cp">#include</span> <span class="cpf">"freertos/task.h"</span><span class="cp">#include</span> <span class="cpf">"esp_mac.h"</span><span class="cp">#include</span> <span class="cpf">"esp_wifi.h"</span><span class="cp">#include</span> <span class="cpf">"esp_event.h"</span><span class="cp">#include</span> <span class="cpf">"esp_log.h"</span><span class="cp">#include</span> <span class="cpf">"nvs_flash.h"</span><span class="cp">#include</span> <span class="cpf">"lwip/err.h"</span><span class="cp">#include</span> <span class="cpf">"lwip/sys.h"</span><span class="cm">/* The examples use WiFi configuration that you can set via project configuration menu.</span><span class="cm"> If you'd rather not, just change the below entries to strings with</span><span class="cm"> the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"</span><span class="cm">*/</span><span class="cp">#define EXAMPLE_ESP_WIFI_SSID "mywifissid"</span><span class="cp">#define EXAMPLE_ESP_WIFI_PASS "mywifipass"</span><span class="cp">#define EXAMPLE_ESP_WIFI_CHANNEL 1</span><span class="cp">#define EXAMPLE_MAX_STA_CONN 4</span><span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">TAG</span> <span class="o">=</span> <span class="s">"wifi softAP"</span><span class="p">;</span><span class="k">static</span> <span class="kt">void</span> <span class="nf">wifi_event_handler</span><span class="p">(</span><span class="kt">void</span><span class="o">*</span> <span class="n">arg</span><span class="p">,</span> <span class="n">esp_event_base_t</span> <span class="n">event_base</span><span class="p">,</span><span class="kt">int32_t</span> <span class="n">event_id</span><span class="p">,</span> <span class="kt">void</span><span class="o">*</span> <span class="n">event_data</span><span class="p">)</span><span class="p">{</span><span class="k">if</span> <span class="p">(</span><span class="n">event_id</span> <span class="o">==</span> <span class="n">WIFI_EVENT_AP_STACONNECTED</span><span class="p">)</span> <span class="p">{</span><span class="n">wifi_event_ap_staconnected_t</span><span class="o">*</span> <span class="n">event</span> <span class="o">=</span> <span class="p">(</span><span class="n">wifi_event_ap_staconnected_t</span><span class="o">*</span><span class="p">)</span> <span class="n">event_data</span><span class="p">;</span><span class="n">ESP_LOGI</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"station "</span><span class="n">MACSTR</span><span class="s">" join, AID=%d"</span><span class="p">,</span><span class="n">MAC2STR</span><span class="p">(</span><span class="n">event</span><span class="o">-></span><span class="n">mac</span><span class="p">),</span> <span class="n">event</span><span class="o">-></span><span class="n">aid</span><span class="p">);</span><span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">event_id</span> <span class="o">==</span> <span class="n">WIFI_EVENT_AP_STADISCONNECTED</span><span class="p">)</span> <span class="p">{</span><span class="n">wifi_event_ap_stadisconnected_t</span><span class="o">*</span> <span class="n">event</span> <span class="o">=</span> <span class="p">(</span><span class="n">wifi_event_ap_stadisconnected_t</span><span class="o">*</span><span class="p">)</span> <span class="n">event_data</span><span class="p">;</span><span class="n">ESP_LOGI</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"station "</span><span class="n">MACSTR</span><span class="s">" leave, AID=%d"</span><span class="p">,</span><span class="n">MAC2STR</span><span class="p">(</span><span class="n">event</span><span class="o">-></span><span class="n">mac</span><span class="p">),</span> <span class="n">event</span><span class="o">-></span><span class="n">aid</span><span class="p">);</span><span class="p">}</span><span class="p">}</span><span class="kt">void</span> <span class="nf">wifi_init_softap</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="p">{</span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="n">esp_netif_init</span><span class="p">());</span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="n">esp_event_loop_create_default</span><span class="p">());</span><span class="n">esp_netif_create_default_wifi_ap</span><span class="p">();</span><span class="n">wifi_init_config_t</span> <span class="n">cfg</span> <span class="o">=</span> <span class="n">WIFI_INIT_CONFIG_DEFAULT</span><span class="p">();</span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="n">esp_wifi_init</span><span class="p">(</span><span class="o">&</span><span class="n">cfg</span><span class="p">));</span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="n">esp_event_handler_instance_register</span><span class="p">(</span><span class="n">WIFI_EVENT</span><span class="p">,</span><span class="n">ESP_EVENT_ANY_ID</span><span class="p">,</span><span class="o">&</span><span class="n">wifi_event_handler</span><span class="p">,</span><span class="nb">NULL</span><span class="p">,</span><span class="nb">NULL</span><span class="p">));</span><span class="n">wifi_config_t</span> <span class="n">wifi_config</span> <span class="o">=</span> <span class="p">{</span><span class="p">.</span><span class="n">ap</span> <span class="o">=</span> <span class="p">{</span><span class="p">.</span><span class="n">ssid</span> <span class="o">=</span> <span class="n">EXAMPLE_ESP_WIFI_SSID</span><span class="p">,</span><span class="p">.</span><span class="n">ssid_len</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">(</span><span class="n">EXAMPLE_ESP_WIFI_SSID</span><span class="p">),</span><span class="p">.</span><span class="n">channel</span> <span class="o">=</span> <span class="n">EXAMPLE_ESP_WIFI_CHANNEL</span><span class="p">,</span><span class="p">.</span><span class="n">password</span> <span class="o">=</span> <span class="n">EXAMPLE_ESP_WIFI_PASS</span><span class="p">,</span><span class="p">.</span><span class="n">max_connection</span> <span class="o">=</span> <span class="n">EXAMPLE_MAX_STA_CONN</span><span class="p">,</span><span class="p">.</span><span class="n">authmode</span> <span class="o">=</span> <span class="n">WIFI_AUTH_WPA_WPA2_PSK</span><span class="p">,</span><span class="p">.</span><span class="n">pmf_cfg</span> <span class="o">=</span> <span class="p">{</span><span class="p">.</span><span class="n">required</span> <span class="o">=</span> <span class="nb">false</span><span class="p">,</span><span class="p">},</span><span class="p">},</span><span class="p">};</span><span class="k">if</span> <span class="p">(</span><span class="n">strlen</span><span class="p">(</span><span class="n">EXAMPLE_ESP_WIFI_PASS</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span><span class="n">wifi_config</span><span class="p">.</span><span class="n">ap</span><span class="p">.</span><span class="n">authmode</span> <span class="o">=</span> <span class="n">WIFI_AUTH_OPEN</span><span class="p">;</span><span class="p">}</span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="n">esp_wifi_set_mode</span><span class="p">(</span><span class="n">WIFI_MODE_AP</span><span class="p">));</span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="n">esp_wifi_set_config</span><span class="p">(</span><span class="n">WIFI_IF_AP</span><span class="p">,</span> <span class="o">&</span><span class="n">wifi_config</span><span class="p">));</span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="n">esp_wifi_start</span><span class="p">());</span><span class="n">ESP_LOGI</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"wifi_init_softap finished. SSID:%s password:%s channel:%d"</span><span class="p">,</span><span class="n">EXAMPLE_ESP_WIFI_SSID</span><span class="p">,</span> <span class="n">EXAMPLE_ESP_WIFI_PASS</span><span class="p">,</span> <span class="n">EXAMPLE_ESP_WIFI_CHANNEL</span><span class="p">);</span><span class="p">}</span><span class="kt">void</span> <span class="nf">app_main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="p">{</span><span class="c1">//Initialize NVS</span><span class="n">esp_err_t</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">nvs_flash_init</span><span class="p">();</span><span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o">==</span> <span class="n">ESP_ERR_NVS_NO_FREE_PAGES</span> <span class="o">||</span> <span class="n">ret</span> <span class="o">==</span> <span class="n">ESP_ERR_NVS_NEW_VERSION_FOUND</span><span class="p">)</span> <span class="p">{</span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="n">nvs_flash_erase</span><span class="p">());</span><span class="n">ret</span> <span class="o">=</span> <span class="n">nvs_flash_init</span><span class="p">();</span><span class="p">}</span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="n">ret</span><span class="p">);</span><span class="n">ESP_LOGI</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"ESP_WIFI_MODE_AP"</span><span class="p">);</span><span class="n">wifi_init_softap</span><span class="p">();</span><span class="p">}</span>Warning
Make sure this new file
main.cis registered as source file usingidf_component_registerfunction insrc/CMakeLists.txtfile:1<span class="nb">idf_component_register</span><span class="p">(</span><span class="s">SRCS</span> <span class="s2">"main.c"</span><span class="p">)</span>
- To compile the project use one of the following options:
- Build option from the
Project Tasksmenu - Build button in PlatformIO Toolbar
- Task Menu
Tasks: Run Task... > PlatformIO: Buildor in PlatformIO Toolbar - Command Palette
View: Command Palette > PlatformIO: Build - Hotkeys
cmd-alt-b / ctrl-alt-b:

- Build option from the
- If everything went well, we should see a successful result message in the terminal window:

- To upload the firmware to the board we can use the following options:
- Upload option from the
Project Tasksmenu - Upload button in PlatformIO Toolbar
- Command Palette
View: Command Palette > PlatformIO: Upload - Task Menu
Tasks: Run Task... > PlatformIO: Upload - Hotkeys
cmd-alt-u / ctrl-alt-u:

- Upload option from the
- Connect the board to your computer and update the default monitor speed to
115200inplatformio.inifile:12345<span class="k">[env:esp32dev]</span><span class="na">platform</span> <span class="o">=</span> <span class="s">espressif32</span><span class="na">board</span> <span class="o">=</span> <span class="s">esp32dev</span><span class="na">framework</span> <span class="o">=</span> <span class="s">espidf</span><span class="na">monitor_speed</span> <span class="o">=</span> <span class="s">115200</span> - Open Serial Monitor to observe the output from the board:

- If everything went well, the board should be visible as a WiFi access point:

Debugging the Firmware
Setting Up the Hardware
In order to use Debugging, we need to connect an external JTAG probe and the board using the following pins:
| ESP32 pin | JTAG probe pin |
|---|---|
3.3V |
Pin 1(VTref) |
GPIO 9 (EN) |
Pin 3 (nTRST) |
GND |
Pin 4 (GND) |
GPIO 12 (TDI) |
Pin 5 (TDI) |
GPIO 14 (TMS) |
Pin 7 (TMS) |
GPIO 13 (TCK) |
Pin 9 (TCK) |
GPIO 15 (TDO) |
Pin 13 (TDO) |
- Specify debug_tool in “platformio.ini” (Project Configuration File). In this tutorial, Olimex ARM-USB-OCD-H debug probe is used:
123456<span class="k">[env:esp32dev]</span><span class="na">platform</span> <span class="o">=</span> <span class="s">espressif32</span><span class="na">board</span> <span class="o">=</span> <span class="s">esp32dev</span><span class="na">framework</span> <span class="o">=</span> <span class="s">espidf</span><span class="na">monitor_speed</span> <span class="o">=</span> <span class="s">115200</span><span class="na">debug_tool</span> <span class="o">=</span> <span class="s">olimex-arm-usb-ocd-h</span>
- To start the debug session we can use the following methods:
Debug: Start debuggingin the top menuStart Debuggingoption in the Quick Access menu- Hotkey button
F5:

- Walk through the code using control buttons, set breakpoints, and add variables to the
Watch window:
Writing Unit Tests
Note
Functions setUp and tearDown are used to initialize and finalize test conditions. Implementations of these functions are not required for running tests but if you need to initialize some variables before you run a test, you use the setUp function and if you need to clean up variables you use tearDown function.
For the sake of simplicity, let’s create a small library called calculator, implement several basic functions addition, subtraction, multiplication, division and test them using PlatformIO Unit Testing solution.
- Create a new folder
calculatorin the lib_dir folder and add two new filescalculator.handcalculator.cwith the following contents:calculator.h:123456789101112131415161718<span class="cp">#ifndef _CALCULATOR_H_</span><span class="cp">#define _CALCULATOR_H_</span><span class="cp">#ifdef __cplusplus</span><span class="k">extern</span> <span class="s">"C"</span><span class="p">{</span><span class="cp">#endif</span><span class="kt">int</span> <span class="nf">addition</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">);</span><span class="kt">int</span> <span class="nf">subtraction</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">);</span><span class="kt">int</span> <span class="nf">multiplication</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">);</span><span class="kt">int</span> <span class="nf">division</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">);</span><span class="cp">#ifdef __cplusplus</span><span class="p">}</span><span class="cp">#endif</span><span class="cp">#endif </span><span class="c1">// _CALCULATOR_H_</span>
calculator.c:123456789101112131415161718192021<span class="cp">#include</span> <span class="cpf">"calculator.h"</span><span class="kt">int</span> <span class="nf">addition</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span><span class="p">{</span><span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span><span class="p">}</span><span class="kt">int</span> <span class="nf">subtraction</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span><span class="p">{</span><span class="k">return</span> <span class="n">a</span> <span class="o">-</span> <span class="n">b</span><span class="p">;</span><span class="p">}</span><span class="kt">int</span> <span class="nf">multiplication</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span><span class="p">{</span><span class="k">return</span> <span class="n">a</span> <span class="o">*</span> <span class="n">b</span><span class="p">;</span><span class="p">}</span><span class="kt">int</span> <span class="nf">division</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span><span class="p">{</span><span class="k">return</span> <span class="n">a</span> <span class="o">/</span> <span class="n">b</span><span class="p">;</span><span class="p">}</span>
- Create a new file
test_calc.cto the folder test_dir and add basic tests for thecalculatorlibrary:1234567891011121314151617181920212223242526272829303132333435363738394041424344<span class="cp">#include</span> <span class="cpf"><calculator.h></span><span class="cp">#include</span> <span class="cpf"><unity.h></span><span class="kt">void</span> <span class="nf">setUp</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="p">{</span><span class="c1">// set stuff up here</span><span class="p">}</span><span class="kt">void</span> <span class="nf">tearDown</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="p">{</span><span class="c1">// clean stuff up here</span><span class="p">}</span><span class="kt">void</span> <span class="nf">test_function_calculator_addition</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="p">{</span><span class="n">TEST_ASSERT_EQUAL</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="n">addition</span><span class="p">(</span><span class="mi">25</span><span class="p">,</span> <span class="mi">7</span><span class="p">));</span><span class="p">}</span><span class="kt">void</span> <span class="nf">test_function_calculator_subtraction</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="p">{</span><span class="n">TEST_ASSERT_EQUAL</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">subtraction</span><span class="p">(</span><span class="mi">23</span><span class="p">,</span> <span class="mi">3</span><span class="p">));</span><span class="p">}</span><span class="kt">void</span> <span class="nf">test_function_calculator_multiplication</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="p">{</span><span class="n">TEST_ASSERT_EQUAL</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="n">multiplication</span><span class="p">(</span><span class="mi">25</span><span class="p">,</span> <span class="mi">2</span><span class="p">));</span><span class="p">}</span><span class="kt">void</span> <span class="nf">test_function_calculator_division</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="p">{</span><span class="n">TEST_ASSERT_EQUAL</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="n">division</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="mi">3</span><span class="p">));</span><span class="p">}</span><span class="kt">void</span> <span class="nf">app_main</span><span class="p">()</span><span class="p">{</span><span class="n">UNITY_BEGIN</span><span class="p">();</span><span class="n">RUN_TEST</span><span class="p">(</span><span class="n">test_function_calculator_addition</span><span class="p">);</span><span class="n">RUN_TEST</span><span class="p">(</span><span class="n">test_function_calculator_subtraction</span><span class="p">);</span><span class="n">RUN_TEST</span><span class="p">(</span><span class="n">test_function_calculator_multiplication</span><span class="p">);</span><span class="n">RUN_TEST</span><span class="p">(</span><span class="n">test_function_calculator_division</span><span class="p">);</span><span class="n">UNITY_END</span><span class="p">();</span><span class="p">}</span>
- Let’s run tests on the board and check the results. There should be a problem with
test_function_calculator_divisiontest:
- Let’s fix the incorrect expected value and run tests again. After processing the results should be correct:

Project Inspection
For illustrative purposes, let’s imagine we need to find a function with the biggest memory footprint. Also, let’s introduce a bug to our project so Static Code Analysis can report it.
- Open
PlatformIO Homeand navigate toInspectsection, select the current project and pressInspectbutton:
- Project statistics:

- The biggest function:

- Possible bugs:

Conclusion
Now we have a project template for the ESP32-DevKitC board that we can use as boilerplate for later projects.