Author Topic: Power saving and pc interrupts on ATMega324PA  (Read 446 times)

0 Members and 1 Guest are viewing this topic.

Offline glentekTopic starter

  • Regular Contributor
  • *
  • Posts: 54
Power saving and pc interrupts on ATMega324PA
« on: April 24, 2023, 02:29:57 am »
I have an ATMega324PA and I want to power down and only wake on CAN receive (working on int 0 successfully), on a schedule, on pcints on 6 digital inputs, and on serial receive - either serial0 or serial1.
I have read Nick Gammon's forum post and have tried to adapt his code to my 324. It will go into sleep, wake on a digital input but then stays awake. I've obviously got something wrong. Also I'm not clear on how to wake on serial. This is some basic test code, the CAN code is not included. I'm using Arduino IDE.
Code: [Select]
/*
ATMega324PA

*/

#include <avr/sleep.h>  // Sleep Modes
#include <avr/power.h>  // Power management
#include <avr/wdt.h>    // Watchdog timer

const byte LED1 = 18;  // pin DO1
const byte DI1 = 28;   // pin DI1 / PCINT4
const byte DI2 = 29;   // pin DI2 / PCINT5
const byte DI3 = 30;   // pin DI3 / PCINT6
const byte DI4 = 31;   // pin DI4 / PCINT7
const byte DI5 = 22;   // pin DI5 / PCINT22
const byte DI6 = 23;   // pin DI6 / PCINT23

ISR(PCINT0_vect) {
  PCICR = 0;
}
ISR(PCINT1_vect) {
  PCICR = 0;
}
ISR(PCINT2_vect) {
  PCICR = 0;
}
// watchdog interrupt
ISR(WDT_vect) {
  wdt_disable();  // disable watchdog
}  // end of WDT_vect

// sleep bit patterns for WDTCSR
enum {
  WDT_16_MS = 0b000000,
  WDT_32_MS = 0b000001,
  WDT_64_MS = 0b000010,
  WDT_128_MS = 0b000011,
  WDT_256_MS = 0b000100,
  WDT_512_MS = 0b000101,
  WDT_1_SEC = 0b000110,
  WDT_2_SEC = 0b000111,
  WDT_4_SEC = 0b100000,
  WDT_8_SEC = 0b100001,
};  // end of WDT intervals enum

void resetWatchdog() {
  // clear various "reset" flags
  MCUSR = 0;
  // allow changes, disable reset, clear existing interrupt
  WDTCSR = bit(WDCE) | bit(WDE) | bit(WDIF);
  // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
  WDTCSR = bit(WDIE) | WDT_8_SEC;  // set WDIE, and 8 seconds delay
  // pat the dog
  wdt_reset();
}  // end of resetWatchdog

void setup() {

  // disable JTAG for pins 18 to 21
  MCUCR |= (1 << JTD);
  MCUCR |= (1 << JTD);

  resetWatchdog();  // do this first in case WDT fires

  pinMode(LED1, OUTPUT);
  pinMode(DI1, INPUT_PULLUP);
  pinMode(DI2, INPUT_PULLUP);
  pinMode(DI3, INPUT_PULLUP);
  pinMode(DI4, INPUT_PULLUP);
  pinMode(DI5, INPUT);
  pinMode(DI6, INPUT);

  // pin change interrupt masks
  PCMSK2 |= bit(PCINT22);  // pin 22
  PCMSK2 |= bit(PCINT23);  // pin 23
  PCMSK0 |= bit(PCINT4);   // pin Din1
  PCMSK0 |= bit(PCINT5);   // pin Din2
  PCMSK0 |= bit(PCINT6);   // pin Din3
  PCMSK0 |= bit(PCINT7);   // pin Din4

  // clear any outstanding interrupts
  PCIFR |= bit(PCIF0) | bit(PCIF1) | bit(PCIF2);
  // enable pin change interrupts
  PCICR |= bit(PCIE0) | bit(PCIE1) | bit(PCIE2);

}  // end of setup

void loop() {
  digitalWrite(LED1, HIGH);
  delay(500);
  digitalWrite(LED1, LOW);
  delay(500);

  goToSleep();
}  // end of loop

void goToSleep() {
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  ADCSRA = 0;           // turn off ADC
  power_all_disable();  // power off ADC, Timer 0 and 1, serial interface
  noInterrupts();       // timed sequence coming up
  resetWatchdog();      // get watchdog ready
  sleep_enable();       // ready to sleep
  interrupts();         // interrupts are required now
  sleep_cpu();          // sleep
  sleep_disable();      // precaution
  power_all_enable();   // power everything back on
}  // end of goToSleep
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf