Hello everyone,
Currently I am trying to use several interrupts to wakeup an autonomo, but for some reason, the board doesnt wakeup from any interrupts. This is the code I am using:
> void setup()
> {
> //Definieer pin 0, 4 en 10 als input
> pinMode(INT1, INPUT);
> pinMode(DHTpin, INPUT);
> pinMode(INT2, INPUT);
> //activeer ISR wanneer de deur opent
> attachInterrupt(INT1, ISRdeur, FALLING);
> //activeer ISR wanneer er beweging wordt gedetecteert
> attachInterrupt(INT2, ISRbeweging, RISING);
> //activeer ISR eens per uur
> rtc.begin();
> rtc.setAlarmSeconds(10);
> rtc.enableAlarm(RTCZero::MATCH_SS); // alarm eens per minuut
> rtc.attachInterrupt(ISR60min); // attach een interrupt aan het RTC alarm
>
> SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; //Zet slaap register op mode Deep sleep
>
>
> // Startup delay na setup, tbv uploaden nieuwe sketch
> delay(15000);
> SerialUSB.println("Starting");
> }
> /* ******************************
> * *
> * Interrupts *
> * *
> * ******************************/
> void ISRdeur()
> {
> SerialUSB.println("interrupt deur");
> msOudDeur = millis();
> deurDetectie = true;
> }
> void ISRbeweging()
> {
> SerialUSB.println("beweging");
> PIRCount ++;
> }
> void ISR60min()
> {
> DHTmeting = true;
> }
> /* ******************************
> * *
> * Functies *
> * *
> * ******************************/
> uint16_t bericht(uint8_t tempmin, uint8_t tempmax, bool deur, bool pir, bool batt)
> {
> return ((uint16_t) tempmin << 10) | ((uint16_t) tempmax << 4) | ((uint16_t) deur << 3) | ((uint16_t) pir << 2) | ((uint16_t) batt << 1);
> }
> float getRealBatteryVoltageMV()
> {
> uint16_t batteryVoltage = analogRead(BATVOLTPIN);
> return (ADC_AREF / 1.023) * (BATVOLT_R1 + BATVOLT_R2) / BATVOLT_R2 * batteryVoltage;
> }
> /* ******************************
> * *
> * main programma *
> * *
> * ******************************/
> void loop()
> {
> msNieuwDeur = millis();
> /* ******************************
> * Deurdetectie *
> * ******************************/
>
> if ((deurDetectie) and ((msNieuwDeur - msOudDeur) >= 1000))
> {
> if (not digitalRead(INT1))
> {
> SerialUSB.println("Deur geopend");
> deurGeopend = true;
> detachInterrupt(INT1);
> }
> deurDetectie = false;
> }
>
> /* ******************************
> * Bewegingdetectie *
> * ******************************/
> if (PIRCount >= 5)
> {
> SerialUSB.println("Beweging gedetecteerd");
> BewegingPIR = true;
> PIRCount = 0;
> detachInterrupt(INT2);
> }
> /* ******************************
> * Temp/luchtv meting *
> * ******************************/
> if (DHTmeting)
> {
> // lees temperatuur en lichtvochtigheid
> dht.begin();
> luchtvNu = dht.readHumidity();
> tempNu = dht.readTemperature();
> // zoek de hoogste en laagste temperatuur van afgelopen 24 uur
> if (tempNu < tempmin)
> {
> tempmin = tempNu;
> }
> if (tempNu > tempmax)
> {
> tempmax = tempNu;
> }
>
> // tel alle luchtvochtigheid waarden bij elkaar op
> luchtvTot += luchtvNu;
> dagCounter ++;
> SerialUSB.println(dagCounter);
> SerialUSB.println("Luchtv is " + String(luchtvNu));
> SerialUSB.println("Opgetelde Luchtv is " + String(luchtvTot));
> SerialUSB.println("Temp is " + String(tempNu));
> DHTmeting = false;
> }
> /* ******************************
> * Zenden LoRa bericht *
> * ******************************/
> // Zend het LoRa bericht eens per 24 uur. Dit gebeurt wanneer er 24 keer een één-uurs interrupt heeft plaatsgevonden
> if (dagCounter == 24)
> {
> loraZenden = true;
> luchtvGem = 0 ;
> luchtvGem = (luchtvTot / 24); // bereken de gemiddelde luchtvochtigheid
> luchtvTot = 0 ;
> dagCounter = 0 ;
> BattLow = (getRealBatteryVoltageMV() < 3350); // Batterij wordt als "laag voltage" gezien wanneer deze lager is dan 3.35 Volt
> loraBericht = (String(bericht(tempmin, tempmax, deurGeopend, BewegingPIR, BattLow)) + String(luchtvGem)) ;
> SerialUSB.println("**************************************");
> SerialUSB.println("batterij: " + String(getRealBatteryVoltageMV())/* + String(loraBericht)*/);
> SerialUSB.println("minimale temperatuur: " + String(tempmin)/* + String(loraBericht)*/);
> SerialUSB.println("maximale temperatuur: " + String(tempmax)/* + String(loraBericht)*/);
> SerialUSB.println("Deur geopend: " + String(deurGeopend)/* + String(loraBericht)*/);
> SerialUSB.println("Beweging: " + String(BewegingPIR)/* + String(loraBericht)*/);
> SerialUSB.println("batterij leeg: " + String(BattLow)/* + String(loraBericht)*/);
> SerialUSB.println("gemiddelde luchtvochtigheid: " + String(luchtvGem)/* + String(loraBericht)*/);
> SerialUSB.println("Lora bericht: " + String(loraBericht));
> SerialUSB.println("**************************************");
> }
> if (dagCounter == 0)
> {
> tempmax = 0;
> tempmin = 50;
> }
> if (loraZenden)
> {
> // Zet de Pinnen naar de LoRabee hoog
> digitalWrite(BEE_VCC, HIGH);
> loraSerial.begin(LoRaBee.getDefaultBaudRate());
>
> if (LoRaBee.initABP(loraSerial, devAddr, appSKey, nwkSKey, true))
> {
> SerialUSB.println("Connection to the network was successful.");
> }
> else
> {
> SerialUSB.println("Connection to the network failed!");
> }
>
> switch (LoRaBee.send(1, (uint8_t*)loraBericht.c_str(), loraBericht.length()))
> {
> case NoError:
> SerialUSB.println("Successful transmission.");
> loraVerzonden = true;
> break;
> default:
> break;
> }
> }
> if (loraVerzonden)
> {
> loraZenden = false;
> //activeer ISR wanneer de deur opent
> attachInterrupt(INT1, ISRdeur, FALLING);
> //activeer ISR wanneer er beweging wordt gedetecteert
> attachInterrupt(INT2, ISRbeweging, RISING);
> }
> /* ******************************
> * Processor naar slaapmode *
> * ******************************/
> // Als aan alle voorwaarden is voldaan, gaat de processor in deep-sleep stand
>
> if ((not deurDetectie) and (not DHTmeting) and (not loraZenden))
> {
> __WFI();
> }
> }
How come none of the interrupts wakeup my application?
The pin CHANGE type interrupts will not work in sleep mode without extra configuration of the GCLK which the EIC module is configured with. That is, CHANGE, RISING, and FALLING will not work but HIGH and LOW will.
The reason for this is because those CHANGE modes require an active clock. The default setup the GCLK connected to the EIC goes to sleep when the MCU does.
The RTC interrupt should work regardless.
Could you try removing the two calls to attachInterrupt() used for the two pin interrupts and test it again to see if the RTC alarm interrupt works?
I removed the attachinterrupt() functions from the setup and (LoraVerzonden) parts of my code, however, this does not seem to change a thing. After the initial “starting” message on the hyperterminal, no other messages come through.
One other thing, for the EIC interrupts on the SAMD platform you use the pin numbers. i.e. 4 for D4 etc. This is different to the ATMega boards where you use the external interrupt number.
What I find odd is that the RTC is not waking the board once per minute.
Is it possible that your code is freezing somewhere in the DHTmeting block?
Could you try switching on a LED before entering that block and then turning it off after.
I defined the pins as
//pin definities
#define INT1 0
#define INT2 10
#define DHTpin 4
Is this wrong? Without the __WFI() function, these seem to work.
I will try switching the led on and off.
Yes that looks fine, INT1 is on D0, INT2 is on D10 and DHTpin is using D4.
If you must use the CHANGE type interrupts, have a look at this post I made on the Arduino forum:
http://forum.arduino.cc/index.php?topic=410699.msg2827922#msg2827922
I’m still curious why the RTC isn’t waking the board though. I have a feeling that it is getting stuck after that first RTC wakeup.
I tried with the led, and the first time it switched the led on, printed the DHTmeting lines and switched the led off, however, it doesn’t wakeup anymore after that.
Then I resetted the Autonomo, to see if it would do this again, but now the autonomo skipped the DHTmeting part and went to sleep immediatly after starting (I added a printline “Sleeping” before the __WFI() function)
I have encountered some unexpected behaviour:
I am trying to figure out why the interrupt doesnt wake up my program, so I have been playing with the example sketch:
#include <RTCZero.h>
RTCZero rtc;
void setup()
{
rtc.begin();
// Set the alarm at the 10 second mark
rtc.setAlarmSeconds(10);
// Match only seconds (Periodic alarm every minute)
rtc.enableAlarm(RTCZero::MATCH_SS);
// Attach ISR
rtc.attachInterrupt(RTC_ISR);
// Set LED pin as output
pinMode(13, OUTPUT);
// Set sleep mode
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
// Sleep sketch startup delay
delay(15000);
}
void RTC_ISR()
{
digitalWrite(13, HIGH);
delayMicroseconds(500000);
digitalWrite(13, LOW);
}
void loop()
{
// Disable USB
//USB->DEVICE.CTRLA.reg &= ~USB_CTRLA_ENABLE;
//Enter sleep mode
SerialUSB.println("Sleep");
__WFI();
// ...Sleep
SerialUSB.println("Wakeup");
// Enable USB
//USB->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE;
// Stay awake for two seconds
delay(2000);
}
I added two printlines, Sleep and Wakeup Just to see if the interrupt works ads intended. I was under the assumption that after an interrupt, the autonomo would continue its program the line below the function that was interrupted (In this case below the __WFI() function.
However, when monitoring the led light(this means an ISR was called) the autonomo doesn’t output “Wakeup”. Why is this?
Edit: It does not even print a second “sleep” after the first one, eventhrough the program MUST go past that function to encounter the WFI function
Don’t expect the SerialUSB to function correctly while using sleep mode.
Unlike the ATMega boards, which use a separate FTDI chip to communicate with the host machine, the SAMD platform has an on-chip USB module. Disabling that module, or entering sleep mode will end the session with the host machine.
This means that you will have to reopen the terminal connection after each wake-up.
Aah so that could mean the autonomo DOES wakeup, there is just no way for me to check?
I would recommend adding a LED flash everytime the board wakes up. Then either power the board either by battery or by USB but without opening a terminal session (console window or other).
You should see the LED flash once per minute, which will show that it is waking regularly.
There is another issue with using output to the SerialUSB stream and sleep mode. Once the connection has been closed, by going into sleep mode, further writes to the SerialUSB stream can block as they are waiting for the transmission of the data to complete. This is probably why you were only seeing one wake event.
I see! I will try without the USB writes then!
If you have a device like a USARTbee or another Ardunio board with a serial passthrough running, you can send the debug output through that other device using one of the Autonomo’s UARTs. As the other device is managing the USB terminal session, it is not affected by the Autonomo entering sleep mode.
I am currently using the autonomo with a LoRaBee, so I am unable to send lots of messages due to the 1% dutycycle restriction. However, I am now waiting on my first message to arrive
I recieved my message. that atleast tells me the 60sec alarm works! I will now try to confirm the other interrupts
While using this code:
void ISRdeur()
{
digitalWrite(LED_BUILTIN, HIGH);
//SerialUSB.println("interrupt deur");
msOudDeur = millis();
deurDetectie = true;
delay(500);
digitalWrite(LED_BUILTIN, LOW);
}
void ISRbeweging()
{
digitalWrite(LED_BUILTIN, HIGH);
//SerialUSB.println("beweging");
PIRCount ++;
delay(500);
digitalWrite(LED_BUILTIN, LOW);
}
However, when I move my hand in front of the PIR, or open the door (Reed switch) at first it does not seem to do anything and after a few tries, the led goes on without ever going off.
It is generally bad practice to do any real work in the ISRs. It is a much better idea to set a flag and then test for that flag in the main loop method.
The reason for this is that interrupts can potentially block each other.
On the AVR platform there is only one priority level for interrupts, so all interrupts are suspended while an ISR is executing. Call a method like delay() will always cause issues as delay relies on a global counter which is incremented by a timer driven interrupt. Hence delay will never return when called from an ISR as the counter will never reach the specified target value.
The SAMD platform has multiple levels of priority. If higher priority level interrupt is activated, it will suspend the current ISR and then handle the new higher priority interrupt. However, interrupts of equal or lower priority will be suspended until the original ISR is finished. I believe the EIC interrupts are set to the highest level by default (in the Arduino SAMD core), this results in similar behaviour as with the AVR platform.
I have encountered some strange behaviour:
I am currently trying to check wether the interrupts even work as intended on my autonomo.
when using the code from your example:
SleepChangeInterrupt.ino
(Using pin 0 instead of 4)
It seems like the interrupt works during the 10 seconds setup delay, but when the program enters the main loop and the USB gets disabled, the board doesn’t respond to the interrupt anymore. Is there something wrong with my board? I assume the testing sketches are supposed to run as intended.
Changed the code a little to see if doing work inside of the ISR was the problem.
currently using this code:
#define INT1 4
bool led = false;
void setup()
{
pinMode(INT1, INPUT);
pinMode(13, OUTPUT);
//Attach the interrupt and set the wake flag
attachInterrupt(INT1, ISR, RISING);
// Set the XOSC32K to run in standby
SYSCTRL->XOSC32K.bit.RUNSTDBY = 1;
// Configure EIC to use GCLK1 which uses XOSC32K
// This has to be done after the first call to attachInterrupt()
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(GCM_EIC) |
GCLK_CLKCTRL_GEN_GCLK1 |
GCLK_CLKCTRL_CLKEN;
//Set sleep mode
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
//Start delay of 10s to allow for new upload after reset
delay(10000);
}
void ISR()
{
led = true;
}
void loop()
{
if (led == true)
{
//Blink the LED for 5s
digitalWrite(13, HIGH);
delayMicroseconds(500000);
digitalWrite(13, LOW);
led = false;
}
//Disable USB
USB->DEVICE.CTRLA.reg &= ~USB_CTRLA_ENABLE;
//Enter sleep mode
__WFI();
//...Sleep
//Enable USB
USB->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE;
//Stay awake 10s
delay(10000);
}
Gives me the same issue. Exactly when I hear the autonomo lose USB connection (windows sound of disconnecting USB), it stops responding to the Interrupt. When I comment the whole disabling, sleeping, enabling part, the interrupt works fine.
I have tried that sketch just now. I have a button attached to D4.
The behaviour is, after the initial setup, when the button is pressed the board wakes up and waits for 10s before flashing the LED and then going back to sleep.
I’m using IDE version 1.6.12 and Sodaq SAMD v1.6.9 with an Autonomo Rev.3.