Electronics

How to fix ESP32 Last error reported from esp-tls: 0x8008

Problem:

While trying to use TLS such as MQTTS or HTTPS on the ESP32, you see an error message like

E (333183) MQTT_CLIENT: mqtt_message_receive: transport_read() error: errno=119
[328153][E][MyMQTT.cpp:80] log_error_if_nonzero(): [MQTT] Last error reported from esp-tls: 0x8008
E (333191) MQTT_CLIENT: mqtt_process_receive: mqtt_message_receive() returned -1

Solution:

0x8008 means  ESP_ERR_ESP_TLS_TCP_CLOSED_FIN. In other words, a TCP connection had been established successfully but unexpectedly, the connection has been closed by the server.

This is often caused by the server software crashing, or restarting in some way. When a server process is terminated, the operating system will cleanup after it and close all connections.

In order to debug the issue, start by checking the log of your server message and/or system log to check for unintended crashes. If that doesn’t help, it’s sometimes helpful to packet capture the communication between the ESP32 and the server. You can also write a software script doing the same communication with the server as the ESP32. This will often allow you to try out changes much more easily than on the microcontroller and observe what’s happening using a debugger.

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

How to fix ESP32 TRANSPORT_WS: Sec-WebSocket-Accept not found

Problem:

Your ESP32 running a MQTT client is printing the following error messages:

E (285025) TRANSPORT_WS: Sec-WebSocket-Accept not found
E (285025) MQTT_CLIENT: Error transport connect

Solution:

You’re using MQTT over websockets (ws:// or wss://) but on the given MQTT URL, no MQTT-over-websocket server is running.

This is often caused by using a wrong URL (possibly the URL is missing the path), but it might also be caused by a misconfiguraton of the server or the reverse proxy.

It’s often best to try using a software websocket client to test the correct settings.

Posted by Uli Köhler in ESP8266/ESP32, MQTT, Networking

How to fix ESP32 Last error reported from esp-tls: 0x8001

Problem:

While trying to use TLS such as MQTTS or HTTPS on the ESP32, you see an error message like

[MQTT] Last error reported from esp-tls: 0x8001

Solution:

0x8001 means ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME. In other words, the ESP32 is unable to resolve the hostname of the host you’re trying to connect to using DNS.

Typically, this is a DNS problem, so check the DNS settings of your network. Also check if the ESP32 has a correct DNS server set – for example, if the ESP32 has 0.0.0.0 as a DNS server, this explains why it isn’t able to resolve the hostname.

Sometimes this issue is also caused by the hostname not existing at all (i.e. there is no DNS entry for that hostname). You can easily check this by resolving the hostname you’re trying to connect

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

How to compute voltage divider output voltage using Python

You can use the UliEngineering library to compute the output voltage of a voltage divider by its top resistor, bottom resistor and its input voltage:

from UliEngineering.Electronics.VoltageDivider import *

# Voltage divider with 1MΩ and 150kΩ resistors & 24V input voltage
print(voltage_divider_voltage("1MΩ", "150kΩ", "24V")) # Print 3.1304347826086953

You can also directly format this voltage using auto_format():

from UliEngineering.EngineerIO import auto_format

# Print formatted as volts
print(auto_format(voltage_divider_voltage, "1MΩ", "150kΩ", "24V")) # Prints "3.13 V"
Posted by Uli Köhler in Electronics, Python

Where to find cheap MOSFETs?

As for most components, LCSC has the best prices if you want to order more than just a few MOSFETs (due to the high shipping fees)

Small-signal MOSFETs

  • N-Channel 2N7002K 60V 300mA 2.2Ohm @0.008€@3kpc = 24€/reel

Power FETs (small package)

These are mostly SOT23-3, so the don’t provide good power dissipation. These are mostly used for switching voltages on and off and not for linear applications.

Posted by Uli Köhler in Components, Electronics

Where to find cheap SMA TVS diodes (SMAJxxA)?

As for most parts, if you order more than just a few, LCSC is the cheapest source of these components (however, you need to consider the rather expensive shipping costs).

The prices given are for budgetary purposes only.

Unidirectional diodes

Posted by Uli Köhler in Components, Electronics

Selectable 3.3V / 5V / 12V supply (with KiCAD schematic)

This example shows you how to make a selectable output voltage (3.3V / 5V / 12V) switching voltage regulator using the AP63200WU (2A current capability – but the approach works with any adjustable voltage regulator). The voltage can be selected using a three-way jumper.

The main trick here is to change the feedback network when selecting the output voltage.

One major mistake is to design the regulator so it doesn’t operate safely when the jumper is removed (for example, the output voltage goes to 12V or even up to the input voltage when no jumper is connected). In our circuit, when no jumper is used, the output voltage is 3.3V. We achieve this by using selectable (& optional) resistors in parallel to the bottom feedback resistor. The 3.3V feedback resistor is fixed.
Using a selectable-in-parallel-to-bottom-FB-resistor topology will always guarantee that the lowest output voltage will be selected when none of the optional parallel resistors are active.

Download this schematic as KiCAD file

Posted by Uli Köhler in Electronics, KiCAD

How to compute MRI Larmor frequency for a given magnetic field using Python

You can use the UliEngineering library to compute the larmor frequency for a given magnetic field in Tesla using Python.

from UliEngineering.Physics.MagneticResonance import *

# Default is to compute the Larmor frequency for hydrogen (H1 nucleus)
# Print frequency [Hz] for a 1.0 T magnetic field
print(larmor_frequency(1.0)) # Prints 42576384.74

# Compute for another nucleus like He3
print(larmor_frequency(1.0, nucleus_larmor_frequency=NucleusLarmorFrequency.He3)) # Prints 32434099.42

You can also directly format this frequency using auto_format():

# Format frequency
from UliEngineering.EngineerIO import auto_format
print(auto_format(larmor_frequency, 1.0)) # Prints "42.6 MHz"
Posted by Uli Köhler in Medical devices, Physics, Python

What is the MRI excitation frequency for 1.5T and 3T MRI scanners?

The base excitation frequency (for hydrogen) is:

  • 63.87 MHz for 1.5 Tesla MRI scanners
  • 127.74 MHz for 3 Tesla MRI scanners

Note that the excitation frequency is not exactly one frequency but varies spatially based on the gradient field strength.

You can calculate the excitation frequency using

Excitation frequency [MHz] = 42.58 MHz/T * [magnetic field strength in Tesla]

For more info, see mriquestions.com

Posted by Uli Köhler in Electronics, Medical devices

Which pins on the ESP32-S2 are DAC outputs?

Only two pins on the ESP32-S2 are capable of being DAC outputs:

  • GPIO23 is DAC_1
  • GPIO24 is DAC_2

Source: ESP32-S2 datasheet

Posted by Uli Köhler in ESP8266/ESP32

How to output 2.048MHz clock on any pin on the ESP32

You can use the LEDC timer (typically used for PWM) to output a 50% duty cycle clock with 3.3V P-P amplitude on any output-capable GPIO pin.

First,

#include <driver/ledc.h>

then setup the timer. You only need to do this once on startup, no code in your loop function is required.

/**
 * Setup 2.048MHz clock output on GPIO33
 */
ledc_timer_config_t ledc_timer = {
    .speed_mode = LEDC_HIGH_SPEED_MODE,
    .bit_num    = LEDC_TIMER_2_BIT,
    .timer_num  = LEDC_TIMER_0,
    .freq_hz    = 2048000
};
ledc_channel_config_t ledc_channel = {
    .gpio_num   = GPIO_NUM_33,
    .speed_mode = LEDC_HIGH_SPEED_MODE,
    .channel    = LEDC_CHANNEL_0,
    .timer_sel  = LEDC_TIMER_0,
    .duty       = 2
};
ledc_timer_config(&ledc_timer);
ledc_channel_config(&ledc_channel);

 

Posted by Uli Köhler in ESP8266/ESP32

How does the ESP32 DAC cosine generator waveform look on an Oscilloscope?

The ESP32 DAC has a built-in cosine waveform generator. Even though it’s an 8-bit DAC, the waveform looks pretty clean.

For an example on how to generate this wavefrm in firmware, see How to use the ESP32 DAC sine/cosine waveform generator using Arduino / PlatformIO

Posted by Uli Köhler in Electronics, ESP8266/ESP32

How to use the ESP32 DAC sine/cosine waveform generator using Arduino / PlatformIO

The ESP32 and its derivatives such as the ESP32-S2 have a built-in sine/cosine waveform generator for the built-in 8-bit DAC.

Using it requires ESP-IDF v5.1+ (see the official example). Using it with Arduino is slightly harder, since the stable version of the arduino-esp32 framework at the time of writing this post is based on ESP-IDF v4.4 which does not provide the DAC cosine generator API.

Therefore, we have to explicitly specify the arduino-espressif32 version (git commit) in platformio.ini:

[env:esp32dev]
platform = espressif32
# Commit f9cddfde697b659b9e818ec514f1505d2bd4a8ae is branch esp-idf-v5.1-libs @2022-02-01
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#f9cddfde697b659b9e818ec514f1505d2bd4a8ae
board = esp32dev
framework = arduino

The example main source code is pretty simple:

#include <Arduino.h>
#include <driver/dac_cosine.h>

void setup() {
    dac_cosine_handle_t chan0_handle;
    dac_cosine_config_t cos0_cfg = {
        .chan_id = DAC_CHAN_1, // GPIO26
        .freq_hz = 1000,
        .clk_src = DAC_COSINE_CLK_SRC_DEFAULT,
        .atten = DAC_COSINE_ATTEN_DEFAULT,  
        .phase = DAC_COSINE_PHASE_0,  
        .offset = 0,
        //.flags.force_set_freq = false,
    };
    ESP_ERROR_CHECK(dac_cosine_new_channel(&cos0_cfg, &chan0_handle));
    ESP_ERROR_CHECK(dac_cosine_start(chan0_handle));
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(1000);
}

If you want to see how the generated waveform looks on an oscilloscope, see How does the ESP32 DAC cosine generator waveform look on an Oscilloscope?

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

What is the the IMPD bit for the MAX11200EEE+ / MAX112100EEE+?

On the MAX11200EEE+ and the MAX112100EEE+, bit 3 of the command byte is named IMPD but this bit is never described in detail in the datasheet.

The meaning of this bit is Immediate power-down. When you set it to 1, the IC will switch to power-down mode. This is evidenced by the power-down example in Table 8 in the datasheet.

Posted by Uli Köhler in Components, Electronics

What is the correct SPI mode for MAX11200EEE+ / MAX112100EEE+?

The MAX11200EEE+ and the MAX112100EEE+ operate using SPI Mode 0Therefore, CPHA=0 & CPOL=0.

For more information, see the datasheet.

Posted by Uli Köhler in Components, Electronics

Minimal PlatformIO ESP32 ArduinoOTA example

Based on our Minimal PlatformIO ESP8266 ArduinoOTA example, this is a minimal starting point for your ESP32 program running ArduinoOTA.

#include <Arduino.h>
#include <WiFi.h>
#include <ArduinoOTA.h>


void setup() {
  Serial.begin(115200);
  /**
   * Connect to Wifi
   */
  WiFi.begin("MyWifi", "abc123abc");
  uint32_t notConnectedCounter = 0;
  while (WiFi.status() != WL_CONNECTED) {
      delay(100);
      Serial.println("Wifi connecting...");
      notConnectedCounter++;
      if(notConnectedCounter > 150) { // Reset board if not connected after 15s
          Serial.println("Resetting due to Wifi not connecting...");
          ESP.restart();
      }
  }
  Serial.print("Wifi connected, IP address: ");
  Serial.println(WiFi.localIP());
  /**
   * Enable OTA update
   */
  ArduinoOTA.begin();
}

void loop() {
  // Check for over the air update request and (if present) flash it
  ArduinoOTA.handle();
}

platformio.ini

Add the following section to your platformio.ini to enable flashing via OTA as well as flashing via serial:

[env:OTA]
extends = env:esp32dev
upload_protocol = espota
upload_port = 10.19.50.80
upload_flags = --host_port=55910
Posted by Uli Köhler in ESP8266/ESP32, PlatformIO

STM32 HAL equivalent of Arduino millis()

The equivalent of Arduino’s millis() function when using the STM32 HAL is

HAL_GetTick()

The ticks occur once every millisecond, so this will also give you a millisecond timer that will overflow after some time equivalently to how millis() overflows.

Posted by Uli Köhler in Arduino, STM32

How to print WiFi MAC address to serial on ESP32 (Arduino)?

It’s as simple as

Serial.println(WiFi.macAddress());

Full example

#include <Arduino.h>

void setup() {
    Serial.begin(115200);
    Serial.println(WiFi.macAddress());
}

void loop() {
    // ...
}

 

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

How to get WiFi MAC address as binary on the ESP32 (Arduino)?

uint8_t mac[6];
WiFi.macAddress(mac);

 

Posted by Uli Köhler in Arduino, ESP8266/ESP32, Networking

VirtualHere USB server & systemd autostart on Raspberry Pi in 15 seconds

The following script will download the VirtualHere USB server for the Raspberry Pi (generic version for ARM) and create a systemd service called vhusbd.service.

In case you are not using the Raspberry Pi, see the VirtualHere server download page to obtain.

#!/bin/bash
# This script installs and enables/starts the VirtualHere USB server
wget -O /usr/bin/vhusbd https://www.virtualhere.com/sites/default/files/usbserver/vhusbdarm
chmod a+x /usr/bin/vhusbd

cat >/etc/systemd/system/vhusbd.service <<EOF
[Unit]
Description=vhusbd
After=network-online.target

[Service]
Restart=always
User=root
Group=root
ExecStart=/usr/bin/vhusbd

[Install]
WantedBy=multi-user.target
EOF

# Enable and start service
systemctl enable --now vhusbd.service

 

Posted by Uli Köhler in Embedded, Raspberry Pi