arduino / ArduinoCore-megaavr

Arduino Core for the ATMEGA4809 CPU
103 stars 62 forks source link

SLEEP_MODE_IDLE return without entering sleep #113

Open chansheunglong opened 2 years ago

chansheunglong commented 2 years ago

Everything works fine with Standby and Power-Down, the device goes to sleep forever without waking up

void loop() {
  SLPCTRL.CTRLA |= SLPCTRL_SMODE_PDOWN_gc; //SLEEP_MODE_PWR_DOWN
  sleep_enable();
  sleep_cpu();
  sleep_disable();

  Serial.println("ERROR"); //If you see this there is an error
  Serial.flush();
}

But I would like to have millis() running since I need to keep track of the time I change to SLEEP_MODE_IDLE (SLPCTRL.CTRLA |= SLPCTRL_SMODE_STDBY_gc;)to have the main clock running However, after that, the device just exits sleep mode immediately. And output "ERROR" to the terminal

Two question that need help: 1) Is there any config I need to do for the MCU to go to IDEL mode and enter sleep? 2) While in STANDBY and PWR_DOWN, is there anyway to keep millis() active?

Thanks all!

facchinm commented 2 years ago

@bobcmartin any hint :upside_down_face: ?

chansheunglong commented 2 years ago

@facchinm I figured out a possible reason, on SLEEP_MODE_IDLE, interrupt is trigger every 1 ms (presumably for the millis() function to update) thus the board return to running the code. To deal with that, I currently use a FOR loop to loop e.g. 1000 times if I wamt to sleep for 1000ms.

Not sure if that is the reason behind and is the intended outcome, but it works at leaat.

facchinm commented 2 years ago

@chansheunglong good to hear that, it would have been my first option for investigation (since it's very similar to what happens on other architectures). Keeping the issue open since there's probably a better way to tackle this

bobcmartin commented 2 years ago

The best way to do this is to configure the RTC peripheral using it's PIT, Periodic Interrupt Timer. The PIT can be clocked from the internal ultra low power 32kHz oscillator. It was added to mega4809 specifically for the purpose of waking up after a specific time in sleep mode. The millis() timer interrupt needs to be disabled or the timer shut off, configuring the RTC PIT function and then calling the SLEEP function. It's then a choice of adding the appropriate number of ticks to the millis() base counter before starting the timer again.

bobcmartin commented 2 years ago

The other issue, assuming the target board is a Nano Every, is that the SAMD11 is still in active mode, so unless it's completely decoupled from the mega4809 it doesn't really matter since the current numbers won't be close to datasheet numbers. I'm deciding between removing a bunch of parts from a Nano Every board or continuing the search for my mega4808 breakout board