ESP8266 arduino framework and loop()

[this is the same question as Issue 226 with platformio/platform-espressif8266]

I use platformio 4.3.4 with the arduino framework. In various sketches that I looked at, it is implied that loop() is called within an endless loop so exiting the function is not a big deal, it will be called again. I even found posts around esp8266 and loop implying that you can not run too much functionality within a single loop as this may affect WiFi and other functionality.

BUT in the platformio version of Arduino.h (from framework-arduinoespressif8266 @ 3.20704.0), the loop() function is marked as [[noreturn]] and lo and behold, if my code actually exits loop(), the board crashes with a stack trace.

This is even more confusing, as in the official arduino repo (Arduino/Arduino.h at master · esp8266/Arduino · GitHub), it is not. The platformio framework claims that it is based on 2.7.4 (Update Arduino core to 2.7.4 · platformio/platform-espressif8266@fbbe4e2 · GitHub).

Diffing the cores/esp8266 tree from this repo with the locally installed ~/.platformio/packages/framework-arduinoespressif8266/cores/esp8266 literally shows this as the only significant difference between the arduino repo and what I see locally:

diff -urb Arduino/cores/esp8266/Arduino.h /home/henning/.platformio/packages/framework-arduinoespressif8266/cores/esp8266/Arduino.h
--- Arduino/cores/esp8266/Arduino.h	2020-08-17 14:09:18.245135688 -0700
+++ /home/henning/.platformio/packages/framework-arduinoespressif8266/cores/esp8266/Arduino.h	2020-08-14 09:47:57.771492095 -0700
@@ -201,7 +201,7 @@
 void preinit(void);
 void setup(void);
-void loop(void);
+[[noreturn]] void loop(void);
 void yield(void);
diff -urb Arduino/cores/esp8266/core_esp8266_main.cpp /home/henning/.platformio/packages/framework-arduinoespressif8266/cores/esp8266/core_esp8266_main.cpp
--- Arduino/cores/esp8266/core_esp8266_main.cpp	2020-08-17 14:09:18.246135675 -0700
+++ /home/henning/.platformio/packages/framework-arduinoespressif8266/cores/esp8266/core_esp8266_main.cpp	2020-08-14 09:47:57.786491890 -0700
@@ -40,7 +40,8 @@
 #define LOOP_QUEUE_SIZE    1
 extern "C" void call_user_start();
-extern void loop();
+[[noreturn]] extern void loop();
 extern void setup();
 extern void (*__init_array_start)(void);
 extern void (*__init_array_end)(void);

So my guess is that there is a reason for this. But I don’t understand it. This seems to be platformio specific and it requires me to rewrite code that works on non-platformio arduino code. What is more confusing, I don’t seem to be able to pinpoint the platce where this change is made nor am I able to find documentation as to why this is changed in platformio.

Can you show:

  • platformio.ini
  • the full build log

On my PlatformIO installation, loop() does not have the [[noreturn]] annotation.

Can you additionally check that you have just a single framework-arduinoespressif8266 directory in /home/henning/.platformio/packages, i.e. no other directory like framework-arduinoespressif8266@83de8812a.

I nuked my local .platformio today and reinstalled “the official way” (with and now the Arduino.h file is fine. Very weird. Before, I always installed with “pip install -U platformio” into a virtualenv.

However, at this point I can no longer reproduce this. I have a backup of the old install and the only source difference between that tree and the current (correct) tree is that one line. And if I now compile code that reliably crashed my ESP-01 board by exiting loop(), the same code works just fine.

This is incredibly weird. I checked another laptop with an older platformio installation and it also had the [[noreturn]] in Arduino.h (with 2.7.1 release). I ran pio update/upgrade on the laptop and it also disappeared.

Short of Gremlins, I have no idea how I got into that state. I did not do anything out of the ordinary (with the exception of using pip install instead of the get-platformio script).

Anyway, all seems to work for me now. Sorry for the noise. I may come back if I find a way to reliably reproduce the problem.

Oh, to your questions:

  • I only have one version of the framework-arduinoespressif8266 (2.6.2)
framework = arduino
lib_deps =
      721@3.1.6  ; TaskScheduler
      1358@0.2.1 ; PCF8574
      576@1.1.4  ; LiquidCrystal_I2C

platform = espressif8266
board = esp01_1m
❯ pio run 
Processing esp01_1m (platform: espressif8266; board: esp01_1m; framework: arduino)
Verbose mode can be enabled via `-v, --verbose` option
PLATFORM: Espressif 8266 2.6.2 > Espressif Generic ESP8266 ESP-01 1M
HARDWARE: ESP8266 80MHz, 80KB RAM, 1MB Flash
 - framework-arduinoespressif8266 3.20704.0 (2.7.4) 
 - tool-esptool 1.413.0 (4.13) 
 - tool-esptoolpy 1.20800.0 (2.8.0) 
 - toolchain-xtensa 2.40802.200502 (4.8.2)
LDF: Library Dependency Finder ->
LDF Modes: Finder ~ chain, Compatibility ~ soft
LibraryManager: Installing id=721 @ 3.1.6
Using cache: /home/henning/.platformio/.cache/6c/7de79d5f71cd8e14e6f7e8deb3aab46c
TaskScheduler @ 3.1.6 has been successfully installed!
LibraryManager: Installing id=1358 @ 0.2.1
Using cache: /home/henning/.platformio/.cache/7c/712aabd5dac77462f54e8c30f51cfa7c
PCF8574 @ 0.2.1 has been successfully installed!
LibraryManager: Installing id=576 @ 1.1.4
Using cache: /home/henning/.platformio/.cache/9c/617697dd58dade4d7a09b2ed2638309c
LiquidCrystal_I2C @ 1.1.4 has been successfully installed!
Found 32 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <ESP8266WiFi> 1.0
|-- <TaskScheduler> 3.1.6
|-- <LiquidCrystal_I2C> 1.1.4
|   |-- <Wire> 1.0
|-- <PCF8574> 0.2.1
|   |-- <Wire> 1.0
|-- <Wire> 1.0
Building in release mode
Archiving .pio/build/esp01_1m/libFrameworkArduino.a
Indexing .pio/build/esp01_1m/libFrameworkArduino.a
Linking .pio/build/esp01_1m/firmware.elf
Building .pio/build/esp01_1m/firmware.bin
Retrieving maximum program size .pio/build/esp01_1m/firmware.elf
Checking size .pio/build/esp01_1m/firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [===       ]  33.8% (used 27676 bytes from 81920 bytes)
Flash: [====      ]  35.3% (used 268880 bytes from 761840 bytes)
Creating BIN file ".pio/build/esp01_1m/firmware.bin" using "/home/henning/.platformio/packages/framework-arduinoespressif8266/bootloaders/eboot/eboot.elf" and ".pio/build/esp01_1m/firmware.elf"

I actually figured it out.

Maybe I should have led with this: I am using CLion. This is the bug:

1 Like

Wow. Good analysis…