Go Down

Topic: Sensor readings inbetween Deep Sleep using RTCZero library [SAMD21] (Read 985 times) previous topic - next topic

gaebel90

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:

Code: [Select]

/********************************************************************/
// 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)

Code: [Select]
#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):

Code: [Select]

//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!

gaebel90

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?


Code: [Select]

#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
}

gaebel90

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

Code: [Select]
/*
  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;
}

Phec

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:
https://www.youtube.com/watch?v=wmWqkJ97Zsc
In the
Code: [Select]
RTCZero-master/src/RTCZero.cpp file in your library directory make two changes:
comment out the line
Code: [Select]
//config32kOSC();
find the line:
Code: [Select]
GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_DIVSEL );
and change to:
Code: [Select]
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.

Go Up