Sensor readings inbetween Deep Sleep using RTCZero library [SAMD21]

Hello everyone,

im fairly new to the topic of programming Boards, especially I'm new to C. Through research on this site and other sites I've managed to put my MKR WAN 1300 to Deep Sleep. At the moment, the Board sleeps for a minute, wakes up to blink 2 times and goes back to sleep afterwards for a minute till it wakes up again to blink 2 times again. Now, I want to realize a temperature reading inbetween the 2 blinks of the Board LED while it's awake. This will be some useful knowledge for me, because I want to use LoRaWAN later on to send temperature measurements to the The Things Network. I already managed to do that with my Board, but I want to realize a Deep Sleep inbetween it's readings.

My code for the temperature reading with the DS18B20 temperature sensor:

/********************************************************************/
// libraries
#include <OneWire.h> 
#include <DallasTemperature.h>
/********************************************************************/
// Data wire is plugged into pin 6 on the Arduino 
#define ONE_WIRE_BUS 6
/********************************************************************/
// Setup a oneWire instance to communicate with any OneWire devices  
// (not just Maxim/Dallas temperature ICs) 
OneWire oneWire(ONE_WIRE_BUS); 
/********************************************************************/
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);
/********************************************************************/ 
void setup(void) 
{ 
 // start serial port 
 Serial.begin(9600); 
 Serial.println("Dallas Temperature IC Control Library Demo"); 
 // Start up the library 
 sensors.begin(); 
} 

void loop(void) 
{ 
 // call sensors.requestTemperatures() to issue a global temperature 
 // request to all devices on the bus 
/********************************************************************/
 Serial.print(" Requesting temperatures..."); 
 sensors.requestTemperatures(); // Send the command to get temperature readings 
 Serial.println("DONE"); 
/********************************************************************/
 Serial.print("Temperature is: "); 
 Serial.print(sensors.getTempCByIndex(0)); // Why "byIndex"?  
   // You can have more than one DS18B20 on the same bus.  
   // 0 refers to the first IC on the wire 
   delay(1000); 
}

My code for realizing the Deep Sleep with the board (Reference 1; Reference 2)

#include <RTCZero.h>

/* Create an rtc object */
RTCZero rtc;

/* Change these values to set the current initial time */
const byte seconds = 0;
const byte minutes = 00;
const byte hours = 00;

/* Change these values to set the current initial date */
const byte day = 24;
const byte month = 9;
const byte year = 16;

bool matched = false;

void setup() 
{
  delay(10000); //delay so we can see normal current draw for a timespan e.g. 10 seconds
  pinMode(LED_BUILTIN, OUTPUT); //set LED pin to output
  digitalWrite(LED_BUILTIN, LOW); //turn LED off

  rtc.begin(); //Start RTC library, this is where the clock source is initialized

  rtc.setTime(hours, minutes, seconds); //set time
  rtc.setDate(day, month, year); //set date

  rtc.setAlarmTime(00, 00, 10); //set alarm time to go off in 10 seconds
  
  //following two lines enable alarm, comment both out if you want to do external interrupt
  rtc.enableAlarm(rtc.MATCH_HHMMSS); //set alarm
  rtc.attachInterrupt(alarmMatch); //creates an interrupt that wakes the SAMD21
  
  //puts SAMD21 to sleep
  rtc.standbyMode(); //library call
  //samSleep(); //function to show how call works
}

void loop() {
  if (matched) {
    matched = false;
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);

    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    int alarmMinutes = rtc.getMinutes();
    alarmMinutes += 1;
    if (alarmMinutes >= 60) {
      alarmMinutes -= 60;
    }

    rtc.setAlarmTime(rtc.getHours(), alarmMinutes, rtc.getSeconds());
    rtc.standbyMode();    // Sleep until next alarm match
  }
}

//functions
void samSleep()
{
  // Set the sleep mode to standby
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  // SAMD sleep
  __WFI();
}

void alarmMatch() {
  matched = true;
}

Now I've combined both codes like that, so that the serial monitor shows me some temperature readings (on paper):

//libraries
#include <OneWire.h> 
#include <DallasTemperature.h>
#include <RTCZero.h>

// Data wire is plugged into pin 6 on the Arduino 
#define ONE_WIRE_BUS 6

// Setup a oneWire instance to communicate with any OneWire devices  
// (not just Maxim/Dallas temperature ICs) 
OneWire oneWire(ONE_WIRE_BUS); 
/********************************************************************/
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);
/********************************************************************/ 

/* Create an rtc object */
RTCZero rtc;

/* Change these values to set the current initial time */
const byte seconds = 0;
const byte minutes = 00;
const byte hours = 00;

/* Change these values to set the current initial date */
const byte day = 24;
const byte month = 9;
const byte year = 16;

bool matched = false;

void setup() 
{
  delay(10000); //delay so we can see normal current draw for a timespan e.g. 10 seconds
  pinMode(LED_BUILTIN, OUTPUT); //set LED pin to output
  digitalWrite(LED_BUILTIN, LOW); //turn LED off

  // setup Alarm for waking the board up from it's deep sleep
  rtc.begin(); //Start RTC library, this is where the clock source is initialized

  rtc.setTime(hours, minutes, seconds); //set time
  rtc.setDate(day, month, year); //set date

  rtc.setAlarmTime(00, 00, 10); //set alarm time to go off in 10 seconds
  
  //following two lines enable alarm, comment both out if you want to do external interrupt
  rtc.enableAlarm(rtc.MATCH_HHMMSS); //set alarm
  rtc.attachInterrupt(alarmMatch); //creates an interrupt that wakes the SAMD21 which is triggered by a FTC alarm

  // setup temperature readings
  // start serial port 
  Serial.begin(9600); 
  Serial.println("Dallas Temperature IC Control Library Demo"); 
  // Start up the library 
  sensors.begin(); 
  
  //puts SAMD21 to sleep
  rtc.standbyMode(); //library call
  //samSleep(); //function to show how call works
}

void loop() {
  if (matched) {
    matched = false;
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    
    // call sensors.requestTemperatures() to issue a global temperature 
    // request to all devices on the bus 
    /********************************************************************/
    Serial.print(" Requesting temperatures..."); 
    sensors.requestTemperatures(); // Send the command to get temperature readings 
    Serial.println("DONE"); 
    /********************************************************************/
    Serial.print("Temperature is: "); 
    Serial.print(sensors.getTempCByIndex(0)); // Why "byIndex"?  
    // You can have more than one DS18B20 on the same bus.  
    // 0 refers to the first IC on the wire 

    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    int alarmMinutes = rtc.getMinutes();
    alarmMinutes += 1;
    if (alarmMinutes >= 60) {
      alarmMinutes -= 60;
    }

    rtc.setAlarmTime(rtc.getHours(), alarmMinutes, rtc.getSeconds());
    rtc.standbyMode();    // Sleep until next alarm match
  }
}

// functions 
void samSleep()
{
  // Set the sleep mode to standby
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  // SAMD sleep
  __WFI();
}

void alarmMatch() {
  matched = true;
}

This code doesnt work though. The LED draws current for 10 seconds in the beginning, then the LED goes out for a few ms and immediately lights up again and it stays like that. I appreciate any advise or help!

I've changed my code a little bit. I can kinda pin point the issue, I guess. When sensors.begin() appears as a comment in the code, the sketch works as intended. When sensors.begin() isnt a comment anymore, the sketch gets blocked after the initial 10 seconds in the void setup(), where everything else gets blocked. Could it be the case, that the RTCZero library and the DallasTemperature library dont work together, because of their individual timers? I can run my sketch with the DallasTemperature library and the RTCZero library independentely, but it seems like I cant use both together (see sketches above). Could this be the case and can somebody confirm it, who owns a MKR WAN 1300 and tries to run the Sketch below? First time with sensors.begin() as a comment and second time without being a comment?

#include <RTCZero.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
#define ONE_WIRE_BUS 6
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

/* Create an rtc object */
RTCZero rtc;

// global variables
int alarmMinutes = 0 ;  // start minute
const int alarmInterval = 1 ;  //fixed intervalls to do something in the void loop() 

/* Set up of the real time clock
/* Change these values to set the current initial time */
const byte seconds = 0;
const byte minutes = 00;
const byte hours = 00;

/* Change these values to set the current initial date */
const byte day = 24;
const byte month = 9;
const byte year = 16;

bool alarmTriggered = false;  // variable which gets switched to true for every alarm trigger

void setup() 
{
  delay(10000); //delay so we can see normal current draw for a timespan e.g. 10 seconds
  pinMode(LED_BUILTIN, OUTPUT); //set LED pin to output
  digitalWrite(LED_BUILTIN, LOW); //turn LED off

  Serial.begin(9600);
  //sensors.begin();  // Start Temperature measurement library
  
  rtc.begin(); //Start RTC library, this is where the clock source is initialized

  rtc.setTime(hours, minutes, seconds); //set time
  rtc.setDate(day, month, year); //set date

  rtc.setAlarmTime(00, 00, 10); //set alarm time to go off in 10 seconds
  // delay 10 seconds  + set alarm 10 seconds vergehen insgesamt, wegen delay und setAlarmtime
  
  //following two lines enable alarm
  rtc.enableAlarm(rtc.MATCH_HHMMSS); //set alarm
  // When the alarm triggers, alarmMatch will be called:
  rtc.attachInterrupt(alarmMatch); //creates an interrupt that wakes the SAMD21 which is triggered by a FTC alarm
  //puts SAMD21 to sleep
  rtc.standbyMode(); //library call --> _WFI() is defined inside; Microcontroller waits for interrupt to wake up
}

void loop() {
  if (alarmTriggered) {
    alarmTriggered = false;
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);

    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    
    alarmMinutes = (alarmMinutes + alarmInterval) % 60;  // Manages to put minutes always between 1 and 60 Minutes; 61 % 60 = 1
    rtc.setAlarmTime(rtc.getHours(), alarmMinutes, rtc.getSeconds());
    rtc.standbyMode();    // Sleep until next alarm match
  }
}

void alarmMatch() {
  // This function is called when the alarm values match
  // and the alarm is triggered.
  alarmTriggered = true;  // Set the global triggered flag
}

And I got the same problem, when I use the ArduinoLowPower library with the MKR WAN 1300.
When I use sensors.begin() it just blocks the whole sketch, which is basically the timedWakeup example from the ArduinoLowPower library.

Reference

/*
  TimedWakeup
  This sketch demonstrates the usage of Internal Interrupts to wakeup a chip in sleep mode.
  Sleep modes allow a significant drop in the power usage of a board while it does nothing waiting for an event to happen. Battery powered application can take advantage of these modes to enhance battery life significantly.
  In this sketch, the internal RTC will wake up the processor every 2 seconds.
  Please note that, if the processor is sleeping, a new sketch can't be uploaded. To overcome this, manually reset the board (usually with a single or double tap to the RESET button)
  This example code is in the public domain.
*/


#define ONE_WIRE_BUS 6

#include <ArduinoLowPower.h>
#include <OneWire.h> 
#include <DallasTemperature.h>
 
OneWire oneWire(ONE_WIRE_BUS);  
DallasTemperature sensors(&oneWire);

int alarm_source = 0;

void setup() {
  delay(10000);
  pinMode(LED_BUILTIN, OUTPUT);
  // start serial port 
  Serial.begin(9600); 
  // Start up the library 
  //sensors.begin(); // uncommenting this blocks the sketch on the MKR WAN 1300
  
  // Uncomment this function if you wish to attach function dummy when RTC wakes up the chip
  LowPower.attachInterruptWakeup(RTC_ALARM_WAKEUP, alarmEvent0, CHANGE); 
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
  LowPower.sleep(5000);
}

void alarmEvent0() {
  alarm_source = 0;
}

I think you are correct in deducing there is a clock conflict. I have got the Dallas library and the RTC library working together by implementing the changes to the RTC library suggested by ForceTronics:

In the RTCZero-master/src/RTCZero.cpp file in your library directory make two changes:
comment out the line

//config32kOSC();

find the line:

GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_DIVSEL );

and change to:

GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_DIVSEL );

These two changes swap the RTC library over to using the internal, less accurate but lower power timer.

Hey Phec,

thx for the help and sorry for the late reply. I just bought a new laptop and now I can work on my project again after a long hiatus. I did what you suggested. I also watched the video and created copies of the RTCzero library files from the default library folder (the RTCzero.cpp and RTCzero.h) and put them in my project folder and made the changes in those files, but without success (#include "RTCZero.h" for using the library in my project folder). The problem persists for me. You were using the latest Dallas library and RTCZero library, right? Which version of the RTCzero library and Dallas library did you use? Did the suggested script from the 18th december I've presented run with your mkrwan 1300 and the changes in RTCZero.cpp, when you didnt comment sensors.begin() anymore?

Can anybody else confirm, that the suggestion of Phec works? I would appreciate the help.

I've looked at the date, on which the forcetronics video was released (24th September 2016). Ive looked for the versions of the libraries OneWire, Dallas and RTCzero, which were released the closest after the release date of the video.

DallasTemperature-3.7.6
OneWire-2.3.2
RTCZero-1.5.0

Because the combination of Dallas and RTCzero worked for Phec, Ive guessed that's a good starting point, but Phec's solution doesnt work with those libraries either. There is still a block happening after sensors.begin().......

I should have used the alert option. I will remember that for the future....