Problems using LowPower/Sleep mode with light logger

Hi all,

Caveat: I'm a biologist trying to learn this stuff, so apologies for my ignorance. I'm building a low-light logger for underwater. I've got to the point where the unit works fine, but (unsurprisingly I gather) uses a lot of power. Ideally I'd like it to log for 5 minutes, then power down for 25, log again, etc so that it significantly reduces power consumption to the point where I can put it out for a week at least. I've explored options, and the simplest (but probably least elegant) is to loop an 8s low-power repeatedly. I can't get it off the ground though.

I'm using the low-power library from here: Sparkfun low power

This basic code works fine:

#include "LowPower.h"

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() 
{
  // Enter idle state for 8 s with the rest of peripherals turned off
  // Each microcontroller comes with different number of peripherals
  // Comment off line of code where necessary

  // ATmega328P, ATmega168
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
  LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, 
                SPI_OFF, USART0_OFF, TWI_OFF);

  
}

And this is the basis of the code that I'm using for the logger:

volatile unsigned long cnt = 0;
unsigned long oldcnt = 0;
unsigned long t = 0;
unsigned long last;

void irq1()
{
  cnt++;
}

void setup() 
{
  Serial.begin(115200);
  Serial.println("START");
  pinMode(2, INPUT);
  digitalWrite(2, HIGH);
  attachInterrupt(0, irq1, RISING);
}


void loop() 
{
 
  if (millis() - last >= 1000)
  {
    last = millis();
    t = cnt;
    unsigned long hz = t - oldcnt;
    Serial.print("FREQ: "); 
    Serial.print(hz);
    Serial.print("\t = "); 
    Serial.print((hz+50)/100);  // +50 == rounding last digit
    Serial.println(" mW/m2");
    oldcnt = t;
    
  }
  
  
}

Which works fine as well.

But if I add in the LowPower command I get gibberish, and no sleep, or just no sleep. For example this one give me gibberish (as in random symbols) without even any line breaks:

#include <LowPower.h>


volatile unsigned long cnt = 0;
unsigned long oldcnt = 0;
unsigned long t = 0;
unsigned long last;

void irq1()
{
  cnt++;
}


void setup() 
{
  Serial.begin(115200);
  Serial.println("START");
  pinMode(2, INPUT);
  digitalWrite(2, HIGH);
  attachInterrupt(0, irq1, RISING);
}


void loop() 
{
 
  if (millis() - last >= 1000)
  {
    last = millis();
    t = cnt;
    unsigned long hz = t - oldcnt;
    Serial.print("FREQ: "); 
    Serial.print(hz);
    Serial.print("\t = "); 
    Serial.print((hz+50)/100);  // +50 == rounding last digit
    Serial.println(" mW/m2");
    oldcnt = t;
    
  }
  
LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, 
                SPI_OFF, USART0_OFF, TWI_OFF);  
}

I assume I'm doing something pretty basic wrong, but am out of my depth. The gibberish seems similar to when I get the serial baud rate wrong?

Any help would be greatly appreciated
Thanks

IDLE mode doesn't really save much power as the power-hungry devices are still running: all the clocks, ADC, etc.
You need one of the deeper sleep modes to really achieve savings, and I don't know about the library you're using, but you may need to turn off ADC manually.
The maximum sleep time using the watchdog timer is about 8 seconds. This however, is not very accurate. If you need precise time-stamping you'd better invest in a RTC (cheap).
During you 5 minutes of logging you'd need to turn sleep off. During your 25 minutes of rest, wake from sleep every 8 seconds, long enough only to increment a counter and check it's value, about 187 counts comes close to 25 minutes. With all of the above, the most important is to turn off the ADC.
You really need to study the datasheet - Power Management and Sleep Modes - to get a handle on this as I've not really seen an adequate write-up on it elsewhere.

Thanks.

IDLE mode doesn't really save much power as the power-hungry devices are still running: all the clocks, ADC, etc.

Ok, thanks, I guess that's the most important thing here.

Re: timing, I've got a combined RTC and SD logger on it, so the data will be time stamped. The only thing I need to be precise is the interval in which it's being logged, ie. the 5 minute interval because the sensor counts voltage spikes to determine light levels. I don't mind how long the unit is asleep for, as long as it's around 25 minutes.

You really need to study the datasheet - Power Management and Sleep Modes - to get a handle on this as I've not really seen an adequate write-up on it elsewhere.

This one: Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors?

This one.
Assuming your Arduino is based on the 328P.

Nazaar--:
I've got a combined RTC and SD logger on it, so the data will be time stamped.

How are you putting the SD card into a low current sleep ?

This one.
Assuming your Arduino is based on the 328P.

Thanks. I've continued looking around, and the longer power down modes, including ones that use the RTC to wake, use an interrupt to wake it up. So nominally either the watchdog, or RTC, or external signal send the interrupt to wake the chip. I tried this earlier and it was a failure, and I'm wondering whether it's because the code I'm using to count the voltage spikes from the sensor includes an interrupt?

volatile unsigned long cnt = 0;
unsigned long oldcnt = 0;
unsigned long t = 0;
unsigned long last;

void irq1()
{
 cnt++;
}

void setup() 
{
 Serial.begin(115200);
 Serial.println("START");
 pinMode(2, INPUT);
 digitalWrite(2, HIGH);
 attachInterrupt(0, irq1, RISING);
}


void loop() 
{

 if (millis() - last >= 1000)
 {
   last = millis();
   t = cnt;
   unsigned long hz = t - oldcnt;
   Serial.print("FREQ: "); 
   Serial.print(hz);
   Serial.print("\t = "); 
   Serial.print((hz+50)/100);  // +50 == rounding last digit
   Serial.println(" mW/m2");
   oldcnt = t;
   
 }
 
 
}

How are you putting the SD card into a low current sleep ?

At this point I can't even get the board to sleep! I gather from https://thecavepearlproject.org/ that it's possible to put the whole thing into power down mode, SD card included. He does mention that different SD cards draw higher/lower current.

pinMode(2, INPUT);
digitalWrite(2, HIGH);
attachInterrupt(0, irq1, RISING);

This sets pin 2 as input with pullup, which means idle state is HIGH. You will not get a rising signal unless the device connected can pull to ground (which is common) and then release. More common to have the interrupt to trigger on FALLING.

Interrupts 0 and 1 (pins 2 and 3) are synchronous interrupts, which means they need a clock running to trigger on a level change or trigger on a LOW level (without the clock) that must be held for a defined period of time. In any sleep mode other than IDLE, all clocks (except WDT) are turned off. Interrupts 0 and 1 no longer work in a level change mode. What still works on those pins, and basically all the other pins, is a Pin Change Interrupt (load library EnableInterrupt NOT PinChangeInt as it has been deprecated). Read the datasheet section on External Interrupts for more detail.

I'll read up on that, thanks, it might be a bit beyond me for the first iteration that has to go into the field.

A related question, I know that pins 2 and 3 are the interrupt pins, so if I wanted to change the pin I use for the sensor from 2 to 3, would I have:

pinMode(3, INPUT);
digitalWrite(3, HIGH);
attachInterrupt(1, irq1, RISING);

Thanks for the help