ESP32 Unable to send Telegram message in interrupt method - arduino

I'm working on my first ESP32 project using a DFRobot Firebeetle 2 (ESP32-WROOM-32E) and the Arduino IDE (configured as per DFRobot's instructions). I'm trying creating a Telegram bot which will send a message when the temperature exceeds a certain value. This part is working in the loop() method, but now I'm trying to add a 'status button' which triggers an interrupt to send a status message. I plan to use the ESP32's sleep function, hence using an interrupt rather than checking the button in loop() - I am aware that loop() doesn't execute when using sleep. The problem is sending a message in the interrupt method is causing an error, but I don't know how to resolve it.
If I reduce minStatusMsgInterval to 250 and call SendStatusMessage(); at the end of setup() I receive the message, so the function works, just not when it's called from an interrupt. The error mentions wdt timeout so I'm thinking bot.sendMessage() is taking too long? But if that is the case, I can't make it any quicker, so is there another way to achieve this? or have I misinterpreted the error completely?
#include <WiFi.h>
#include "WiFiClientSecure.h"
#include <ESP32Time.h>
#include <DFRobot_DHT11.h>
#include <UniversalTelegramBot.h>
//WiFi
#define WLAN_SSID "ESP32Test"
#define WLAN_PASS "*********"
//WiFiFlientSecure for SSL/TLS support
WiFiClientSecure client;
//Time
ESP32Time rtc(0); // offset in seconds; 0 = GMT, 3600 = GMT+1
//Telegram
#define TELEGRAM_TOKEN "*********:*************************"
#define CHAT_ID "**********"
UniversalTelegramBot bot(TELEGRAM_TOKEN, client);
//Temperature
DFRobot_DHT11 DHT;
#define DHT11_PIN D11
//Buttons
#define ONBOARD_BUTTON_PIN 27 //ESP32 pin 27
#define STATUS_BUTTON_PIN D10 //ESP32 pin 12
int StatusButtonLastInterrupt = 0;
//Alerts
int alertValue = 27;
bool alertSent = false;
int minStatusMsgInterval = 5000;
void IRAM_ATTR SendStatusMessage() {
if (millis() - StatusButtonLastInterrupt < minStatusMsgInterval) return; //Prevent executing multiple times per button press or more frequent than required
String message = "Temperature Monitor Status\n\n";
message += "Internal temperature: " + String(DHT.temperature) + "C\n";
message += "Internal humidity: " + String(DHT.humidity) + "%\n";
//message += "System time: " + rtc.getDateTime(); // Causes ESP to crash and reset. Error: abort() was called at PC 0x40084cf7 on core 1
//TODO: Check WiFi is connected first - will need to connect when woken from sleep
bot.sendMessage(CHAT_ID, message, ""); // Causes ESP to crash and reset. Error: Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1).
StatusButtonLastInterrupt = millis();
}
void SyncNTP() {
Serial.print("Retrieving time: ");
configTime(0, 3600, "time.google.com"); // get UTC time via NTP
time_t now = time(nullptr);
while (now < 24 * 3600)
{
Serial.print(".");
delay(100);
now = time(nullptr);
}
rtc.setTime(now); //Set the time on the realtime clock
Serial.println(rtc.getDateTime());
}
void setup() {
pinMode(ONBOARD_BUTTON_PIN, INPUT_PULLUP);
pinMode(STATUS_BUTTON_PIN, INPUT);
Serial.begin(115200);
//Interrupts
attachInterrupt(STATUS_BUTTON_PIN, SendStatusMessage, FALLING);
// Connect to WiFi access point.
Serial.println(); Serial.println();
Serial.print("Connecting to ");
Serial.println(WLAN_SSID);
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(WLAN_SSID, WLAN_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
//Serial.print(".");
Serial.print("WiFi Status: ");
Serial.println(WiFi.status());
}
Serial.println();
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Add root certificate for api.telegram.org
SyncNTP();
}
void loop() {
DHT.read(DHT11_PIN);
Serial.print("temp:");
Serial.print(DHT.temperature);
Serial.print(" humi:");
Serial.println(DHT.humidity);
if (DHT.temperature >= alertValue)
{
if (!alertSent)
{
bot.sendMessage(CHAT_ID, "TEMPERATURE ALERT: Internal temperature is: " + String(DHT.temperature), "");
alertSent = true;
}
} else {
if (alertSent)
{
bot.sendMessage(CHAT_ID, "Alert Cleared: Internal temperature is: " + String(DHT.temperature), "");
alertSent = false; //Reset the flag when temperature drops below alertValue
}
}
delay(1000);
}
Serial Monitor Output:
Connecting to ESP32Test
WiFi Status: 6
WiFi Status: 6
WiFi Status: 6
WiFi Status: 6
WiFi Status: 3
WiFi connected
IP address: 192.168.1.2
Retrieving time: ....................Sun, Feb 19 2023 22:23:38
temp:25 humi:57
temp:24 humi:53
temp:24 humi:60
temp:24 humi:60
temp:24 humi:60
temp:24 humi:60
Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1).
Core 1 register dump:
PC : 0x40090362 PS : 0x00060f34 A0 : 0x8008f47e A1 : 0x3ffbeb00
A2 : 0x3ffde700 A3 : 0x3ffbd994 A4 : 0x00000004 A5 : 0xb33fffff
A6 : 0x00000001 A7 : 0x00000001 A8 : 0x3ffbd994 A9 : 0x3ffbd994
A10 : 0x00000019 A11 : 0x00000019 A12 : 0x3ffc3afc A13 : 0xb33fffff
A14 : 0x00000001 A15 : 0x00000001 SAR : 0x0000000f EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x400896b0 LEND : 0x400896c6 LCOUNT : 0xffffffff
Core 1 was running in ISR context:
EPC1 : 0x400e8e33 EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x40090362
Backtrace:0x4009035f:0x3ffbeb000x4008f47b:0x3ffbeb20 0x4008de7c:0x3ffbeb40 0x40106ab7:0x3ffbeb80 0x400f408f:0x3ffbeba0 0x401071c5:0x3ffbebd0 0x40107464:0x3ffbebf0 0x400f379d:0x3ffbec40 0x400d49d2:0x3ffbec60 0x400d472d:0x3ffbeed0 0x400d483e:0x3ffbef00 0x400d6c31:0x3ffbef20 0x400d7ece:0x3ffbef80 0x400d8406:0x3ffbf000 0x4008139e:0x3ffbf070 0x400d93f5:0x3ffbf0d0 0x40084a8d:0x3ffbf0f0 0x40173c7f:0x3ffc78f0 0x400e82e9:0x3ffc7910 0x4008e417:0x3ffc7930
Core 0 register dump:
PC : 0x40090522 PS : 0x00060634 A0 : 0x8008fc1b A1 : 0x3ffb3290
A2 : 0x3ffbf108 A3 : 0x3ffb32ac A4 : 0x00060623 A5 : 0xb33fffff
A6 : 0x0000cdcd A7 : 0x0000abab A8 : 0x0000abab A9 : 0x0000abab
A10 : 0x3ffde770 A11 : 0x000000d0 A12 : 0x3ffc6948 A13 : 0xb33fffff
A14 : 0x00000001 A15 : 0x00000001 SAR : 0x00000011 EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x400896b0 LEND : 0x400896c6 LCOUNT : 0xffffffff
Backtrace:0x4009051f:0x3ffb32900x4008fc18:0x3ffb32d0 0x4008dd9c:0x3ffb32f0 0x401069c0:0x3ffb3330 0x40106d0e:0x3ffb3350 0x400f56bb:0x3ffb3370 0x400f5739:0x3ffb3390 0x400f812c:0x3ffb33b0 0x400f8211:0x3ffb33e0 0x40108557:0x3ffb3400 0x400f3f19:0x3ffb3420
ELF file SHA256: 0000000000000000
Rebooting...
ets Jul 29 2019 12:21:46
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1412
load:0x40078000,len:13400
load:0x40080400,len:3672
entry 0x400805f8
Connecting to ESP32Test

In general, interrupt handlers need to do as little as possible and return as quickly as possible. Doing too much or calling unsafe functions (which almost all functions will be) leads to programs crashing exactly the way you saw.
Interrupts, as the name indicates, interrupt whatever code is running and execute the interrupt's handler. The handler has no idea what state the code that was interrupted is in. It could easily be in an inconsistent state while it's performing a computation; calling it while it's in an inconsistent state is likely to corrupt memory or cause it to crash or behave erratically. Unless software is specifically designed to be called from an interrupt handler you must assume it's not safe to do so.
As you noticed, the ESP32 requires an interrupt handler to be marked with the IRAM_ATTR attribute - this tells the ESP32 to always keep this code in "Instruction RAM" so that it's always available to execute. The ESP32 isn't able to pull code in from flash storage on demand to service an interrupt. That means that not only does the interrupt handler have to be in IRAM, all functions it calls must be as well. IRAM is a scarce resource, so you want to use as little of it as possible - calling Telegram from an interrupt handler means that not only does all of the Telegram code need to be in IRAM but the entire TCP/IP network stack needs to be. Which also means you'd have to modify every single function in the TelegramBot and network stack to be declared IRAM_ATTR.
Obviously that's not going to work.
Unless you really know what you're doing, the safest way to code an interrupt handler is to set a flag variable indicating there's work to be done, store any data that needs to be saved for the work in other variables and return.
In your case it would look something like this:
volatile boolean should_send_telegram_message = false;
void IRAM_ATTR SendStatusMessage() {
if (millis() - StatusButtonLastInterrupt < minStatusMsgInterval)
return; //Prevent executing multiple times per button press or more frequent than required
should_send_telegram_message = true;
}
void loop() {
if(should_send_telegram_message) {
should_send_telegram_message = false;
String message = "Temperature Monitor Status\n\n";
message += "Internal temperature: " + String(DHT.temperature) + "C\n";
message += "Internal humidity: " + String(DHT.humidity) + "%\n";
//message += "System time: " + rtc.getDateTime(); // Causes ESP to crash and reset. Error: abort() was called at PC 0x40084cf7 on core 1
//TODO: Check WiFi is connected first - will need to connect when woken from sleep
bot.sendMessage(CHAT_ID, message, ""); // Causes ESP to crash and reset. Error: Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1).
StatusButtonLastInterrupt = millis();
}
// do other loop() stuff
}
The volatile attribute on should_send_telegram_message tells the compiler that this variable may unexpectedly have its value changed (as the interrupt handler may do) so that the compiler will avoid doing certain optimizations that depend on the variable not unexpectedly changing.

Related

Solved --- ESP8266 with DHT11 / DHT22 Standalon -> problem with Arduino to flash the ESP8266

before to come here, I've tried lot an lot of solutions found on the net and here.
The issue is:
After compile code (passed as good), I try to upload it into ESP8266 throu Arduino.
The result is:
« esptool.py v3.0 Serial port /dev/ttyACM0
Connecting........_____....._____....._____....._____....._____....._____.....____
Traceback (most recent call last):
File "/home/patrick/.arduino15/packages/esp8266/hardware/esp8266/3.0.2/tools/upload.py", line 66, in <module> esptool.main(cmdline)
File "/home/patrick/.arduino15/packages/esp8266/hardware/esp8266/3.0.2/tools/esptool/esptool.py", line 3552, in main esp.connect(args.before, args.connect_attempts)
File "/home/patrick/.arduino15/packages/esp8266/hardware/esp8266/3.0.2/tools/esptool/esptool.py", line 529, in connect raise
FatalError('Failed to connect to %s: %s' % (self.CHIP_NAME, last_error)) esptool.
FatalError: Failed to connect to ESP8266: Timed out waiting for packet header
_ le port série sélectionné _ n'existe pas ou votre Arduino n'est pas connecté »
During transfer I can see both Arduino (TX and RX) DEL blinking, and Arduino RX blinks the ESP8266 TX blinks also. From there ... I feel like having good connection.
The pinout goses like this
Arduino - ESP8266
GND - GND
3.3V - VCC
RX+0 - TX
TX+1 - RX
3.3V - CH_PD/EN
According to ESP8266pinout
I tried to
change the upload speed
change the CPU frequency
change the cristal frequency
switch TX / RX just i case I would plugged them on reverse
updated the DHT driver and adapted the code consequently
downgrade the ESP8666 driver on Arduino IDE from 3.2 to 2.5.1, to 2.5.0, to 2.4.9
modify the upload.py file, line 66 and around
My ESP8666 did connect properly to the WiFi Network previously, programming it with Raspberry PICO and micropython. From that, I'm pretty sure about the good working state of the device.
Below is my c++ code
#include <ESP8266WiFi.h>
#include <DHT.h>
const char* ssid = "BullFrog"; // Your ssid
const char* password = "Pr1on$J3sus"; // Your Password
WiFiServer server(80);
//Instantiation d'une nouvelle classe DHT
// DHT DHT (pin, type, count);
// #param pin
// pin number that sensor is connected
// #param type
// type of sensor
// #param count
// number of sensors
DHT DHT(2, 11, 1);
double Fahrenheit(double celsius) {
return ((double)(9 / 5) * celsius) + 32;
}
double Kelvin(double celsius) {
return celsius + 273.15;
}
void setup() {
Serial.begin(115200);
delay(10);
Serial.println();
// Connect to WiFi network
WiFi.mode(WIFI_STA);
Serial.println();
Serial.println();
Serial.print("Tentative de connexion au Wifi nommé ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("Connexion WiFi établie");
// Start the server
server.begin();
Serial.println("Démarrage du serveur web");
// Print the IP address
Serial.println(WiFi.localIP());
}
void loop() {
int err;
float temp, humi;
if (temp = DHT.readTemperature(false, false)) {
Serial.print("Température:");
Serial.print(temp);
} else {
Serial.println();
Serial.print("Erreur lors de la lecture de la température. No :");
Serial.print(err);
Serial.println();
}
if (temp = DHT.readHumidity(false)) {
Serial.print(" Humidité:");
Serial.print(humi);
Serial.println();
} else {
Serial.println();
Serial.print("Erreur lors de la lecture de l humidité relative. No :");
Serial.print(err);
Serial.println();
}
WiFiClient client = server.available();
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println("Refresh: 5");
client.println();
client.println("<!DOCTYPE html>");
client.println("<html xmlns='http://www.w3.org/1999/xhtml'>");
client.println("<head>\n<meta charset='UTF-8'>");
client.println("<title>ESP8266 Température & Humidité DHT11</title>");
client.println("</head>\n<body>");
client.println("<H2>Capteurs ESP8266 & DHT11</H2>");
client.println("<H3>Humidité / Température</H3>");
client.println("<pre>");
client.print("Humidité (%) : ");
client.println((float)humi, 2);
client.print("Température (°C) : ");
client.println((float)temp, 2);
client.print("Température (°F) : ");
client.println(Fahrenheit(temp), 2);
client.print("Température (°K) : ");
client.println(Kelvin(temp), 2);
client.println("</pre>");
client.println("<H3>Revenez nous voir!</H3>");
client.print("</body>\n</html>");
// delay(DHT11_RETRY_DELAY); //delay for reread
}
I want to use this kit in standalone
I followed this tutorial (among others)
Thanks for your attention and help.
I would first try to program your ESP-01 with a simple Blink sketch, just to confirm the ESP-01 is ok.
These are examples from the same website you reference:
https://www.elec-cafe.com/tag/esp8266-flasher/
https://www.elec-cafe.com/esp8266-esp-01-firmware-update/
Also, the ESP8266 requires a good amount for power for WiFi transmit. Sometimes it help to use separate power supply and add 470uF or 1000uF capacitor across the VCC and GND of the ESP chip.
I hope this might help you to succeed.
The problem is not in coding but in wiring.
Remember that (with ESP8266-01) :
pin 1 as GND (from left to right 1,2,3,4) on the row near to the middle of board
pins 5 as VCC (from right to left 5,6,7,8) on the row near to the ridge of board
pins 5 and 7 must be permanently connected
for loading code into ESP8266-01: pins 1 and 3 must be connected for the uploading time duration.
Once everything is uploaded, come back to the using position (uplug 1 - 3) like this:

How to use custom pins for SPI on ESP32 (pico-v3-02)

I trying to use custom pins for SPI on the pico-mini-02 board. The board has esp32 (pico-v3-02). I'm using Arduino IDE (with arduino-esp32) and windows 10.
When I try to use the SPI example (multiple buses example), I'm getting Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled. error. I have decoded the exception backtrace
0x40080f31: __pinMode at C:\Users\newto\OneDrive\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.5\cores\esp32\esp32-hal-gpio.c line 115
0x400d0f3a: spiAttachSCK at C:\Users\newto\OneDrive\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.5\cores\esp32\esp32-hal-spi.c line 87
0x400d0db2: SPIClass::begin(signed char, signed char, signed char, signed char) at C:\Users\newto\OneDrive\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.5\libraries\SPI\src\SPI.cpp line 57
0x400d0c2b: setup() at C:\Users\newto\OneDrive\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.5\libraries\SPI\examples\SPI_Multiple_Buses/SPI_Multiple_Buses.ino line 67
0x400d190a: loopTask(void*) at C:\Users\newto\OneDrive\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.5\cores\esp32\main.cpp line 32
0x40085fa5: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143
The full error message:
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 271414342, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:10124
load:0x40080400,len:5856
entry 0x400806a8
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x40080f31 PS : 0x00060730 A0 : 0x800d0f3d A1 : 0x3ffb1f30
A2 : 0x0000000e A3 : 0x00000002 A4 : 0x3ffb8364 A5 : 0x00000001
A6 : 0x00000000 A7 : 0x00000004 A8 : 0x3f400674 A9 : 0xaaaaaaaa
A10 : 0xaaaaaaaa A11 : 0x00000030 A12 : 0x3ffb82cc A13 : 0x00000000
A14 : 0x00000000 A15 : 0x00000000 SAR : 0x00000009 EXCCAUSE: 0x0000001c
EXCVADDR: 0xaaaaaaaa LBEG : 0x400d1258 LEND : 0x400d1265 LCOUNT : 0x00000000
ELF file SHA256: 0000000000000000
Backtrace: 0x40080f31:0x3ffb1f30 0x400d0f3a:0x3ffb1f50 0x400d0db2:0x3ffb1f70 0x400d0c2b:0x3ffb1f90 0x400d190a:0x3ffb1fb0 0x40085fa5:0x3ffb1fd0
Rebooting...
ets Jul 29 2019 12:21:46
Any help would be appreciated.
The sketch:
/* The ESP32 has four SPi buses, however as of right now only two of
* them are available to use, HSPI and VSPI. Simply using the SPI API
* as illustrated in Arduino examples will use VSPI, leaving HSPI unused.
*
* However if we simply intialise two instance of the SPI class for both
* of these buses both can be used. However when just using these the Arduino
* way only will actually be outputting at a time.
*
* Logic analyser capture is in the same folder as this example as
* "multiple_bus_output.png"
*
* created 30/04/2018 by Alistair Symonds
*/
#include <SPI.h>
// Define ALTERNATE_PINS to use non-standard GPIO pins for SPI bus
#ifdef ALTERNATE_PINS
#define VSPI_MISO 2
#define VSPI_MOSI 4
#define VSPI_SCLK 0
#define VSPI_SS 33
#define HSPI_MISO 26
#define HSPI_MOSI 27
#define HSPI_SCLK 25
#define HSPI_SS 32
#else
#define VSPI_MISO MISO
#define VSPI_MOSI MOSI
#define VSPI_SCLK SCK
#define VSPI_SS SS
#define HSPI_MISO 12
#define HSPI_MOSI 13
#define HSPI_SCLK 14
#define HSPI_SS 15
#endif
static const int spiClk = 1000000; // 1 MHz
//uninitalised pointers to SPI objects
SPIClass * vspi = NULL;
SPIClass * hspi = NULL;
void setup() {
//initialise two instances of the SPIClass attached to VSPI and HSPI respectively
vspi = new SPIClass(VSPI);
hspi = new SPIClass(HSPI);
//clock miso mosi ss
#ifndef ALTERNATE_PINS
//initialise vspi with default pins
//SCLK = 18, MISO = 19, MOSI = 23, SS = 5
vspi->begin();
#else
//alternatively route through GPIO pins of your choice
vspi->begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_SS); //SCLK, MISO, MOSI, SS
#endif
#ifndef ALTERNATE_PINS
//initialise hspi with default pins
//SCLK = 14, MISO = 12, MOSI = 13, SS = 15
hspi->begin();
#else
//alternatively route through GPIO pins
hspi->begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_SS); //SCLK, MISO, MOSI, SS
#endif
//set up slave select pins as outputs as the Arduino API
//doesn't handle automatically pulling SS low
pinMode(VSPI_SS, OUTPUT); //VSPI SS
pinMode(HSPI_SS, OUTPUT); //HSPI SS
}
// the loop function runs over and over again until power down or reset
void loop() {
//use the SPI buses
vspiCommand();
hspiCommand();
delay(100);
}
void vspiCommand() {
byte data = 0b01010101; // junk data to illustrate usage
//use it as you would the regular arduino SPI API
vspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
digitalWrite(VSPI_SS, LOW); //pull SS slow to prep other end for transfer
vspi->transfer(data);
digitalWrite(VSPI_SS, HIGH); //pull ss high to signify end of data transfer
vspi->endTransaction();
}
void hspiCommand() {
byte stuff = 0b11001100;
hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
digitalWrite(HSPI_SS, LOW);
hspi->transfer(stuff);
digitalWrite(HSPI_SS, HIGH);
hspi->endTransaction();
}
Hi Mate I tried the code and it works. I have selected AI Thinker ESP32 that matches my board,and I have selected Flash Mode QIO and also DIO: both working fine. If you may still have the issue I would suggest to select DOUT or DIO.
Basically please check if your board matches the one selected on Tools->Board and check also the selection of 'Flash mode'.
Not all chips support all of these modes. The datasheet is the best source to know what supports what.
DIO - SPI host uses the "Dual I/O Fast Read" command (BBh). Two SPI pins are used to write the flash address part of the command, and to read flash data out. Therefore these phases need half the clock cycles compared to standard SPI.
DOUT - SPI host uses the "Dual Output Fast Read" command (3Bh). Two SPI pins are used to read flash data out. Slightly slower than DIO, because the address is written via the single MOSI data pin.
QIO - SPI host uses the "Quad I/O Fast Read" command (EBh). Four SPI pins are used to write the flash address part of the command, and to read flash data out. Therefore these phases need a quarter the clock cycles compared to standard SPI.
QOUT - SPI host uses the "Quad Output Fast Read" command (6Bh). Four SPI pins are used to read the flash data out. Slightly slower than QIO, because the address is written via the single MOSI data pin.
ESP-IDF defaults to DIO because some flash chips use a mode bit to enable QIO & QOUT support, and this can vary between manufacturers.
If using DIO/DOUT mode, GPIOs 9 & 10 are available for other uses. However note that if they are wired to the SPI flash chip (as they are in WROOM, for example) then the SPI flash chip may use them for other pin functions. Consult the SPI flash chip data sheet to be sure.
Very interesting discussion on this subject here: https://www.esp32.com/viewtopic.php?t=1250
Hope this helps. All the best.

mbed: HardFault Error when accessing SD-Card after building up network connection

I want to combine a HTTP-Client and a SD-Card-Reader. My goal is to download a file from a server and save that file on the SD-Card. Unfortunately Im stuck on the way, because of an Hard Fault 0x80FF013D.
I haven broken down the code and recognized in summary:
network communication (GET-command) works fine solo
SD-Card access (read and write) works fine solo
SD-Card access works fine before building up the network connection
Hard Fault occures, when I access the SD-Card after building up the network connection
Core-Infos:
OS: MBED OS5
IDE: MBED CLI v1.8.2
MC: NUCLEO-F746ZG
SD-Card Reader: CATALEX MicroSD Card Adapter with Transcend 2GB microSD (FAT formatted)
Libraries:
mbed-os
https://github.com/ARMmbed/mbed-os/#e1bea44212b8275f7d8ce7253e758c2e25c57482
sd-driver https://github.com/ARMmbed/sd-driver/#a8c85d30af86a7431d85dee02d133d60dd386406
Serial Output with HardFault:
[NWKH] Connecting to network...
[NWKH] Connected to the network
[NWKH] IP address: 192.168.188.29
Test SD-Card
++ MbedOS Fault Handler ++
FaultType: HardFault
Context:
R0 : 20000400
R1 : BFF39B82
R2 : 08025B6A
R3 : 00000003
R4 : 00000000
R5 : 2000FA34
R6 : 84551677
R7 : 7FFFFC00
R8 : 00000003
R9 : 08025B6A
R10 : 2000FA34
R11 : 00000000
R12 : 08013E6D
SP : 2000F9F8
LR : 0801A8E7
PC : A0000000
xPSR : 210B0000
PSP : 2000F990
MSP : 2004FFC0
CPUID: 410FC271
HFSR : 40000000
MMFSR: 00000001
BFSR : 00000000
UFSR : 00000000
DFSR : 0000000B
AFSR : 00000000
Mode : Thread
Priv : Privileged
Stack: PSP
-- MbedOS Fault Handler --
++ MbedOS Error Info ++
Error Status: 0x80FF013D Code: 317 Module: 255
Error Message: Fault exception
Location: 0x8012A7B
Error Value: 0xA0000000
Current Thread: Id: 0x2000DA34 Entry: 0x8012BEB StackSize: 0x2000 StackMem: 0x2000DA78 SP: 0x2004FF58
For more info, visit: https://armmbed.github.io/mbedos-error/?error=0x80FF013D
-- MbedOS Error Info --
I have started with the http-example from mbed https://os.mbed.com/teams/sandbox/code/http-example/file/2efadc4d8784/source/main-http-socket-reuse.cpp/shortlog/
and added some stuff from the sd card file system example
https://os.mbed.com/cookbook/SD-Card-File-System
main-http.cpp
#include "select-demo.h"
#if DEMO == DEMO_HTTP
#include "mbed.h"
#include "http_request.h"
#include "network-helper.h"
#include "mbed_mem_trace.h"
#include "SDBlockDevice.h"
#include "FATFileSystem.h"
#include "DebouncedIn.h"
#define SD_MOUNT_PATH "sd"
#define FULL_UPDATE_FILE_PATH "/" SD_MOUNT_PATH "/" MBED_CONF_APP_UPDATE_FILE
SDBlockDevice sd(MBED_CONF_APP_SD_CARD_MOSI, MBED_CONF_APP_SD_CARD_MISO,
MBED_CONF_APP_SD_CARD_SCK, MBED_CONF_APP_SD_CARD_CS);
FATFileSystem fs(SD_MOUNT_PATH);
NetworkInterface* network;
DebouncedIn btn(USER_BUTTON);
FILE* file;
int main()
{
/*------Init SD-Card-----------*/
int r;
//Init
if ((r = sd.init()) != 0) {
printf("Could not initialize SD driver (%d)\n", r);
return 1;
}
//Mount
if ((r = fs.mount(&sd)) != 0) {
printf("Could not mount filesystem, is the SD card formatted as FAT? (%d)\n", r);
return 1;
}
/*------Init Network-----------*/
network = connect_to_default_network_interface();
if (!network)
{
printf("Cannot connect to the network, see serial output\n");
return 1;
}
//Write
printf("Test SD-Card\n");
char testbuffer2[] = { 'a' , 'b' , 'c' };
file = fopen("/sd/test.bin", "wb");
fwrite("abc",1,3,file);
//fwrite(testbuffer2,1,sizeof(testbuffer2),file);
fclose(file);
//Hauptschleife
while(1)
{
//Buttondruck
if (btn.rising())
{
printf("Update wird gesucht, bitte warten\n");
}
}
}
#endif
mbed_app.json
{
"config": {
"main-stack-size": {
"value": 8192
},
"update_file": {
"help": "Path to the application update binary on the SD card",
"value": "\"update.bin\""
},
"sd_card_mosi": {
"help": "MCU pin connected to the SD card's SPI MOSI pin",
"value": "D11"
},
"sd_card_miso": {
"help": "MCU pin connected to the SD card's SPI MISO pin",
"value": "D12"
},
"sd_card_sck": {
"help": "MCU pin connected to the SD card's SPI SCK pin",
"value": "D13"
},
"sd_card_cs": {
"help": "MCU pin connected to the SD card's SPI CS pin",
"value": "D10"
}
},
"macros": [
"MBEDTLS_MPI_MAX_SIZE=1024",
"MBEDTLS_MPI_WINDOW_SIZE=1",
"MBEDTLS_USER_CONFIG_FILE=\"mbedtls_entropy_config.h\"",
"MBEDTLS_TEST_NULL_ENTROPY",
"MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES",
"MBED_HEAP_STATS_ENABLED=1"
],
"target_overrides": {
"*": {
"platform.stdio-baud-rate": 115200,
"platform.stdio-convert-newlines": true,
"mbed-mesh-api.6lowpan-nd-channel-page": 0,
"mbed-mesh-api.6lowpan-nd-channel": 12,
"mbed-trace.enable": 1,
"platform.error-hist-enabled": 1,
"mbed-http.http-buffer-size": 2048,
"nsapi.default-wifi-security": "WPA_WPA2",
"nsapi.default-wifi-ssid": "\"SSID\"",
"nsapi.default-wifi-password": "\"Password\""
}
}
}
I have already read the Tutorial for "Analyzing Mbed OS crash dump" -> https://os.mbed.com/docs/v5.8/tutorials/analyzing-mbed-os-crash-dump.html,
but I have still no idea what I can do, to find the reason for the Hard Fault.
Error Status: "0x80FF013D" means "Hard Fault exception"
HFSR: 40000000 means "Forced Hard Fault"
MMFSR: 00000001 means "The processor attempted an instruction fetch from a location that does not permit execution."
UFSR: 00000000 means "everything is good"
BFSR: 00000000 means "everything is good"
I would appreciate some help. Thanks in advance.
This board has conflict pin D11. It used by ethernet and both your SPI. You need to use another SPI pins or follow guide from mbed site to fix board:
If you use both SPI and Ethernet You have to patch the NUCLEO board on the back side:
remove SB121 and close SB122 solder bridges. This will
connect PB_5 to D11 instead of PA_7.
Overwrite the d11_configuration by using the mbed_app.json file and use PB_5 (instead of PA_7 default value).

How to disable 'interrupt watchdog' in ESP32 OR increase ISR time limit?

I am using ESP32 DEVKIT link and Adafruit VS1053 Codec + MicroSD Breakout - MP3/WAV/MIDI/OGG Play + Record - v4 link to record and then play the sound. I am using Arduino IDE for coding.
I am facing an issue right now that the module uses hardware interrupt for playing purposes. But ESP32 is resetting again and again when I try to play a sound track. The debug log says:
Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1)
Core 1 register dump:
PC : 0x400d1280 PS : 0x00060834 A0 : 0x800d128f A1 : 0x3ffc0bb0
A2 : 0x3ffc241c A3 : 0x3ffb1f20 A4 : 0x800d1779 A5 : 0x3ffb1f00
A6 : 0x3ffc241c A7 : 0x3f400f9c A8 : 0x800d1280 A9 : 0x3ffc0b90
A10 : 0x0000002b A11 : 0x3f401067 A12 : 0x800d1691 A13 : 0x3ffb1ed0
A14 : 0x3ffc241c A15 : 0x00000000 SAR : 0x0000001f EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xffffffff
Core 1 was running in ISR context:
EPC1 : 0x400d4123 EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x400d1280
Backtrace: 0x400d1280:0x3ffc0bb0 0x400d128c:0x3ffc0bd0 0x40080e21:0x3ffc0bf0 0x400817d5:0x3ffc0c10 0x400d3ae5:0x00000000
Core 0 register dump:
PC : 0x400ee86e PS : 0x00060934 A0 : 0x8008656c A1 : 0x3ffc7910
A2 : 0x00000008 A3 : 0x00000000 A4 : 0x00000001 A5 : 0x3ffc7f4c
A6 : 0x00000000 A7 : 0x00000001 A8 : 0x3ffc3404 A9 : 0x3ffc33e8
A10 : 0x00000000 A11 : 0x00000001 A12 : 0x00000000 A13 : 0x00000001
A14 : 0x00060b20 A15 : 0x00000000 SAR : 0x00000000 EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000
Backtrace: 0x400ee86e:0x3ffc7910 0x40086569:0x3ffc7930
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:952
load:0x40078000,len:6084
load:0x40080000,len:7936
entry 0x40080310
Adafruit VS1053 Simple Test
VS1053 found
The line Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1) indicates that its interrupt wdt.
I searched ways to disable interrupt WDT but no help. The file esp_int_wdt.h in ~Documents\Arduino\hardware\espressif\esp32\tools\sdk\include\esp32 provides two functions for enabling interrupt WDT for both or one CPU. There is no function to disable it.
How to disable ESP32 interrupt WDT?
#include "soc/rtc_wdt.h"
rtc_wdt_protect_off();
rtc_wdt_disable();
Or turn it off in menuconfig. I agree with other posters though, you should not turn it off, instead, you can also feed it with the following function:
rtc_wdt_feed();
I usually create a lowest priority FreeRTOS task that just loops and calls the feed method with a delay less then the timeout, giving enough time for higher priority "business logic" to run. Example:
Set timeout to 250 ms in menuconfig or in code:
rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us);
rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_SYSTEM);
rtc_wdt_set_time(RTC_WDT_STAGE0, 250);
Then do this in your task:
while(true) {
rtc_wdt_feed();
vTaskDelay(pdMS_TO_TICKS(100));
}
This will feed both the FreeRTOS WDT and the RTC WDT and reset your system if it gets stuck in a loop or doesn't processes within your time requirements. You'll need to play with the timeout and how often you feed the timer to get it right for your system.Keep in mind the Wifi, PHY, and BT are not deterministic so you'll have a lot of unpredictability in timing if you are dependent on DAQ from from "the net".
I don't know how to disable watchdog using arduino, but I can tell you how to disable it using esp-idf and its make menuconfig
Open menuconfig: make menuconfig
Enter component config
Enter ESP32-specific
Remove star from interrupt watchdog
P.S. According to esp-idf docs void esp_int_wdt_init() is used to init interrupt watchdog. This function is called when IWDT enabled in menuconfig. So you can try to find call of this function and remove it ;)
BUT:
I advise you to not disable watchdog. Instead of this, try to use FreeRTOS tasks to execute large amount of code on interrupt.
Im not sure how to do it exactly in arduino platform, but I can tell how I did it using esp-idf
First, create interrupt handler with signature void f(void*)
void MyHandler(void* pData){
/* Your code here */
vTaskDelete(NULL); // delete current taks, must have
}
Second, in interrupt handler you have to create new task, using xTaskCreate or xTaskCreatePinnedToCore. For example, xTaskCreate(MyHandler, "int_handler", 256, NULL, 4, NULL); (Check out api reference)
That's all, now you can run big code on your interrupt. In addition to this, I advise you to not create too many tasks. System may hang.
P.S. If you need to handle tonns of interurpt requests per second, try to use FreeRTOS queues
The watchdog timer plays an important role in system stability.
Rather than disabling the watchdog timer, try to make sure that you don't stay in loop() for too long. You should always structure your code so that you do the least work you can in loop() and let it return. When it returns the software that supports your ESP32 application gets to do important housekeeping tasks, and reset the watchdog timer.
For instance, you should never write:
void loop() {
while(1) {
do_some_work();
}
}
and instead you should write:
void loop() {
do_some_work();
}
If you absolutely have to do more work in loop() than the watchdog timer allows for, make sure you call yield() or delay() occasionally from your code; this will allow the system to catch up on things it needs to do. yield() will return immediately after doing any needed housekeeping work; delay(milliseconds) will return milliseconds later after doing any needed work.
So rather than write
void loop() {
unsigned long start_time = millis();
while(millis() - start_time < 10*1000) { }
do_some_work();
}
which would cause the watchdog timer to go off, you'd want to write
void loop() {
delay(10*1000);
do_some_work();
start_time = millis();
}
or even better, if your loop may be servicing multiple needs:
void loop() {
static unsigned long start_time1 = millis();
static unsigned long start_time2 = millis();
if(millis() - start_time >= 10*1000) {
do_some_work1();
start_time1 = millis();
}
if(millis() - start_time >= 20*1000) {
do_some_work2();
start_time2 = millis();
}
}
I use HELTEC ESP32 LORA.
Board selected in arduino HELTEC WIFI LORA 32 (V2)
My firmware works fine, but same firmware one year later the esp32 start to reset in the interrupt.
the message in the terminal
Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1).
I checked the :
1.- Watch dog, it did not work
2.- decrease the program inside the interrupt, it did not work.
Finally, the solution WAS...
Downgrade the ESp32 by expressive system library from 2.0.6 to 2.0.3
I hope it be useful
Bye

Error on sending AT+CWJAP_DEF commands to ESP8266

I am trying to send AT commands to ESP8266 to get connected with internet with the Wifi.
When I am sending AT and AT+RST command on serial monitor then I am getting OK and ready response which seems perfect.
Then I am sending AT+CWLAP to get list of available wifi networks which is also executing correctly.
AT+CWLAP
+CWLAP:(3,"Moto",-42,"a4:70:d6:7a:fa:6c",1,25,0)
+CWLAP:(4,"PRANJAL",-95,"1c:a5:32:3d:f5:c4",1,-16,0)
+CWLAP:(2,"VIHAN",-94,"c8:3a:35:2f:1d:81",1,-21,0)
+CWLAP:(3,"Tenda",-93,"c8:3a:35:20:a9:b1",9,-4,0)
OK
Then I sent AT+CWMODE? which is also perfect.
AT+CWMODE?
+CWMODE:1
OK
Now I am trying to connect ESP8266 with above listed Wifi with this command, it is sending an ERROR on serial monitor.
AT+CWJAP_DEF="Moto","reset1234"
Error
⸮=IRe"Moto","reset1234"
ERROR
Can anyone suggest me what could be the reason of this issue ?
#include "SoftwareSerial.h"
SoftwareSerial esp8266(2, 3); // RX, TX
void setup()
{
Serial.begin(9600); // serial port used for debugging
esp8266.begin(9600); // your ESP's baud rate might be different
}
void loop()
{
if(esp8266.available()) // check if the ESP is sending a message
{
while(esp8266.available())
{
char c = esp8266.read(); // read the next character.
Serial.write(c); // writes data to the serial monitor
}
}
if(Serial.available())
{
delay(10); // wait to let all the input command in the serial buffer
// read the input command in a string
String cmd = "";
while(Serial.available())
{
cmd += (char)Serial.read();
}
// send to the esp8266
esp8266.println(cmd);
}
}
The current official AT command set seems to be documented on https://github.com/espressif/ESP8266_AT/wiki/AT_Description
http://espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
https://www.itead.cc/wiki/ESP8266_Serial_WIFI_Module#AT_Commands
If the module is to be configured as a client, i.e. to connect to an access point, the following AT commands have to be sent (11500 baud 8N1, CR-LF line termination):
AT+RST
AT+CWMODE=3 (1 is "Station" only (wifi client), 3 is mixed mode "Station and Access-Point", both should work)
AT+CWJAP="Moto","reset1234"
AT+CWJAP_CUR="Moto","reset1234" (temporary) or
AT+CWJAP_DEF="Moto","reset1234" (stored)
For reference, a "success story" (ESP8266 module with USB-UART, Software: HTerm, Access Point with WPA2 (both TKIP / CCMP tested)):
AT<\r><\r><\n><\r><\n>
OK<\r><\n>
AT+RST<\r><\r><\n><\r><\n>
OK<\r><\n>
<\r><\n>
ets Jan 8 2013,rst cause:2, boot mode:(3,6)<\r><\n>
<\r><\n>
load 0x40100000, len 1856, room 16 <\r><\n>
tail 0<\r><\n>
chksum 0x63<\r><\n>
load 0x3ffe8000, len 776, room 8 <\r><\n>
tail 0<\r><\n>
chksum 0x02<\r><\n>
load 0x3ffe8310, len 552, room 8 <\r><\n>
tail 0<\r><\n>
chksum 0x79<\r><\n>
csum 0x79<\r><\n>
<\r><\n>
2nd boot version : 1.5<\r><\n>
SPI Speed : 40MHz<\r><\n>
SPI Mode : DIO<\r><\n>
SPI Flash Size & Map: 32Mbit(512KB+512KB)<\r><\n>
jump to run user1 # 1000<\r><\n>
<\r><\n>
??r?d?l<18>?<31><\0><\f>?l`<3>??s?l?<28>?<19>?<4><4><4>$ <2>??r?$<4>??<27>?<4><4>ll`<3>r$?<18>?"<\0>????"<4>l?cs|<\f>?`?22???<27>BB<18>c??o??<18>NN?<16><2><\0><2>d$??<2>d??<\0>?<4>d??<\0>ll????d??l`<2>?<2>N?<\0>????"<4>d??<28>p<4><4><2><2>???"b<4>$<4>?"prlrl<\r><\n>
Ai-Thinker Technology Co. Ltd.<\r><\n>
<\r><\n>
ready<\r><\n>
WIFI DISCONNECT<\r><\n>
AT+CWMODE?<\r><\r><\n>+CWMODE:3<\r><\n>
<\r><\n>
OK<\r><\n>
AT+CWJAP_CUR="Moto","reset1234"<\r><\r><\n>
WIFI CONNECTED<\r><\n>
WIFI GOT IP<\r><\n>
<\r><\n>
OK<\r><\n>
AT+CIFSR<\r><\r><\n>+CIFSR:APIP,"0.0.0.0"<\r><\n>
+CIFSR:APMAC,"00:00:00:00:00:00"<\r><\n>
+CIFSR:STAIP,"0.0.0.0"<\r><\n>
+CIFSR:STAMAC,"00:00:00:00:00:00"<\r><\n>
<\r><\n>
OK<\r><\n>
AT+GMR<\r><\r><\n>AT version:1.1.0.0(May 11 2016 18:09:56)<\r><\n>
SDK version:1.5.4(baaeaebb)<\r><\n>
Ai-Thinker Technology Co. Ltd.<\r><\n>
Jun 13 2016 11:29:20<\r><\n>
OK<\r><\n>
This also works with mode=1.
Major rewrite.
Questions and ideas to test:
what is your module firmware version?
access point issues (e.g. MAC address restrictions)?
power supply good?
might there be any old configuration or other code running on the module?
what is the byte code of ⸮ in the error message - Is it two bytes 0x2E2E?
are you using the Arduino serial monitor for communication?
in contrast to my comment, maybe the arduino does have an influence (timing?). Try to rule this out by
doing the pass-through character-based instead of line-based, e.g.:
(end of list, no code possible otherwise:)
loop(){
if( esp8266.available() )
Serial.write(esp8266.read());
if( Serial.available() )
esp8266.write(Serial.read());
}
keeping the AVR in reset and connecting the ESP8266 serial lines directly to the USB-UART converter
Alright! I just tried to connect with different wifi and it got connected with it. It was some kinda issue with mobile hotspot.

Resources