Electronics

ESP-IDF minimal Wifi client hello world example using PlatformIO

This basic example showcases how to use PlatformIO with ESP-IDF only (no Arduino) to connect to Wifi in station mode and print Hello world in a loop. It is based on the basic Hello World example from PlatformIO ESP32 with ESP-IDF minimal C++ example:

#include <cstdio>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

#include <esp_wifi.h>
#include <esp_log.h>
#include <nvs_flash.h>
#include <esp_netif.h>
#include <esp_event.h>


extern "C" {
    void app_main(void);
}


static void NetworkEventHandler(void* arg, esp_event_base_t event_base,
                          int32_t event_id, void* event_data) {
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        esp_wifi_connect();
        ESP_LOGI("wifi", "Retrying to connect to Wifi...");
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI("wifi", "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
    }
}

void InitNVS() {
    // Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
}

void InitWifi() {

    // Initialize TCP/IP network interface (required for Wi-Fi)
    ESP_ERROR_CHECK(esp_netif_init());

    // Initialize the event loop
    ESP_ERROR_CHECK(esp_event_loop_create_default());    
    esp_netif_create_default_wifi_sta();

    // Initialize Wi-Fi
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    // Set Wi-Fi to station mode
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));

    // Configure the Wi-Fi connection
    wifi_config_t wifi_config = {
        .sta = {
            .ssid = "MyWifi",
            .password = "mypassword"
        }
    };
    // Register event handler
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &NetworkEventHandler,
                                                        NULL,
                                                        NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &NetworkEventHandler,
                                                        NULL,
                                                        NULL));

    // Set Wi-Fi configuration and start Wi-Fi
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());
}

void app_main() {
    InitNVS();
    InitWifi();

    while(true) {
        printf("Hello PlatformIO!\n");
        // Wait for one second
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = espidf
monitor_speed = 115200

All sdkconfig settings have been left at their respective defaults.

Posted by Uli Köhler in C/C++, ESP8266/ESP32, PlatformIO

How to fix ESP-IDF error: cannot convert ‘esp_interface_t’ to ‘wifi_interface_t’

Problem:

While trying to  compile your ESP-IDF app using code such as

ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));

you see an error message such as

src/main.cpp:76:41: error: cannot convert 'esp_interface_t' to 'wifi_interface_t'
   76 |     ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
      |                                         ^~~~~~~~~~~~~~~
      |                                         |
      |                                         esp_interface_t

Solution:

Instead of ESP_IF_WIFI_STA, use WIFI_IF_STA (which has the correct type):

ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32

PlatformIO ESP32 with ESP-IDF minimal C++ example

By default, when you initialize a PlatformIO ESP-IDF project, it will generate main.c – not a C++ but a pure C file

This minimal example instead uses main.cpp (you can just rename your main.c – see How to use C++ main.cpp with PlatformIO on ESP32 / esp-idf for a detailed list of steps to do).

#include <cstdio>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

extern "C" {
    void app_main(void);
}

void app_main() {
    while(true) {
        printf("Hello PlatformIO!\n");
        // Wait for one second
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32, PlatformIO

How to use C++ main.cpp with PlatformIO on ESP32 / esp-idf

When you are using PlatformIO to compile your firmware, it is easily possible to use a C++ main.cpp instead of the pure C main.c by just renaming main.c to main.cpp

However, you also need to properly declary app_main(). After the #include section of your main.cpp (or at the top of the file if you don’t have an #include section yet), add this code:

extern "C" {
    void app_main(void);
}

This will tell the compiler that app_main() is a C function, not a C++ function.

Full main.cpp example

#include <cstdio>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

extern "C" {
    void app_main(void);
}

void app_main() {
    while(true) {
        printf("Hello PlatformIO!\n");
        // Wait for one second
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32, PlatformIO

How to fix ESP32 error: ‘portTICK_PERIOD_MS’ was not declared in this scope

Problem:

While trying to compile your ESP-IDF firmware (with or without PlatformIO), you see an error message such as

src/main.cpp:13:27: error: 'portTICK_PERIOD_MS' was not declared in this scope
   13 |         vTaskDelay(1000 / portTICK_PERIOD_MS);

Solution:

Include FreeRTOS by adding the following lines to the top of the file where the error occured (src/main.cpp in this example):

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

 

Posted by Uli Köhler in ESP8266/ESP32, FreeRTOS, PlatformIO

How to fix ESP32 error: ‘vTaskDelay’ was not declared in this scope

Problem:

While trying to compile your ESP-IDF firmware (with or without PlatformIO), you see an error message such as

src/main.cpp:13:9: error: 'vTaskDelay' was not declared in this scope
   13 |         vTaskDelay(1000 / portTICK_PERIOD_MS);

Solution:

Include FreeRTOS by adding the following lines to the top of the file where the error occured (src/main.cpp in this example):

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

 

Posted by Uli Köhler in ESP8266/ESP32, FreeRTOS, PlatformIO

What pitch do Molex Mini-Fit Jr connectors have?

According to the Molex Website, the entire Mini-Fit family has a pin pitch of 4.2mm

 

Posted by Uli Köhler in Components

JST VH connector part numbers & LCSC links

Prices shown are for budgetary purposes only. Check the LCSC page or other distributors for up-to-date pricing information.

Straight THT connector

  • 2 positions: B2P-VH 0,0343€/pc @100pcs
  • 3 positions: B3P-VH 0,0473€/pc @100pcs
  • 4 positions: B4P-VH 0,0719€/pc @100pcs
  • 5 positions: B5P-VH 0,1034€/pc @100pcs
  • 6 positions: B6P-VH 0,1113€/pc @100pcs
  • 7 positions: B7P-VH 0,1317€/pc @100pcs
  • 8 positions: B8P-VH 0,1165€/pc @100pcs
  • 9 positions: B9P-VH 0,1228€/pc @100pcs
  • 10 positions: B10P-VH0,1368€/pc @100pcs

Right-angled THT connector

Also called side-entry type

  • 2 positions: B2PS-VH 0,0924€/pc @100pcs
  • 3 positions: B3PS-VH 0,119€/pc @100pcs
  • 4 positions: B4PS-VH 0,1432€/pc @100pcs
  • 5 positions: B5PS-VH 0,1779€/pc @100pcs
  • 6 positions: B6PS-VH 0,1991€/pc @100pcs
  • 7 positions: B7PS-VH 0,2323€/pc @100pcs
  • 8 positions: B8PS-VH 0,2982€/pc @100pcs
  • 9 positions: B9PS-VH 0,1837€/pc @100pcs
  • 10 positions: B10PS-VH 0,1862€/pc @100pcs

Connector housing

  • 2 positions: VHR-2N  0.0315€/pc @100pcs
  • 3 positions: VHR-3N  0.0298€/pc @100pcs
  • 4 positions: VHR-4N 0.0369€/pc @100pcs
  • 5 positions: VHR-5N  0.0388€/pc @100pcs
  • 6 positions: VHR-6N  0.0437€/pc @100pcs
  • 7 positions: VHR-7N  0.0477€/pc @100pcs
  • 8 positions: VHR-8N  0.0575€/pc @100pcs
  • 9 positions: VHR-9N  0.0692€/pc @100pcs
  • 10 positions: VHR-10N  0.094€/pc @100pcs
  • 11 positions: VHR-11N  0.144€/pc @100pcs
Posted by Uli Köhler in Components, Electronics

Where to find 3D models for JST-VH connectors?

You can find 3D models as 3D-PDF for JST VH connectors on the JST website.

However, in order to obtain STEP or IGES models, you have to look on the jst-mfg.com site.

Also see:

Posted by Uli Köhler in Components, Electronics

How to fix “kicad-cli pcb export step” not exporting component 3D models

Problem:

You are trying to export a 3D STEP model of your PCB using a command such as

kicad-cli pcb export step MyPCB.kicad_pcb

but the resulting STEP file is missing all (or almost all) component models (i.e. only the PCB is exported).

Furthermore, in the output of the command, you can read

Cannot add a VRML model to a STEP file.

for every single component, for example

Add component R6.
Cannot add a VRML model to a STEP file.
Add component R21.
Cannot add a VRML model to a STEP file.
Add component C7.
Cannot add a VRML model to a STEP file.
Add component C16.
Cannot add a VRML model to a STEP file.

Solution:

Add the --subst-models flag to kicad-cli in order to automatically substitute VRML models with STEP models:

kicad-cli pcb export step MyPCB.kicad_pcb --subst-models

After that, all available component models will be exported just like in the viewer.

Posted by Uli Köhler in Electronics, KiCAD

Where to find Trinamic TMC5160 StepStick schematic PDF?

There are multiple manufacturers providing StepStick drivers based on the TMC5160 with open schematics.

One example is Watterott – GitHub link

Posted by Uli Köhler in Electronics

List of JST XH connector MPNs (with LCSC links)

Prices shown are for budgetary purposes only. Check the LCSC page or other distributors for up-to-date pricing information.

Female connector housing (for crimp contacts)

    • 2-pin: XHP-2 0.0158€/pc @100pcs
    • 3-pin: XHP-3 0.0172€/pc @100pcs
    • 4-pin: XHP-4 0.0167€/pc @100pcs
    • 5-pin: XHP-5 0.0182€/pc @100pcs
    • 6-pin: XHP-6 0.0217€/pc @100pcs
    • 7-pin: XHP-7 0.0276€/pc @100pcs
    • 8-pin: XHP-8 0.0266€/pc @100pcs
    • 9-pin: XHP-9 0.028€/pc @100pcs
    • 10-pin: XHP-10 0.0305€/pc @100pcs
    • 11-pin: XHP-11 0.0314€/pc @100pcs
    • 12-pin: XHP-12 0.0452€/pc @100pcs
    • 13-pin: XHP-13 0.0543€/pc @100pcs
    • 14-pin: XHP-14 0.0645€/pc @100pcs
    • 15-pin: XHP-15 0.08€/pc @100pcs Not stocked
    • 16-pin: XHP-16 0.1594€/pc @100pcs
    • 17-pin: XHP-17 Not offered on LCSC
    • 18-pin: XHP-18 Not offered on LCSC
    • 19-pin: XHP-19 Not offered on LCSC
    • 20-pin: XHP-20 0.1581€/pc @100pcs

Male straight through-hole PCB-mount connectors

with lead-free tin finish

Male right-angled (“side-entry”) THT connectors:

with lead-free tin finish

Posted by Uli Köhler in Components

How to read multimeter and paste into Excel spreadsheet cell on hotkey press using Python

The following Python script uses PyVISA / LabInstruments to read a Rigol DM3058(E) multimeter and automatically paste the voltage reading into an open spreadsheet on Shift+Alt+Q press.

First, clone LabInstruments to the current directory using

git clone https://github.com/ulikoehler/LabInstruments.git

Now install the requirements from the following requirements.txt

system_hotkey310
pyperclip
pyvisa
pyvisa-py

and run the script:

#!/usr/bin/env python3
"""
This script allows quick reading of multimeter, automatically pasting the reading
into the current e.g. excel spreadsheet and pressing "Enter" to advance to the next cell.

Press Shift+Alt+Q to read the multimeter and paste the reading into the current cell.
"""
import subprocess
import pyautogui
import time
import re
import pyperclip
import sexpdata
import pyvisa
from LabInstruments.DM3058 import DM3058

import locale
locale.setlocale(locale.LC_NUMERIC, f"{locale.getdefaultlocale()[0]}.utf-8")

rm = pyvisa.ResourceManager()
rm.list_resources()
inst = rm.open_resource('USB0::6833::2500::DM3R245003970::0::INSTR')
multimeter = DM3058(inst)
multimeter.set_speed("S")
multimeter.mode_dc_voltage()


def run():
    voltage = multimeter.read_voltage()
    
    locale_formatted_voltage = locale.format_string("%.5f", voltage, grouping=False)
    print("Voltage: ", locale_formatted_voltage)

    # Copy locale-formatted voltage to clipboard
    pyperclip.copy(locale_formatted_voltage)
    # Paste into cell
    pyautogui.hotkey('ctrl', 'v')
    # Wait for excel
    time.sleep(0.1)
    # Press Enter key to save
    pyautogui.press('enter')

# Register hotkeys
from system_hotkey import SystemHotkey
hk = SystemHotkey()
hk.register(('shift', 'alt', 'q'), callback=lambda x: run())

# Wait for exit
while True:
    time.sleep(10)

 

Posted by Uli Köhler in Electronics, Python

How to generate inverted pulses using the ESP32 RMT module (Arduino & PlatformIO)

In our previous post ESP32 RMT pulse generation minimal example using Arduino & PlatformIO using the RMT peripheral. The pulses have a steady state (off state) of 0V and a pulse voltage of 3.3V.

If we want to generate inverted pulses, we have to invert the level entries in the pulseRMT array:

static const rmt_item32_t pulseRMT[] = {
    {{{
      /*pulse duration=*/100, /*pulse level*/0,
      // After pulse, output 1
      0, 1
    }}},
};

and additionally configure the RMT output when the pulse is finished using

config.tx_config.idle_level = RMT_IDLE_LEVEL_HIGH;
config.tx_config.idle_output_en = true;

This is how the pulse looks like:

Full example:

#include <Arduino.h>
#include <esp_log.h>
#include <driver/rmt.h>

// Output pulse train on D14
constexpr gpio_num_t rmtPin = GPIO_NUM_14;
constexpr rmt_channel_t RMT_TX_CHANNEL = RMT_CHANNEL_0;

static const rmt_item32_t pulseRMT[] = {
    {{{
      /*pulse duration=*/100, /*pulse level*/0,
      // After pulse, output 1
      0, 1
    }}},
};

void setup() {
  Serial.begin(115200);

  rmt_config_t config = RMT_DEFAULT_CONFIG_TX(rmtPin, RMT_TX_CHANNEL);
  config.clk_div = 80; // input clock 80 MHz => output clk 1 MHz
  config.tx_config.idle_level = RMT_IDLE_LEVEL_HIGH;
  config.tx_config.idle_output_en = true;

  ESP_ERROR_CHECK(rmt_config(&config));
  ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));

}

void loop() {
  ESP_ERROR_CHECK(rmt_write_items(RMT_TX_CHANNEL, pulseRMT, sizeof(pulseRMT) / sizeof(rmt_item32_t), true));
  delay(10);
}

 

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200

 

Posted by Uli Köhler in Arduino, C/C++, ESP8266/ESP32, PlatformIO

ESP32 HTTP float query parser with range check example using HumanESPHTTP

Example for HumanESPHTTP

static const httpd_uri_t setPowerHandler = {
    .uri       = "/api/set-power",
    .method    = HTTP_GET,
    .handler   = [](httpd_req_t *request) {
        QueryURLParser parser(request);
        if(parser.HasParameter("power")) {
            std::string power = parser.GetParameter("power");
            // Parse power as float
            float powerFloat;
            try {
              powerFloat = std::stof(power);
            } catch (const std::invalid_argument& e) {
              httpd_resp_set_status(request, "400 Bad Request");
              httpd_resp_set_type(request, "text/plain");
              httpd_resp_sendstr(request, "Error: Invalid argument for power parameter (not a float)!");
              return ESP_OK;
            }
            // Check range
            if(powerFloat < 0.0 || powerFloat > 1.0) {
              httpd_resp_set_status(request, "400 Bad Request");
              httpd_resp_set_type(request, "text/plain");
              httpd_resp_sendstr(request, "Error: Invalid argument for power parameter (not in range 0.0 ... 1.0)!");
              return ESP_OK;
            }
            // TODO: Your code goes here
            // Example code: send back power
            httpd_resp_send_chunk(request, "Power is: ", HTTPD_RESP_USE_STRLEN);
            httpd_resp_send_chunk(request, std::to_string(powerFloat).c_str(), HTTPD_RESP_USE_STRLEN);
            httpd_resp_send_chunk(request, nullptr, 0); // Finished
        } else {
            httpd_resp_set_type(request, "text/plain");
              httpd_resp_set_status(request, "400 Bad Request");
            httpd_resp_sendstr(request, "No 'power' query parameter found!");
        }
        return ESP_OK;
    }
};

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32

ESP32 RMT pulse generation minimal example using Arduino & PlatformIO

The following example will generate 100us pulses every 10ms. The pulses are generated using the RMT peripheral.

#include <Arduino.h>
#include <esp_log.h>
#include <driver/rmt.h>

// Output pulse train on D14
constexpr gpio_num_t rmtPin = GPIO_NUM_14;
constexpr rmt_channel_t RMT_TX_CHANNEL = RMT_CHANNEL_0;


static const rmt_item32_t pulseRMT[] = {
    {{{
      /*pulse duration=*/100, /*pulse level*/1,
      // After pulse, output 0
      0, 0
    }}},
};


void setup() {
  Serial.begin(115200);

  rmt_config_t config = RMT_DEFAULT_CONFIG_TX(rmtPin, RMT_TX_CHANNEL);
  config.clk_div = 80; // input clock 80 MHz => output clk 1 MHz

  ESP_ERROR_CHECK(rmt_config(&config));
  ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));

}

void loop() {
  ESP_ERROR_CHECK(rmt_write_items(RMT_TX_CHANNEL, pulseRMT, sizeof(pulseRMT) / sizeof(rmt_item32_t), true));
  delay(10);
}

 

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200

 

Posted by Uli Köhler in Arduino, C/C++, ESP8266/ESP32, PlatformIO

How to fix unixODBC “Can’t open lib ‘postgresql’: file not found” on Linux

Problem:

When you try to connect to a PostgreSQL database using a ODBC application such as KiCAD (database library connection), you see the following error message:

[unixODBC][Driver Manager]Can't open lib 'postgresql' : file not found

Solution:

First, install the ODBC PostgreSQL driver adapter:

sudo apt -y install odbc-postgresql

Using that driver, you would typically use a driver setting such as

Driver={PostgreSQL Unicode}

 

Posted by Uli Köhler in Databases, KiCAD, Linux

KiCAD PostgreSQL database connection string example

This has been tested on Linux with sudo apt -y install odbc-postgresql:

Driver={PostgreSQL Unicode};Server=127.0.0.1;Port=5432;Username=kicad;Password=abc123;Database=kicad;

 

Posted by Uli Köhler in Databases, KiCAD

What voltage does the KNX TP1 equalization pulse have?

According to the KNX standard, the allowable voltage during the equalization part of a logical 0 transmitted on the bus is between 0V and 13V above the DC voltage or reference voltage, which is typically 30V.

Source: KNX standard: Communication media: Twisted Pair 1, v01.02.02, section 1.1.2, Figure 7, download at my.knx.org

Posted by Uli Köhler in Electronics