PlatformIO

How to read 16-bit I2C register using Arduino Wire library: A minimal example

The following code demonstrates how to read a register that is 2 bytes (16 bits) long over I2C. It will work with almost all I2C devices like EEPROMs, ADCs and others, provided you have the correct. Note that some devices like the LAN9303 have a slightly different addressing scheme or other peculiarities. In my opinion, it’s most efficient to just try out the standard way of reading a register and start from there.

Note that this code does not implement error handling for the sake of simplicity. Additionally, we wait for data using delay() instead of Wire.available(). This is a minimal example so it creates minimal confusion for the reader. We will provide a full example with error handling in a followup post.

Option 1: Reading the register into an uint16_t (recommended)

const uint8_t SLAVE_I2C_ADDRESS = 0b1010;
const uint16_t SLAVE_I2C_REGISTER_ADDRESS = 0x50;

Wire.beginTransmission(SLAVE_I2C_ADDRESS);
Wire.write(SLAVE_I2C_REGISTER_ADDRESS);
Wire.endTransmission();
Wire.requestFrom(SLAVE_I2C_ADDRESS, 2); // This register is 16 bits = 2 bytes long
delay(5); // Wait for data to be available
// Read directly into an uint32_t
uint16_t buf;
Wire.readBytes((uint8_t*)&buf, 2);
// Print register value
Serial.printf("Register value: %04x\r\n", __builtin_bswap16(buf));

For an explanation on why we need __builtin_bswap16(), see How to print 16-bit uint16_t as four hex digits in Arduino

Option 2: Reading the register into an uint8_t array

const uint8_t SLAVE_I2C_ADDRESS = 0b1010;
const uint16_t SLAVE_I2C_REGISTER_ADDRESS = 0x50;

Wire.beginTransmission(SLAVE_I2C_ADDRESS);
Wire.write(SLAVE_I2C_REGISTER_ADDRESS);
Wire.endTransmission();
Wire.requestFrom(SLAVE_I2C_ADDRESS, 2); // This register is 16 bits = 2 bytes long
delay(5); // Wait for data to be available
// Read into a 2-byte buffer
uint8_t buf[2];
Wire.readBytes(buf, 2);
// Print register value
Serial.printf("Register value: %02x%02x\r\n", buf[0], buf[1]);

Also see:

Posted by Uli Köhler in Arduino, C/C++, Electronics, Embedded, PlatformIO

How to read 32-bit I2C register using Arduino Wire library: A minimal example

The following code demonstrates how to read a register that is 4 bytes (32 bits) long over I2C. It will work with almost all I2C devices like EEPROMs, ADCs and others, provided you have the correct. Note that some devices like the LAN9303 have a slightly different addressing scheme or other peculiarities. In my opinion, it’s most efficient to just try out the standard way of reading a register and start from there.

Note that this code does not implement error handling for the sake of simplicity. Additionally, we wait for data using delay() instead of Wire.available(). This is a minimal example so it creates minimal confusion for the reader. We will provide a full example with error handling in a followup post.

Option 1: Reading the register into an uint32_t (recommended)

const uint8_t SLAVE_I2C_ADDRESS = 0b1010;
const uint16_t SLAVE_I2C_REGISTER_ADDRESS = 0x50;

Wire.beginTransmission(SLAVE_I2C_ADDRESS);
Wire.write(SLAVE_I2C_REGISTER_ADDRESS);
Wire.endTransmission();
Wire.requestFrom(SLAVE_I2C_ADDRESS, 4); // This register is 32 bits = 4 bytes long
delay(5); // Wait for data to be available
// Read directly into an uint32_t
uint32_t buf;
size_t actually_read = Wire.readBytes((uint8_t*)&buf, 4);
// Print register value
Serial.printf("Register value: %08lx\r\n", __builtin_bswap32(buf));

For an explanation on why we need __builtin_bswap32(), see How to print 32-bit uint32_t as eight hex digits in Arduino

Option 2: Reading the register into an uint8_t array

const uint8_t SLAVE_I2C_ADDRESS = 0b1010;
const uint16_t SLAVE_I2C_REGISTER_ADDRESS = 0x50;

Wire.beginTransmission(SLAVE_I2C_ADDRESS);
Wire.write(SLAVE_I2C_REGISTER_ADDRESS);
Wire.endTransmission();
Wire.requestFrom(SLAVE_I2C_ADDRESS, 4); // This register is 32 bits = 4 bytes long
delay(5); // Wait for data to be available
// Read into a 4-byte buffer
uint8_t buf[4];
size_t actually_read = Wire.readBytes(buf, 4);
// Print register value
Serial.printf("Register value: %02x%02x%02x%02x\r\n", buf[0], buf[1], buf[2], buf[3]);

Also see:

Posted by Uli Köhler in Arduino, C/C++, Electronics, Embedded, PlatformIO

How to access LAN9303 registers over I2C using Arduino / PlatformIO

The LAN9303 has some peculiarities when accessing its registers. This post will not cover indirect register access but only access to the registers which are directly accessible over I2C. Note that the prerequisite for this is to configure the LAN9303 into a mode where management over the I2C slave interface is enabled. See How to get the LAN9303 into I2C managed mode for more info on how to do that.

The main point to take away is that you do not write the register offset from the datasheet (such as 0x50 for the Chip ID and revision register) in the I2C address byte but the address divided by 4 (0x50 >> 2 == 0x14). This is evidenced by figure 8-8 from the datasheet, copyright Microchip, listing the address byte as A[9:2] as opposed to the standard A[7:0]:

 

Example on how to access the register at offset 0x50 (Chip ID and revision register) in Arduino using the Wire library:

const uint8_t LAN9303_I2C_ADDRESS = 0b1010;
const uint16_t LAN9303_CHIPID_REV_Register = 0x50;

Wire.beginTransmission(LAN9303_I2C_ADDRESS);
Wire.write(LAN9303_CHIPID_REV_Register >> 2);
Wire.endTransmission();
Wire.requestFrom(LAN9303_I2C_ADDRESS, 4); // This register is 32 bits = 4 bytes long
delay(5); // Wait for data to be available

// Read directly into an uint8_t
uint32_t buf;
size_t actually_read = Wire.readBytes((uint8_t*)&buf, 4);
// Check if we have received all 4 bytes
if(actually_read != 4) {
    Serial.println("Did not read enough bytes");
}

// Print register value
Serial.printf("LAN9303 Chip ID and revision: %08lx\r\n", __builtin_bswap32(buf));

This will print

LAN9303 Chip ID and revision: 93030001

in other words: Chip ID = 0x9303, revision = 0x0001

 

Posted by Uli Köhler in Arduino, C/C++, Electronics, Embedded, Networking, PlatformIO

How to print 64-bit uint64_t as sixteen hex digits in Arduino

When using Arduino, you often want to print the hex value of a 64-bit value such as a uint64_t, consisting of sixteen hex digits. For example, if you have uint64_t val = 169557370125;, you intend to print 000000277a68250d.

In Arduino you can do that using Serial.printf() with %08lx08lx as format specifier, splitting the uint64_t in two uint32_t instances and printing those one after another:

Serial.printf("%08lx%08lx\r\n",
    ((uint32_t)((val >> 32) & 0xFFFFFFFF)),
    ((uint32_t)(val & 0xFFFFFFFF)));

 

See How to print 32-bit uint32_t as eight hex digits in Arduino for more information on what %x means and why we need to use the 08 in %08x as a printf format specifier.

Posted by Uli Köhler in Arduino, Electronics, Embedded, PlatformIO

How to print 32-bit uint32_t as eight hex digits in Arduino

When using Arduino, you often want to print the hex value of a 32-bit value such as a uint32_t, consisting of eight hex digits. For example, if you have uint32_t val = 9177025;, you intend to print 008C07C1.

In Arduino you can do that using Serial.printf() with %08lx as format specifier. Furthermore, you typically want to invert the byte order of the uint32_t using __builtin_bswap32()since it’s more inuitive to write the hex value MSB-first (big-endian) while most hardware platforms represent the uint32_t as LSB-first (little-endian):

Serial.printf("val = %08lx\r\n", __builtin_bswap32(val));

When using printf, %x means to format the value as hex whereas l tells printf() that the argument is a long (32 bit) as opposed to an int (16 bit). 08 means to pad the value with 0s up to a length of 8 digits. If you would format 9177025 using just %x, it would print 008C07C1  instead of 008C07C1. This is why you need to use %08lx instead.

Posted by Uli Köhler in Arduino, Electronics, Embedded, PlatformIO

How to print 16-bit uint16_t as four hex digits in Arduino

When using Arduino, you often want to print the hex value of a 16-bit value such as a uint16_t, consisting of four hex digits. For example, if you have uint16_t val = 2022;, you intend to print 07E6.

In Arduino you can do that using Serial.printf() with %04x as format specifier.

Furthermore, you typically want to invert the byte order of the uint16_t using __builtin_bswap16()since it’s more inuitive to write the hex value MSB-first (big-endian) while most hardware platforms represent the uint16_t as LSB-first (little-endian):

Serial.printf("val = %04x\r\n", __builtin_bswap16(val));

When using printf, %x means to format the value as hex. 04 means to pad the value with 0s up to a length of 4 digits. If you would format 2022 using just %x, it would print 7E6  instead of 07E5. This is why you need to use %04x instead.

Posted by Uli Köhler in Arduino, Electronics, Embedded, PlatformIO

How to print byte as two hex digits in Arduino

In embedded programming, you often want to print the hex value of a byte, consisting of two hex digits. For example, if you have uint8_t val = 14;, you intend to print 0x0E.

In Arduino you can do that using Serial.printf() with %02x as format specifier:

Serial.printf("val = %02x\r\n", val);

When using printf, %x means to format the value as hex. 02 means to pad the value with 0s up to a length of 2 digits. If you would format 14 using just %x, it would print E  instead of 0E. This is why you need to use %02x.

Posted by Uli Köhler in Arduino, Electronics, Embedded, PlatformIO

Arduino I2C: Wire.endTransmission() before or after Wire.requestFrom() ?

The correct order to call Wire commands in Arduino is:

Wire.beginTransmission(MY_I2C_ADDR);
Wire.write(addr);
Wire.endTransmission();
Wire.requestFrom(MY_I2C_ADDR, 1); // Request one byte
delay(5); // Wait for data to be available
uint8_t value = Wire.read();

So you call Wire.endTransmission() after Wire.write() and call Wire.requestFrom() directly after Wire.endTransmission()

Posted by Uli Köhler in Arduino, Electronics, Embedded, PlatformIO

Teensy 4.x Quadrature Encoder minimal example in PlatformIO/Arduino

This example uses PlatformIO and the Teensy-4.x-Quad-Encoder-Library to implement a hardware quadrature encoder on pins 0 and 1. Remember that the teensy will be destroyed if you use 5V encoder signals. You can only use 3.3V signals!

#include <Arduino.h>
#include <QuadEncoder.h>

QuadEncoder encoder(1, 0, 1, 0);

void setup() {
    Serial.begin(115200);
    encoder.setInitConfig();
    encoder.init();
}

void loop() {
    int32_t position = encoder.read();
    // Compute position in mm and print it
    constexpr float mm_per_count = 0.0012;
    float mm = position * mm_per_count;
    Serial.printf("Position: %+3.4f (count %ld)\r\n", mm, position);
    // Print every 50ms
    delay(50);
}
[env:teensy41]
platform = teensy
board = teensy41
framework = arduino
monitor_speed = 115200
lib_deps =
    git+https://github.com/mjs513/Teensy-4.x-Quad-Encoder-Library

 

Posted by Uli Köhler in C/C++, Electronics, Embedded, PlatformIO, Teensy

How to set pin speed/alternate function in STM32 Arduino (PlatformIO)

You can use the STM32 HAL (STM32CubeMX) even when using Arduino as a framework for STM32 boards in PlatformIO:

GPIO_InitTypeDef pinInit = {
  .Pin = GPIO_PIN_8,
  .Mode = GPIO_MODE_AF_PP,
  .Pull = GPIO_NOPULL,
  .Speed = GPIO_SPEED_FREQ_VERY_HIGH,
  .Alternate = GPIO_AF1_TIM1
};
HAL_GPIO_Init(GPIOA, &pinInit);

Use

#include <stm32f4xx_hal_gpio.h>

in order to include the HAL functions.

Posted by Uli Köhler in Arduino, Electronics, PlatformIO, STM32

How to pass firewall using PlatformIO espota ArduinOTA upload

ArduinoOTA’s protocol tries to connect to the host which is trying to program the device on a randomly chosen port. This often leads to the packets being filtered in a firewall since no rule exists to pass the packet and they are not related to an existing connection.

You could create a firewall rule to pass all traffic from the ESP8266/ESP32 to the programming host, but that is extremely insecure since it allows a hacked IoT device to hack your devices.

In order to fix it, add a fixed host port in platformio.ini using

upload_flags = --host_port=55910

and add these firewall rules:

allow from <programming host> to <IoT device> port 55910 TCP
allow from <IoT device> to <programming host> port 55190 TCP

Complete platformio.ini example:

[env:d1_mini_ota]
extends = env:d1_mini
upload_protocol = espota
upload_port = 192.168.178.25
upload_flags = --host_port=55910

 

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

How to use ESP32 as USB-to-UART converter in PlatformIO

The ESP32 can easily be used as USB-to-UART converter. Note that the ESP32 does not feature an USB interface by itself and ESP32 boards with an onboard USB connector just use an USB-to-UART converter (this is a separate chip on the board). Hence, from the ESP32 perspective, it

You can map UART TX and RX to any GPIO pin on the ESP32. While there are very, very slight performance advantages to using a set of predefined pins, this does not really matter in practice. In this example, we will use pin GPIO2 for UART RX and pin GPIO4 for UART TX.

Basically, the code is just copying bytes between Serial2 and Serial (connected to USB):

// Copy bytes incoming via PC serial
while (Serial.available() > 0) {
  Serial2.write(Serial.read());
}
// Copy bytes incoming via UART serial
while (Serial2.available() > 0) {
  Serial.write(Serial2.read());
}

Full example

#include <Arduino.h>

#define UART_RX_PIN 2 // GPIO2
#define UART_TX_PIN 4 // GPIO4

void setup() {
  // Serial connects to the computer
  Serial.begin(115200);
  // Serial2 is the hardware UART port that connects to external circuitry
  Serial2.begin(115200, SERIAL_8N1,
                UART_RX_PIN,
                UART_TX_PIN);
}

void loop() {
  // Copy byte incoming via PC serial
  while (Serial.available() > 0) {
    Serial2.write(Serial.read());
  }
  // Copy bytes incoming via UART serial
  while (Serial2.available() > 0) {
    Serial.write(Serial2.read());
  }
}

Regarding platformio.ini, we just need to set the monitor_speed to match the value in Serial.begin(115200);:

[env:nodemcu-32s]
platform = espressif32
board = nodemcu-32s
framework = arduino
monitor_speed = 115200

 

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

ESPAsyncWebserver: How to run code in main loop thread

When working with ESPAsyncWebserver, you will soon encounter one of its most fundamental limitations: Its code will always run in interrupts, hence you can’t use delay() or any function that uses delay() or similar functions internally.

However, there’s a simple programming pattern that will enable you to execute code in the main thread if requested by the webserver. Note: In this example, we will only cover how to activate code in the main loop from the webserver, but the response will be sent before the code in the main loop is run – hence, the response is just {"status": "ok"} and it doesn’t depend on whatever is happening on the main loop.

The idea is to have a global flag:

bool request_serial_output = false;

which is set in the webserver handler code, whereas the main loop checks the flag repeatedly:

void loop() {
  if(request_serial_output) {
    request_serial_output = false; // Clear flag
    // TODO Add handling code here
  }
}

Full example

This example uses PlatformIO and should work on any ESP32 board.

#include <Arduino.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>

AsyncWebServer server(80);

bool request_serial_output = false;

void setup() { 
  Serial.begin(115200);
  // Connect Wifi, restart if not connecting
  // https://techoverflow.net/2021/01/21/how-to-fix-esp32-not-connecting-to-the-wifi-network/
  WiFi.begin("WLAN", "privat2014");
  uint32_t notConnectedCounter = 0;
  while (WiFi.status() != WL_CONNECTED) {
      delay(100);
      Serial.println("Wifi connecting...");
      notConnectedCounter++;
      if(notConnectedCounter > 50) { // Reset board if not connected after 5s
          Serial.println("Resetting due to Wifi not connecting...");
          ESP.restart();
      }
  }
  Serial.print("Wifi connected, IP address: ");
  Serial.println(WiFi.localIP());

  // Initialize webserver URLs
  server.on("/api/test", HTTP_GET, [](AsyncWebServerRequest *request) {
      // Send request to main loop
      request_serial_output = true;
      // Send JSON "ok" response.
      // NOTE: The response will be sent BEFORE the main loop has finished
      // processing the request
      AsyncResponseStream *response = request->beginResponseStream("application/json");
      DynamicJsonDocument json(1024);
      json["status"] = "ok";
      serializeJson(json, *response);
      request->send(response);
  });

  // Start webserver
  server.begin();
}

void loop() {
  if(request_serial_output) {
    request_serial_output = false; // Clear flag
    // Output serial
    Serial.println("First message. Now waiting one second...");
    // Wait 1s. You can't do that in the webserver handler!
    delay(1000);
    // Output another message on Serial
    Serial.println("Second message!");
  }
}
[env:nodemcu-32s]
platform = espressif32
board = nodemcu-32s
framework = arduino
monitor_speed = 115200
lib_deps =
    ESP Async [email protected]
    [email protected]

 

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

Test code for 8 Neopixel/WS2812B LEDs

This test code toggles 8 WS2812b LEDs with circulating colors and will test all three R/G/B LEDs in each LED plus their connection.. It is based on an ESP32 with a 74LV245 level shifter, but it will also work on other platforms supported by NeoPixelBus. In my configuration, the 3.3V signal output pin is on pin 13.

#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>

const uint16_t PixelCount = 8;
const uint8_t PixelPin = 13;

NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);

void DrawPixels(uint32_t offset)
{
    strip.SetPixelColor((0 + offset) % 8, RgbColor(255, 0, 0));
    strip.SetPixelColor((1 + offset) % 8, RgbColor(0, 255, 0));
    strip.SetPixelColor((2 + offset) % 8, RgbColor(0, 0, 255));
    strip.SetPixelColor((3 + offset) % 8, RgbColor(255, 255, 0));
    strip.SetPixelColor((4 + offset) % 8, RgbColor(0, 255, 255));
    strip.SetPixelColor((5 + offset) % 8, RgbColor(255, 0, 255));
    strip.SetPixelColor((6 + offset) % 8, RgbColor(255, 255, 255));
    strip.SetPixelColor((7 + offset) % 8, RgbColor(0, 0, 0));
    strip.Show();
}

void setup()
{
    strip.Begin();
    strip.Show();
}

uint32_t loopCounter = 0;
void loop()
{
  DrawPixels(loopCounter);
  loopCounter++;
  delay(250);
}

PlatformIO config:

; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:nodemcu-32s]
platform = espressif32
board = nodemcu-32s
framework = arduino
lib_deps =
     makuna/NeoPixelBus @ ^2.6.9

 

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

How I fixed PlatformIO Arduino

Problem:

When uploading an Atmel AVR firmware like for the Arduino Uno using PlatformIO, you see an error message like

Auto-detected: /dev/ttyACM0
Uploading .pio/build/uno/firmware.hex
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x00

avrdude done.  Thank you.

*** [upload] Error 1

or

Auto-detected: /dev/ttyUSB0
Uploading .pio/build/uno/firmware.hex
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x00
avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x00
avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x00
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x00
avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0x00
avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0x00
avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0x00
avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0x00
avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0x00
avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x00

avrdude done.  Thank you.

*** [upload] Error 1

Solution

This issue occurs if:

  • Either there is no bootloader on the board or the bootloader is damaged or
  • The wrong upload speed for this bootloader is selected

Note that  you can flash a new/updated bootloader using the Arduino IDE, overwriting the old / defective bootloader. You can do that using an AVR programmer, or you can do it using another Arduino. This will make working with the board much easier in general, but it will most likely fix your programming issues. In case you flash a new bootloader, the correct upload_speed setting in platformio.ini will typically be upload_speed = 115200.

In case you want to work with the bootloader currently present on the board, you need to select the correct upload_speed setting.

Depending on the age of the bootloader on the board, it will typically have either 115200, 57600 or 19200 baud speed.

In order to fix the issue, edit platformio.ini and add

upload_speed = 115200

then restart the upload. In case this doesn’t work, try

upload_speed = 57600

and

upload_speed = 19200

Rarely, the following setting work:

upload_speed = 9600

or

upload_speed = 230400

In case none of these settings work at all, either you are facing a hardware defect or you need to flash a new bootloader onto the board. I recommend to always try to flash a bootloader first before throwing away the board.

Posted by Uli Köhler in Arduino, Electronics, Embedded, PlatformIO

How fast is analogRead() on the ESP8266?

An analogRead() call on the ESP8266 takes about 90-100 microseconds.

I tested this experimentally using a Wemos D1 Mini board, PlatformIO and this code:

uint32_t t0 = micros();
for (size_t i = 0; i < 1000; i++)
{
    analogRead(A0);
}
uint32_t t1 = micros();
Serial.print("1000 analogRead() calls took [us]: ");
Serial.println(t1-t0);

Output:

1000 analogRead() calls took [us]: 97168

Since 1000 analogRead() calls (including some overhead from the loop) took 97.168ms, one analogRead() call takes about 97.168us (+-0.02us).

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

How to enable Watchdog on ESP8266/ESP32 using PlatformIO

You can enable the watchdog on the ESP8266 or ESP32 using

ESP.wdtEnable(5000);

where 5000 is the number of milliseconds until the watchdog times out.

Call

ESP.wdgFeed();

periodically to reset the watchdog.

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

What does ESP8266 rst cause: 2 mean?

Sometimes you will see a message like

 ets Jan  8 2013,rst cause:2, boot mode:(3,6)

load 0x4010f000, len 3460, room 16 
tail 4
chksum 0xcc
load 0x3fff20b8, len 40, room 4 
tail 4
chksum 0xc9
csum 0xc9
v0007e100
~ld
7

on the ESP8266 serial line.

rst cause: 2 means that the ESP was restarted from the firmware using

ESP.restart();

Typically such a restart is intentional. Look for ESP.restart() calls in your firmware. It’s not straightforward to identify which ESP.restart() call caused the reset. I recommend to insert Serial.println() statements describing the reset cause before every call to ESP.restart(), for example:

Serial.println("Resetting due to Wifi not connecting...");
ESP.restart();

 

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

How to fix ESP8266 PlatformIO error: WIFI_STA was not declared in this scope

Problem:

When compiling your PlatformIO firmware, you see an error message like

src/main.cpp: In function 'void setup()':
src/main.cpp:49:10: error: 'class WiFiClass' has no member named 'mode'
   49 |     WiFi.mode(WIFI_STA);
      |          ^~~~
src/main.cpp:49:15: error: 'WIFI_STA' was not declared in this scope
   49 |     WiFi.mode(WIFI_STA);
      |               ^~~~~~~~

Solution:

You included WiFi.h instead of the correct ESP8266WiFi.h. This will cause multiple issues like reboots on WiFi.begin() even if it compiles correctly.

Replace

#include <WiFi.h>

with

#include <ESP8266WiFi.h>

everywhere in your source code and does not support

WiFi.mode(WIFI_STA);

For more details, see our previous post on How to fix PlatformIO ESP8266 WiFi.h: No Such File or Directory

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