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 Module
as 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.c
in 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.c
is registered as source file usingidf_component_register
function insrc/CMakeLists.txt
file: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 Tasks
menu - Build button in PlatformIO Toolbar
- Task Menu
Tasks: Run Task... > PlatformIO: Build
or 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 Tasks
menu - 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
115200
inplatformio.ini
file: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 debugging
in the top menuStart Debugging
option 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
calculator
in the lib_dir folder and add two new filescalculator.h
andcalculator.c
with 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.c
to the folder test_dir and add basic tests for thecalculator
library: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_division
test: - 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 Home
and navigate toInspect
section, select the current project and pressInspect
button: - 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.