Help needed sleeping the Atmega4809 Arduino Nano Every

My project is a soil moisture sensor, powered by a battery, that is charged with a solar panel, sending data over ethernet-over-nRF24l01 radio (parts under $25, without housing $?) to an MQTT broker (RPi). I have this running on an older Nano and radio.

Now I'd like to use the Nano Every. My question is pretty much the same closed question at Sleep Mode Atmega4809 Arduino Nano Every

LowPower.h provides a simple way to power down the non-mega CPUs. Granted the max sleep time is 8s, but you can string those 8s together with only being powered up for a few uSecs between them.

The "LowPower.h" library doesn't work on the Every. The closed topic "Arduino Nano Every" links to "avr-libc: <avr/sleep.h>: Power Management and Sleep Modes". The information on that page is inadequate and makes the useless reference "Refer to the datasheet for the details relating to the device you are using"

The documentation I have found has a lot of "if you screw this up you can brick your device" and a lot of language referring to CPU registers, a place the inexperienced should avoid. This last link talks about turning off various timers and interrupts, but doesn't tell one if they get turned back on after returning from sleep.

I just need a little hand holding.

Thanks.

Sleep mode handling is completely different, and much more flexible, with the ATmega4809 on which the new Nano Every is based. This chip has an RTC peripheral and you have to configure this by register entries. Probably, the PIT (periodic Interrupt timer) is the best in your case if you need the Power Down sleep mode.

This may help: http://ww1.microchip.com/downloads/en/AppNotes/TB3213-Getting-Started-with-RTC-90003213A.pdf

If not, put together a very simple sketch for the old Nano which simply demonstrates forcing it to sleep and waking afterwards and I (or someone else) may give you some pointers to convert it for the Nano Every.

EDIT

Here is a simple example of Sleep mode. It performs a cycle of blinking 5 times, then sleeping for 8 seconds.

/*
  Nano Every: Cycle of Blink 5 times then Sleep for 8 seconds
  Configuration option: No ATmega328P Register emulation

*/

#include <avr/sleep.h>
uint8_t loopCount = 0 ;


void RTC_init(void)
{
  while (RTC.STATUS > 0) ;    /* Wait for all register to be synchronized */
 
  RTC.CLKSEL = RTC_CLKSEL_INT1K_gc;        // Run low power oscillator (OSCULP32K) at 1024Hz for long term sleep
  RTC.PITINTCTRL = RTC_PI_bm;              // PIT Interrupt: enabled */

  RTC.PITCTRLA = RTC_PERIOD_CYC8192_gc | RTC_PITEN_bm;     // Set period 8 seconds (see data sheet) and enable PIC                      
}

ISR(RTC_PIT_vect)
{
  RTC.PITINTFLAGS = RTC_PI_bm;          // Clear interrupt flag by writing '1' (required) 
}

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  RTC_init();   
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // Set sleep mode to POWER DOWN mode 
  sleep_enable();                       // Enable sleep mode, but not going to sleep yet 
}


void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(200);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(200);                       // wait for a second

  if( ++ loopCount == 5 ) {
    loopCount = 0 ;
    sleep_cpu();                     // Sleep the device and wait for an interrupt to continue
  }
}

@OldSurferDude Please edit your post and fix the link.

I don't have the Atmega4809 (yet) but it looks like you can do sleep periods well in the days interval compared to the 8 seconds you get from older AVRs

Thanks, 6v6gt! I'll be looking at the link. Here is a functional example:
SleepExample_old_.ino (1.6 KB)

Sorry, I, too, see that the link is dead and I can't find the post. This thread has some good information, while the former had no responses.

If you're looking for answers to the question of sleeping the Every, this is a good place.

If you're looking to support us who do not know how and have better information, this thread would also be a good place to post.

Thanks for alerting us that the link is dead.

OSD

Another Thanks, 6v6gt. Your code worked without modification (though I did put in some comments to jog my own memory :slight_smile:

And this got me to thinking, I'd like to be able to run the same code on either Nano. Is that possible? A compiler directive would work, but is there something that could be done at run time?

Also, in my readings I read some warnings about trying to download new code while the Nano Every is in sleep. Could you comment on that?

Thanks

OSD

Your only option to support both the original Nano and the Nano Every in one sketch is with compiler directives to exclude code for the architectures which do not match that of the board type selected at the time you compile. Registers for the other architecture would not be recognised.

Can you post a link to this . . . ?

I'll be looking for the link. But in the mean time, I put print statements before and after the sleep statement.
//-------------------------------------------------------------------------------loop
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(200); // wait for a second

if( ++ loopCount == 5 ) {
loopCount = 0 ;
Serial.print(F("Lulaby..."));
sleep_cpu(); // Sleep the device and wait for an interrupt to continue
Serial.println(F("Smell the coffee"));
}
}

Output:
⸮⸮⸮⸮⸮..Smell the coffee
⸮⸮⸮⸮⸮..Smell the coffee
⸮⸮⸮⸮⸮..Smell the coffee

same output when the F() function is removed.

Not what I would expect :grimacing:

OSD

fixed, thanks for pointing it out :slight_smile:

That behaviour is not new. The Serial buffer does not survive a sleep.

/*
  Nano Every: Cycle of Blink 5 times then Sleep for 8 seconds
  Configuration option: No ATmega328P Register emulation

*/

#include <avr/sleep.h>
uint8_t loopCount = 0 ;


void RTC_init(void)
{
  while (RTC.STATUS > 0) ;    /* Wait for all register to be synchronized */

  RTC.CLKSEL = RTC_CLKSEL_INT1K_gc;        // Run low power oscillator (OSCULP32K) at 1024Hz
  RTC.PITINTCTRL = RTC_PI_bm;              // PIT Interrupt: enabled */

  RTC.PITCTRLA = RTC_PERIOD_CYC8192_gc | RTC_PITEN_bm;     // Set period 8 seconds (see data sheet) and enable PIC
}

ISR(RTC_PIT_vect)
{
  RTC.PITINTFLAGS = RTC_PI_bm;          // Clear interrupt flag by writing '1' (required)
}

void setup() {
  Serial.begin( 9600 ) ;
  pinMode(LED_BUILTIN, OUTPUT);
  RTC_init();
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // Set sleep mode to POWER DOWN mode
  sleep_enable();                       // Enable sleep mode, but not going to sleep yet
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
  delay(200); // wait for a second
  digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
  delay(200); // wait for a second

  if ( ++ loopCount == 5 ) {
    loopCount = 0 ;
    Serial.print(F("Lulaby..."));
    Serial.flush() ;
    delay( 10 ) ;
    sleep_cpu(); // Sleep the device and wait for an interrupt to continue
    Serial.println(F("Smell the coffee"));
  }
}

Notice now the flush() and delay(). There are probably better ways than the delay to ensure the buffer is clean before the sleep.

Thanks! I should have remembered that as I do delay before sleep in my project code (MQTT client over ethernet over nRF24l01)

I'm still looking for that page

found that link to the warning about downloading code while Nano Every is sleeping Section 2, subsection "Putting your device to sleep"

Warning

Be careful! If the microcontroller is put to Power-down sleep mode without first defining interrupt procedure, the microcontroller will not wake up. The only way to wake it up is by provide a signal to the RESET pin. As a result of this situation, if you try to reprogram the microcontroller in sleep mode, you will not be successful. The tool for uploading the code to the microcontroller will attempt, in case of failure, to upload the code again. Rebooting the microcontroller in this moment is a suitable solution. As a result, the microcontroller wakes up and, during the startup, the microcontroller code is recorded.