Book Image

Developing IoT Projects with ESP32 - Second Edition

By : Vedat Ozan Oner
3 (2)
Book Image

Developing IoT Projects with ESP32 - Second Edition

3 (2)
By: Vedat Ozan Oner

Overview of this book

ESP32, a low-cost and energy-efficient system-on-a-chip microcontroller, has become the backbone of numerous WiFi devices, fueling IoT innovation. This book offers a holistic approach to building an IoT system from the ground up, ensuring secure data communication from sensors to cloud platforms, empowering you to create production-grade IoT solutions using the ESP32 SoC. Starting with IoT essentials supported by real-world use cases, this book takes you through the entire process of constructing an IoT device using ESP32. Each chapter introduces new dimensions to your IoT applications, covering sensor communication, the integration of prominent IoT libraries like LittleFS and LVGL, connectivity options via WiFi, security measures, cloud integration, and the visualization of real-time data using Grafana. Furthermore, a dedicated section explores AI/ML for embedded systems, guiding you through building and running ML applications with tinyML and ESP32-S3 to create state-of-the-art embedded products. This book adopts a hands-on approach, ensuring you can start building IoT solutions right from the beginning. Towards the end of the book, you'll tackle a full-scale Smart Home project, applying all the techniques you've learned in real-time. Embark on your journey to build secure, production-grade IoT systems with ESP32 today!
Table of Contents (15 chapters)
13
Other Books You May Enjoy
14
Index

Debugging

All families of ESP32 MCUs support Joint Test Action Group (JTAG) debugging. ESP-IDF makes use of OpenOCD, an open-source software, to interface with the JTAG probe/adapter, such as an ESP-Prog debugger. To debug our applications, we use an Espressif version of gdb (the GNU debugger), depending on the architecture of ESP32 that we have in a particular project. The next figure shows a general ESP32 debug setup:

Figure 2.24: JTAG debugging

When we develop our own custom ESP32 devices, we can connect to the standard JTAG interface of ESP32 to debug the application. With this option, we need to use a JTAG probe between the development machine and the custom ESP32 device. The JTAG pins are listed on the official documentation for each family of ESP32 (https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/configure-other-jtag.html).

The issue with JTAG debugging is that it requires at least 4 GPIO pins to carry the JTAG signals, which means 4 GPIO pins less available to your application. This might be a problem in some projects where you need more GPIO pins. To address this issue, Espressif introduces direct USB debugging (built-in JTAG) without a JTAG probe. In the preceding figure, the JTAG probe in the middle is not needed for debugging and OpenOCD running on the development machine talks directly to the MCU over USB. The built-in JTAG debugging requires only two pins on ESP32, which saves two pins compared to the ordinary JTAG debugging with a probe. This feature is not available in all ESP32 families but ESP32-C3 and ESP32-S3 do have it; thus, we will prefer this method in this example with our ESP32-S3-BOX-Lite devkit. We don’t need a JTAG probe but we still need a USB cable with the pins exposed outside to be able to connect them to the corresponding pins of the devkit. The connections are:

ESP32-S3 Pin    USB Signal
GPIO19            D-
GPIO20            D+
5V                V_BUS
GND            Ground

We can find a USB cable on many online shops with all lines exposed but it is perfectly fine to cut a USB cable and solder a 4-pin header to use its pins. You can see my simple setup below:

Figure 2.25: Built-in JTAG

We don’t need a driver for Linux or macOS to use the built-in JTAG debugging. The Windows driver comes with the ESP-IDF Tools Installer (https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/get-started/windows-setup.html#esp-idf-tools-installer).

Now, it is time to create the project and upload the firmware to see whether our setup works. In this example, we will see another way of creating an ESP-IDF project. We will work in the ESP-IDF environment from the command line and use the idf.py script to create the project and for other project tasks. Let’s do this in steps:

  1. If you are a Windows user, run the ESP-IDF Command Prompt shortcut from the Windows Start menu. It will open a command-line terminal with the ESP-IDF environment. If your development platform is Linux or macOS, start a terminal and run the export.sh or export.fish scripts respectively to have the ESP-IDF environment in the terminal:
    $ source ~/esp/esp-idf/export.sh 
    Detecting the Python interpreter
    Checking "python" ...
    Python 3.10.11
    "python" has been detected
    Adding ESP-IDF tools to PATH…
    <more logs>
    Done! You can now compile ESP-IDF projects.
    Go to the project directory and run:
    idf.py build
    
  2. Test the idf.py script by running it without any arguments. It will print the help message:
    $ idf.py
    Usage: idf.py [OPTIONS] COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]...
    ESP-IDF CLI build management tool. For commands that are not known to idf.py an attempt to execute it as a build system target will be made.
    <rest of the help message>
    
  3. Go to your project directory and run idf.py with a new project name. The script will create an ESP-IDF project with that name in a directory with the same name:
    $ idf.py create-project debugging_ex
    Executing action: create-project
    The project was created in <your project directory>/debugging_ex
    $ ls
    debugging_ex
    $ cd debugging_ex/
    $ tree
    .
    ├── CMakeLists.txt
    └── main
        ├──CMakeLists.txt
        └── debugging_ex.c
    1 directory, 3 files
    
  4. Download the sdkconfig file from the book repository into the project directory. It can be found here: https://github.com/PacktPublishing/Developing-IoT-Projects-with-ESP32-2nd-edition/blob/main/ch2/debugging_ex/sdkconfig.
  5. Run VSCode and open the debugging_ex directory.
  6. In the VSCode IDE, rename main/main.c to main/main.cpp and edit it to have the following code inside:
    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    void my_func(void)
    {
        int j = 0;
        ++j;
    }
    extern "C" void app_main()
    {
        int i = 0;
        while (1)
        {
            vTaskDelay(pdMS_TO_TICKS(1000));
            ++i;
            my_func();
        }
    }
    
  7. Update the main/CMakeLists.txt file with the following content:
    idf_component_register(SRCS "debugging_ex.cpp" INCLUDE_DIRS ".")
    
  8. After these changes, we should have the following directory structure:
    $ tree
    .
    ├── CMakeLists.txt
    ├── main
    │   ├── CMakeLists.txt
    │   └── debugging_ex.cpp
    └── sdkconfig
    1 directory, 4 files
    
  9. We need to enable the debug options in the root CMakeLists.txt file. Edit it and set its content as the following:
    cmake_minimum_required(VERSION 3.16.0)
    include($ENV{IDF_PATH}/tools/cmake/project.cmake)
    project(debugging_ex)
    idf_build_set_property(COMPILE_OPTIONS "-O0" "-ggdb3" "-g3" APPEND)
    
  10. In the terminal, build the application by running idf.py:
    $ idf.py build
    Executing action: all (aliases: build)
    <more logs>
    Creating esp32s3 image...
    Merged 2 ELF sections
    Successfully created esp32s3 image.
    <more logs>
    
  11. See that the idf.py script has generated the application binary under the build directory:
    $ ls build/*.bin
    build/debugging_ex.bin
    
  12. Run the following command to see the basic size information of the application:
    $ idf.py size
    <some logs>
    Total sizes:
    Used static IRAM:   87430 bytes ( 274810 remain, 24.1% used)
          .text size:   86403 bytes
       .vectors size:    1027 bytes
    Used stat D/IRAM:   13941 bytes ( 158987 remain, 8.1% used)
          .data size:   11389 bytes
          .bss  size:    2552 bytes
    Used Flash size :  153979 bytes
          .text     :  113547 bytes
          .rodata   :   40176 bytes
    Total image size:  252798 bytes (.bin may be padded larger)
    
  13. Flash the application on the devkit (if flashing fails with a port error, just reverse the D+/D- connections of the devkit. This simple change will probably solve the problem):
    $ idf.py flash
    Executing action: flash
    Serial port /dev/ttyACM0
    Connecting...
    Detecting chip type... ESP32-S3
    <more logs>
    Leaving...
    Hard resetting via RTS pin...
    Done
    
  14. We now have an application running on the devkit, ready for debugging. Run a GDB server with the following command (idf.py will start an OpenOCD process for this):
    $ idf.py openocd --openocd-commands "-f board/esp32s3-builtin.cfg"
    Executing action: openocd
    OpenOCD started as a background task 477341
    Executing action: post_debug
    Open On-Chip Debugger v0.11.0-esp32-20221026 (2022-10-26-14:47)
    Licensed under GNU GPL v2
    <more logs> 
    
  15. Start another ESP-IDF command-line terminal as we did in step 1 and change the current directory to the project root directory.
  16. Run the following command to start a GDB client. It will open a web-based GUI in your default browser:
    $ idf.py gdbgui
    Executing action: gdbgui
    gdbgui started as a background task 476131
    

The idf.py script is the single point of contact to manage an ESP-IDF project. We can create, build, flash, and debug an application by only using this script. It has more features and we will have many chances to learn and practice those features throughout the book. The ESP-IDF build system documentation provides detailed information about the idf.py script and how it works with cmake to collect all the project components to compile them into an application. Here is the link for the documentation: https://docs.espressif.com/projects/esp-idf/en/v4.4.4/esp32s3/api-guides/build-system.html.

With a debugging session ready on the web GUI, we can now debug the application. The following screenshot shows this GUI.

Figure 2.26: Web-based debugger

The left panel shows the source code that is being debugged. We can set/remove breakpoints by clicking on the row numbers. The right panel shows the current status of the application, including threads, variables, memory, etc. On the top right, the buttons for the debug functions (restart, pause, continue, and step in/out/over) are placed. The debug functions also have keyboard shortcuts to ease the debugging process. Try the following debugging tasks on the GUI:

  • Click on line number 17 to set a breakpoint.
  • Press C (continue) on the keyboard and observe that the local variable i increases every time the execution hits the breakpoint.
  • Try pressing N (next) to run each of the lines consecutively.
  • When the execution comes to my_func, press S (step in) to enter the function. You can exit the function by pressing U (up).

This GUI is enough for an average debugging session and can be used to observe the behavior of the application when necessary. If you need to access other gdb commands, there is also another panel at the bottom where you can type these commands.