[EN] ESP-IDF Ep.2 : Hello World!

This article is a continuation of the installation of ESP-IDF to test code, compile and upload to the ESP32 board to understand the steps of the development of the C programming language on the ESP32 microcontroller board.

(Figure. 1 esp32+OLED)

Let’s start

Go to ~/esp-idf/examples/get-started/hello_world. to use this sample code to get started with programming. You can check the ESP-IDF microcontroller model support installed by the following commands.

(Figure. 2 Check supported models)

From Figure 2 it can be seen that the installed ESP-IDF supports esp32, esp32s2 and esp32c3 microcontrollers. To select the target of the compile program is to set the target with the following command.

idf.py set-target microcontroller’s version

To adjust the microcontroller’s properties, you need to edit the menuconfig page with the following command. You will get a screen as shown in figure 3. In this screen, set the subject of various memory sizes.

idf.py menuconfig

(Figure. 3 menuconfig window)

Edit the code of hello_world_main.c in ~/esp-idf/examples/get-started/hello_world/main as follows.

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <math.h>

#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"

int counter = 0;
float t0, t1;

bool isPrimeNumber(uint16_t x) {
  uint16_t i;
  for (i = 2; i < x; i++) {
    if (x % i == 0) {
      return false;
    }
  }
  if (i == x)
    return true;
  return false;
}

void testPrimeNumber(uint16_t maxN) {
  t0 = esp_timer_get_time()/1000.0;
  for (uint16_t n = 2; n < maxN; n++) {
    if (isPrimeNumber(n)) {
      counter++;
    }
  }
  t1 = esp_timer_get_time()/1000.0;
}

void app_main(void)
{  
    testPrimeNumber(2000);
    printf("Found %d in %f milliseconds.\n", counter, fabs(t1-t0)); 
}

The next step is to compile, go back to ~/esp-idf/examples/get-started/hello_world. and proceed as follows.

idf.py build

An example of commands is as follows.

$ idf.py build
Executing action: all (aliases: build)
Running ninja in directory /home/cid/esp-idf/examples/get-started/hello_world/build
Executing "ninja all"...
[0/1] Re-running CMake...
-- Building ESP-IDF components for target esp32
-- Project sdkconfig file /home/cid/esp-idf/examples/get-started/hello_world/sdkconfig
-- App "hello-world" version: v4.4-dev-1594-g1d7068e4b-dirty
-- Adding linker script /home/cid/esp-idf/components/esp_rom/esp32/ld/esp32.rom.ld
-- Adding linker script /home/cid/esp-idf/components/esp_rom/esp32/ld/esp32.rom.api.ld
-- Adding linker script /home/cid/esp-idf/components/esp_rom/esp32/ld/esp32.rom.libgcc.ld
-- Adding linker script /home/cid/esp-idf/components/esp_rom/esp32/ld/esp32.rom.newlib-data.ld
-- Adding linker script /home/cid/esp-idf/components/esp_rom/esp32/ld/esp32.rom.syscalls.ld
-- Adding linker script /home/cid/esp-idf/components/esp_rom/esp32/ld/esp32.rom.newlib-funcs.ld
-- Adding linker script /home/cid/esp-idf/components/esp_rom/esp32/ld/esp32.rom.newlib-time.ld
-- Adding linker script /home/cid/esp-idf/examples/get-started/hello_world/build/esp-idf/esp32/esp32_out.ld
-- Adding linker script /home/cid/esp-idf/components/esp32/ld/esp32.project.ld.in
-- Adding linker script /home/cid/esp-idf/components/esp32/ld/esp32.peripherals.ld
-- Components: app_trace app_update asio bootloader bootloader_support bt cbor cmock coap console cxx driver efuse esp-tls esp32 esp_adc_cal esp_common esp_eth esp_event esp_gdbstub esp_hid esp_http_client esp_http_server esp_https_ota esp_https_server esp_hw_support esp_ipc esp_lcd esp_local_ctrl esp_netif esp_phy esp_pm esp_ringbuf esp_rom esp_serial_slave_link esp_system esp_timer esp_websocket_client esp_wifi espcoredump esptool_py expat fatfs freemodbus freertos hal heap idf_test jsmn json libsodium log lwip main mbedtls mdns mqtt newlib nghttp nvs_flash openssl openthread partition_table perfmon protobuf-c protocomm pthread sdmmc soc spi_flash spiffs tcp_transport tcpip_adapter tinyusb ulp unity vfs wear_levelling wifi_provisioning wpa_supplicant xtensa
-- Component paths: /home/cid/esp-idf/components/app_trace /home/cid/esp-idf/components/app_update /home/cid/esp-idf/components/asio /home/cid/esp-idf/components/bootloader /home/cid/esp-idf/components/bootloader_support /home/cid/esp-idf/components/bt /home/cid/esp-idf/components/cbor /home/cid/esp-idf/components/cmock /home/cid/esp-idf/components/coap /home/cid/esp-idf/components/console /home/cid/esp-idf/components/cxx /home/cid/esp-idf/components/driver /home/cid/esp-idf/components/efuse /home/cid/esp-idf/components/esp-tls /home/cid/esp-idf/components/esp32 /home/cid/esp-idf/components/esp_adc_cal /home/cid/esp-idf/components/esp_common /home/cid/esp-idf/components/esp_eth /home/cid/esp-idf/components/esp_event /home/cid/esp-idf/components/esp_gdbstub /home/cid/esp-idf/components/esp_hid /home/cid/esp-idf/components/esp_http_client /home/cid/esp-idf/components/esp_http_server /home/cid/esp-idf/components/esp_https_ota /home/cid/esp-idf/components/esp_https_server /home/cid/esp-idf/components/esp_hw_support /home/cid/esp-idf/components/esp_ipc /home/cid/esp-idf/components/esp_lcd /home/cid/esp-idf/components/esp_local_ctrl /home/cid/esp-idf/components/esp_netif /home/cid/esp-idf/components/esp_phy /home/cid/esp-idf/components/esp_pm /home/cid/esp-idf/components/esp_ringbuf /home/cid/esp-idf/components/esp_rom /home/cid/esp-idf/components/esp_serial_slave_link /home/cid/esp-idf/components/esp_system /home/cid/esp-idf/components/esp_timer /home/cid/esp-idf/components/esp_websocket_client /home/cid/esp-idf/components/esp_wifi /home/cid/esp-idf/components/espcoredump /home/cid/esp-idf/components/esptool_py /home/cid/esp-idf/components/expat /home/cid/esp-idf/components/fatfs /home/cid/esp-idf/components/freemodbus /home/cid/esp-idf/components/freertos /home/cid/esp-idf/components/hal /home/cid/esp-idf/components/heap /home/cid/esp-idf/components/idf_test /home/cid/esp-idf/components/jsmn /home/cid/esp-idf/components/json /home/cid/esp-idf/components/libsodium /home/cid/esp-idf/components/log /home/cid/esp-idf/components/lwip /home/cid/esp-idf/examples/get-started/hello_world/main /home/cid/esp-idf/components/mbedtls /home/cid/esp-idf/components/mdns /home/cid/esp-idf/components/mqtt /home/cid/esp-idf/components/newlib /home/cid/esp-idf/components/nghttp /home/cid/esp-idf/components/nvs_flash /home/cid/esp-idf/components/openssl /home/cid/esp-idf/components/openthread /home/cid/esp-idf/components/partition_table /home/cid/esp-idf/components/perfmon /home/cid/esp-idf/components/protobuf-c /home/cid/esp-idf/components/protocomm /home/cid/esp-idf/components/pthread /home/cid/esp-idf/components/sdmmc /home/cid/esp-idf/components/soc /home/cid/esp-idf/components/spi_flash /home/cid/esp-idf/components/spiffs /home/cid/esp-idf/components/tcp_transport /home/cid/esp-idf/components/tcpip_adapter /home/cid/esp-idf/components/tinyusb /home/cid/esp-idf/components/ulp /home/cid/esp-idf/components/unity /home/cid/esp-idf/components/vfs /home/cid/esp-idf/components/wear_levelling /home/cid/esp-idf/components/wifi_provisioning /home/cid/esp-idf/components/wpa_supplicant /home/cid/esp-idf/components/xtensa
-- Configuring done
-- Generating done
-- Build files have been written to: /home/cid/esp-idf/examples/get-started/hello_world/build
[2/7] Performing build step for 'bootloader'
[0/1] Re-running CMake...
-- Building ESP-IDF components for target esp32
-- Project sdkconfig file /home/cid/esp-idf/examples/get-started/hello_world/sdkconfig
-- Adding linker script /home/cid/esp-idf/components/esp32/ld/esp32.peripherals.ld
-- Adding linker script /home/cid/esp-idf/components/esp_rom/esp32/ld/esp32.rom.ld
-- Adding linker script /home/cid/esp-idf/components/esp_rom/esp32/ld/esp32.rom.api.ld
-- Adding linker script /home/cid/esp-idf/components/esp_rom/esp32/ld/esp32.rom.libgcc.ld
-- Adding linker script /home/cid/esp-idf/components/esp_rom/esp32/ld/esp32.rom.newlib-funcs.ld
-- Adding linker script /home/cid/esp-idf/components/bootloader/subproject/main/ld/esp32/bootloader.ld
-- Adding linker script /home/cid/esp-idf/components/bootloader/subproject/main/ld/esp32/bootloader.rom.ld
-- Components: bootloader bootloader_support efuse esp32 esp_common esp_hw_support esp_rom esp_system esptool_py freertos hal log main micro-ecc newlib partition_table soc spi_flash xtensa
-- Component paths: /home/cid/esp-idf/components/bootloader /home/cid/esp-idf/components/bootloader_support /home/cid/esp-idf/components/efuse /home/cid/esp-idf/components/esp32 /home/cid/esp-idf/components/esp_common /home/cid/esp-idf/components/esp_hw_support /home/cid/esp-idf/components/esp_rom /home/cid/esp-idf/components/esp_system /home/cid/esp-idf/components/esptool_py /home/cid/esp-idf/components/freertos /home/cid/esp-idf/components/hal /home/cid/esp-idf/components/log /home/cid/esp-idf/components/bootloader/subproject/main /home/cid/esp-idf/components/bootloader/subproject/components/micro-ecc /home/cid/esp-idf/components/newlib /home/cid/esp-idf/components/partition_table /home/cid/esp-idf/components/soc /home/cid/esp-idf/components/spi_flash /home/cid/esp-idf/components/xtensa
-- Configuring done
-- Generating done
-- Build files have been written to: /home/cid/esp-idf/examples/get-started/hello_world/build/bootloader
[1/1] cd /home/cid/esp-idf/examples/get-started/hello_world/build/bootloader/esp-idf/esptool_py && /home/cid/.espressif/python_env/idf4.4_py3.8_env/bin/python /home/cid/esp-idf/components/partition_table/check_sizes.py --offset 0x8000 bootloader 0x1000 /home/cid/esp-idf/examples/get-started/hello_world/build/bootloader/bootloader.bin
Bootloader binary size 0x60e0 bytes. 0xf20 bytes (16%) free.
[4/5] Generating binary image from built executable
esptool.py v3.1-dev
Merged 2 ELF sections
Generated /home/cid/esp-idf/examples/get-started/hello_world/build/hello-world.bin
[5/5] cd /home/cid/esp-idf/examples/get-started/hello_world/bu...esp-idf/examples/get-started/hello_world/build/hello-world.bin
hello-world.bin binary size 0x280f0 bytes. Smallest app partition is 0x100000 bytes. 0xd7f10 bytes (84%) free.

Project build complete. To flash, run this command:
/home/cid/.espressif/python_env/idf4.4_py3.8_env/bin/python ../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 460800 --before default_reset --after hard_reset --chip esp32  write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/hello-world.bin
or run 'idf.py -p (PORT) flash'

When the build passes, flash the esp32 by specifying the correct USB port. For example, JarutEx team found the USB port of the ESP32 at /dev/ttyUSB0 so it works as follows and gets the result as shown in Figure 4.

idf.py -p /dev/ttyUSB0 flash

(Figure. 4 Result when flash complete)

When running the program by looking at the Serial Monitor of Arduino IDE, it will show the result as in Figure 5.

(Figure. 5 Result of the program)

Because the normal value of the clock signal is set to 160MHz, but esp32 supports up to 240MHz, so if you try to change it higher by modifying it with idf.py menuconfig to enter the configuration screen as in Figure 6, go to the Component config will be as shown in Figure 7 after that go to ESP32-specific to adjust the clock frequency to 240MHz as shown in Figure 8, the last is to record with the S key, the report is as shown in Figure 9 and exit the program by pressing the Q key. The result of the operation is as shown in Figure 10.

(Figure. 6 Selecting Component config)
(Figure. 7 List of ESP32-specific)
(Figure. 8 List of CPU frequency that needs to be adjusted to 240MHz.)
(Figure. 9 Saving confirmation screen when pressing the S key.)
(Figure. 10 The result when the clock frequency is set to 240MHz.)

If you want to use ESP-IDF as a monitoring tool without using any other program, you can do it with the following command and exit the monitor with Ctrl+]

idf.py -p พอร์ตสื่อสาร monitor

Compared to the code written in Python of Micropython, it is shown in Figure 11.

(Figure. 11 Example of finding Prime Number in Python.)

When modifying the code from the previous article Serial.begin( 115200 ); and upload it to ESP32, the result of the operation will be as shown in Figure 12

(Figure. 12 The result obtained by running code written from Arduino.)

When changed to testPrimeNumber(40000); The output for the ESP32 board is shown in Figure 13, stm32f103c8 in Figure 14, and Figure 15, and 16 are the output when used with the ESP-IDF used with the esp32 and esp32s2 respectively.

(Figure. 13 The result of esp32 when running 40,000 cycles.)
(Figure. 14 Result of stm32f103 when running 40,000 cycles)
(Figure. 15 Result of esp32 when running 40,000 cycles on ESP-IDF.)
(Figure. 16 Result of esp32s2 when running 40,000 cycles on ESP-IDF)

Conclusion

From this article, you will find that ESP-IDF’s C programming language is faster than Micropython’s Python, but the development tools and writing process are more procedural and require more tools. The espressive has improved by using Eclipse as an IDE to include all functions. But running on the Windows operating system, as shown in Figure 17, making it more convenient for developers to use. In addition, when comparing performance with coding via Arduino, ESP-IDF is faster. But there is also the issue of libraries that Arduino is more versatile. Hopefully, this article is enough to provide an alternative for those who are interested.

(Figure. 17 ESP-IDF+Eclipse on Windows)

If you want to discuss or talk with us, feel free to comments below!

(C) 2020-2021, By Jarut Busarathid and Danai Jedsadathitikul
Updated 2021-10-10