How to know if an Arduino restarted as a result of a WDT timeout? - arduino

I have Arduino code in which I have implemented an 8-second watchdog. To test I put a for loop and everything works correctly.
I want to know if it is possible to print a message when a watchdog timeout occurs in the Arduino, specifically what I want to do is send a message by XBee when a reset has occurred caused by the watch dog. I already have the XBee logic, how do I know when this reset occurs?
I already tried the solution raised here but it doesn't work for me:
link
My Code:
#include <avr/wdt.h>
void setup() {
Serial.begin(9600);
Serial.println("turning on");
delay(1000);
watchdogsetup();
}
void loop() {
for (int i = 0; i <= 9; i++) {
Serial.println();
delay(1000);
} //Test to activate watchdog
//My code ....
//....
wdt_reset(); // reset the watch dog to zero
}

Just an idea.
When the watchdog fires, it is uncertain if the time and resources you need to send a message via XBee are still available, so that message is probably best sent after the Arduino has reset and is running normally again.
I think the watchdog timer does set a flag that survives the reset itself, but it is cleared by the bootloader, so that information is lost if you use the bootloader.
So, you need to set your own flag, and read that flag back after the Arduino has reset. What you could try is writing an interrupt handler and add some other stuff to write a flag to EEPROM, something like this (untested):
#include <EEPROM.h>
int addr = 0; // Or whatever EEPROM address you like
setup() {
if (EEPROM.read(addr) == 1) { //If a WDT flag was set
// Send panicky message by XBee here
}
EEPROM.write(addr, 0); // Reset the WDT flag
// Rest of setup() goes here
}
ISR(WDT_vect) {
EEPROM.write(addr, 1); // Set the WDT flag
}
... and hope that the Arduino hasn't crashed beyond being able to write to the EEPROM when the watchdog fires.

Related

AC Dimmer EpS32

I have an application on to control ESP32 Light Dimmer from the temperature read from a temperature sensor. The rule is very simple, when my sensor reads the temperature of more than 27ºC the lamp should be turned off by the Dimmer. However, this is not happening.
What the code does is, when the system is turned on the lamp turns on and the temperature is read from time to time, but when the temperature exceeds 27ºC the dimmer does not turn off the lamp. I think it might be something I'm doing wrong in the zero_crosss_int routine, because when the temperature reaches its limit the message "TRIAC OFF" is displayed.
Below the code used.
#define ZERO_CROSS 2
#define DIMMER_CONTROL 4
int dimming=64;
float programedTemp = 27.0;
int halfDimming=128;
int maxDimming=64;
void power(void *parameters){
tempSensor.requestTemperaturesByIndex(0);
temp=tempSensor.getTempCByIndex(0);
if(temp<programedTemp){
dimming=maxDimming;
if(temp<(programedTemp-1.0)){
dimming=maxDimming;
} else if(temp<programedTemp){
dimming++;
}
} else if(temp>programedTemp+0.9){
dimming=128;
}else{
dimming=halfDimming;
}
delay(4000);
}
void zero_crosss_int() {
if(dimming>=128){
delayMicroseconds(8.333);
digitalWrite(DIMMER_CONTROL, LOW); // triac Off
Serial.println((String) "=====>>> TRIAC OFF <<<=====");
}else{
int dimtime = (65*dimming);
delayMicroseconds(dimtime); // Off cycle
digitalWrite(DIMMER_CONTROL, HIGH); // triac firing
delayMicroseconds(8.333);
digitalWrite(DIMMER_CONTROL, LOW); // triac Off
}
}
void setup() {
pinMode(DIMMER_CONTROL, OUTPUT);
pinMode(ZERO_CROSS, INPUT);
attachInterrupt(ZERO_CROSS, zero_crosss_int, RISING);
Serial.begin(115200);
xTaskCreatePinnedToCore(power,"controlDimm",10000,NULL,0,&mainsPower,0);
}
void loop() {
}
You're doing way too much in your interrupt handler. It's amazing that it isn't just crashing constantly... the only reason that's not happening is likely because you don't do anything in loop().
It's not safe to call most of the functions you're calling in the interrupt handler. Interrupt handlers need to run for as little time as possible - other interrupts may be locked out and they may interfere with the network stack and other housekeeping functions. You absolutely should not be calling delayMicroseconds() or any Serial methods in an interrupt handler, or spending any more time there than is absolutely necessary. Almost all ESP-IDF or Arduino Core functions are not safe to call from inside an interrupt handler - the interrupt handler may interrupt another call to them while they're in an inconsistent state, or may change hardware settings while they're in the middle of using that hardware.
Your code would be much better if you structured it like this:
volatile bool zero_crossing_flag = false;
void IRAM_ATTR zero_cross_int() {
zero_crossing_flag = true;
}
void loop() {
if(zero_crossing_flag) {
zero_crossing_flag = false;
if(dimming>=128){
delayMicroseconds(8.333);
digitalWrite(DIMMER_CONTROL, LOW); // triac Off
Serial.println((String) "=====>>> TRIAC OFF <<<=====");
}else{
int dimtime = (65*dimming);
delayMicroseconds(dimtime); // Off cycle
digitalWrite(DIMMER_CONTROL, HIGH); // triac firing
delayMicroseconds(8.333);
digitalWrite(DIMMER_CONTROL, LOW); // triac Off
}
}
}
The IRAM_ATTR attribute on zero_cross_int() tells the compiler that this code must always be available. If you write an interrupt handler without IRAM_ATTR it's basically luck if it executes properly.
Restructuring your code this way will probably not solve the problem you're asking about, but it will allow it to run in a stable, reproducible way, which it's unlikely to the way it's written now.
Use your ZCD input to generate an interrupt. In the ISR start a Timer which generates another interrupt within 0ms(Full power) to 10ms(completely off) of the ZCD interrupt.
I don't understand to Switch off the lamp why are you using TRIAC instead of a Relay.

MPU9250 getting stuck in reset loop with ESP8266 using WOM

I've been experimenting with the sleep options of both the ESP8266 wifi chip and the MPU9250 IMU. The ESP has a deep sleep command which essentially shuts the chip down apart from the real time clock until the RESET pin is pulled low, either by the ESPs GPIO16 or by an external interrupt.
The MPU9250 provides this interrupt in the form of its WOM (Wake On Motion) function, which brings the chip to bare minimum functionality until it detects motion on the built-in accelerometer, at which point its INT pin gets pulled high (I attached this pin to the gate of an NMOS transistor between the RESET pin of the ESP and GND to invert the interrupt).
When I set it up and use the following code, however, the setup enters a reset loop; both print statements execute, but I am unsure if the ESP actually has time to execute the DeepSleep command because it instantly resets as soon as the "Got here" prints and doesn't wait for motion.
However, if I disconnect and reconnect the INT connection from the NMOS while the program is running, it works temporarily and sleeps until it detects motion, at which point the reset loop begins again (even if the MPU9250 is kept completely still after moving). This means the WOM functionality is working, but something is causing the INT pin to ping high when it shouldn't be, and I can't figure out what the problem is. Does anyone know what the problem could be? Is it something I can fix with code alone?
Main code (loop() is empty):
#include <quaternionFilters.h>
#include <MPU9250.h>
#include <ESP8266WiFi.h>
extern "C" {
#include "gpio.h"
}
extern "C" {
#include "user_interface.h"
}
MPU9250 myIMU;
void setup()
{
Wire.begin(5, 14);
Serial.begin(74880);
printf("WAKE ME UP INSIDE");
delay(500);
sensorMpu9250WomEnable();
printf("Got Here");
ESP.deepSleep(0, WAKE_RF_DEFAULT);
}
In a separate file:
bool sensorMpu9250WomEnable(void)
{
uint8_t val;
// Clear registers
val = 0x80;
myIMU.writeByte(MPU9250_ADDRESS, PWR_MGMT_1, val);
delay(10);
// Enable accelerometer, disable gyro
val = 0x07;
myIMU.writeByte(MPU9250_ADDRESS, PWR_MGMT_2, val);
delay(10);
// Set Accel LPF setting to 184 Hz Bandwidth
val = 0x01;
myIMU.writeByte(MPU9250_ADDRESS, ACCEL_CONFIG2, val);
delay(10);
// Enable Motion Interrupt
val = 0x40;
myIMU.writeByte(MPU9250_ADDRESS, INT_ENABLE, val);
delay(10);
// Enable Accel Hardware Intelligence
val = 0xC0;
myIMU.writeByte(MPU9250_ADDRESS, MOT_DETECT_CTRL, val);
delay(10);
// Set Motion Threshold
val = 0x40;
myIMU.writeByte(MPU9250_ADDRESS, WOM_THR, val);
delay(10);
// Set Frequency of Wake-up
val = 6;
myIMU.writeByte(MPU9250_ADDRESS, LP_ACCEL_ODR, val);
delay(10);
// Enable Cycle Mode (Accel Low Power Mode)
val = 0x20;
myIMU.writeByte(MPU9250_ADDRESS, PWR_MGMT_1, val);
delay(10);
return true;
}
Thank you very much for this snippets, they helped me to get my project up and running.
I could fix the issue by adding a delay before start the deep sleep:
Wire.begin(I2C_SDA, I2C_SCL);
Serial.begin(115200);
Serial.println("WAKE ME UP INSIDE");
delay(500);
sensorMpu9250WomEnable();
Serial.println("Got Here");
Serial.flush();
delay(1000);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_27, 1);
esp_deep_sleep_start();
Hope that helps you too.

ATTiny85 Serial communication with Bluetooth Module

For a simple project, I would like to use an ATTiny85 connected to an HC-06 Bluetooth module, so it can talk to my Android phone.
I wrote code for my Arduino Uno and it worked as expected. When I changed the code to use on my ATTiny85 I got an error saying that 'Serial' was not declared in this scope and assumed that the ATTiny does not support Hardware Serial.
I need to read a String when received and sleep the MCU when not receiving. I went to use SoftwareSerial and was not able to get a String, just the first char.
I approached it in some way, like defining a char string[10]; as global and string[i] = mySerial.read(); i++; inside the loop, but it keeps not working. Whether it is the sleep, or my work to read data, I couldn't make it work.
Can someone provide a way to put a ATTiny85 to sleep, wake up to receive a String through Serial and sleep until the next data through Serial, please?
To sleep I'm using
void sleep() {
GIMSK |= _BV(PCIE); // Enable Pin Change Interrupts
PCMSK |= _BV(PCINT3); // Use PB3 as interrupt pin
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable(); // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
sei(); // Enable interrupts
sleep_cpu(); // sleep
// woke up
cli(); // Disable interrupts
PCMSK &= ~_BV(PCINT3); // Turn off PB3 as interrupt pin
sleep_disable(); // Clear Sleep Enable bit
sei(); // Enable interrupts
}
ISR(PCINT3_vect) {
}
And my loop is something like
char inputString[10];
int i = 0;
void loop() {
sleep();
if (serial.available() > 0) {
char inputChar = serial.read();
if (inputChar == '2') { //Char to break
//Do something and reset i
} else {
inputString[i] = inputChar;
}
i++;
}
}
Thanks to all.
if (serial.available() > 0) {
That's a one-time thing. You should put this in a while loop.
while (serial.available() > 0) {
char inputChar = serial.read();
if (inputChar == '2') { //Char to break
//Do something and reset i
} else {
inputString[i] = inputChar;
}
i++;
}
Wouldn't hurt to check i after incrementing, too.

Garbage text in serial monitor from Arduino

I have a problem with my brand new Arduino, it seems that
no matter what I print with
Serial.println()
be it numbers, strings or anything else, I get garbage
on the Arduino serial monitor:
Not even the simplest hello world program works.
Could you help me identify the problem and solve it?
I found the solution :)
I wrote a test program and found a working baud-rate at 600.
My test program:
long baudrates[] = {600,1200,2400,4800,9600,14400,19200,28800,38400,56000,57600,115200,128000,256000};
unsigned char baudcounter = 0;
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication
Serial.begin(baudrates[baudcounter]);
}
// the loop routine runs over and over again forever:
void loop() {
Serial.println();
Serial.println(baudrates[baudcounter]);
Serial.println(" !\"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~");
Serial.println();
baudcounter++;
baudcounter %= sizeof(baudrates)/sizeof(long);
delay(1000); // delay
Serial.begin(baudrates[baudcounter]); // switch baudrate
}

Arduino Loop and alarm

I'm working on my first physical computing project with an arduino, well actually a seeduino stalker 2.1. I'm building a device to record water collection rates over time.
Getting the project set up and running hasn't been all that hard, until today that is. Inside the main loop I have a call to the a method that handles the logging. I also now an alarm delay to handle a timer repeat I need in order to summarize data and send it via SMS to a recipient number.
The issue is that when the alarm.repeat() is active it preempts the logging of the data. The question is: why is the logging method inside the loop not working when the alarm.delay is there?
void setup() {
Serial.begin(9600);
Wire.begin();
setTime(1,17,0,1,1,13); // set time
Alarm.timerRepeat(60, Repeats); //set repeater
}
void loop(){
logging(); //call logging
Alarm.delay(1300); //for repeater
}
void Repeats(){
Serial.println("the repeater fired"); // just to see it working
}
void logging(){
val = digitalRead(Sensor_Pin); // read Sensor_Pin
if (val == HIGH) {
// If Sensor N.C. (no with magnet) -> HIGH : Switch is open / LOW : Switch is closed
// If Sensor N.0. (nc with magnet) -> HIGH : Switch is closed / LOW : Switch is open
digitalWrite(Led_Pin, LOW); //Set Led low
//Serial.print("status -->");
//Serial.println("low");
//delay(500);
} else {
digitalWrite(Led_Pin, HIGH); //Set Led high
logdata();
}
}
void logdata(){
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File myFile = SD.open("datalog.txt", FILE_WRITE);
// if the file opened okay, write to it:
if (myFile) {
//DateTime now = RTC.now();
//String myString = readTimestamp(now);
time_t t = now();
String aDate = String(year(t))+"/"+String(month(t))+"/"+String(day(t))+" "+String(hour(t))+":"+String(minute(t))+":"+String(second(t));
myFile.println(aDate);
// close the file:
myFile.close();
Serial.println(aDate);
delay(500); } else {
// if the file didn't open, print an error:
// Serial.println("error opening DATALOG.TXT");
}
}
Q: Why must I use Alarm.delay() instead of delay()? A: Task scheduling
is handled in the Alarm.delay function. Tasks are monitored and
triggered from within the Alarm.delay call so Alarm.delay should be
called whenever a delay is required in your sketch. If your sketch
waits on an external event (for example, a sensor change), make sure
you repeatedly call Alarm.delay while checking the sensor.
From the FAQ of the Alarm library. So it looks like Alarm.Delay is just like the standard delay but can be interrupted by scheduled events. Your logging call isn't scheduled, it just happens at the start of the loop. ..is your logging not happening at all? It looks like it should be called at the start of each loop, then a 1300 delay with your repeater firing during the delay.
On your logdata() function you're calling delay(50) instead of Alarm.delay(50).
As caude pointed, you have to use Alarm.delay when a delay is needed, otherwise the delay will mess up with the alarms.
I think you could have done in other way using timer library. If you say the data has to be logged every second,it easier to done by timer.Example code
#include <SimpleTimer.h>
// the timer object
SimpleTimer timer;
// a function to be executed periodically
void repeatMe() {
Serial.print("Uptime (s): ");
Serial.println(millis() / 1000);
}
void setup() {
Serial.begin(9600);
timer.setInterval(1000, repeatMe);
}
void loop() {
timer.run();
}

Resources