I am trying to use atmega88 timer2 with a 32.768KHz crystal. I'm using a slightly modified version of Nick Gammon's code. I am using Minicore. No bootloader, 1MHz clock from internal oscillator, BOD disabled. Sleep is interrupted every 8 seconds. I use a counter to count 12 minutes. Since it overshoots about 8 seconds every 6 hours, I am subtracting 8 sec every 6 hours. I hope to eventually make a weather logger with this.
The code is mostly working in it's bare stripped down version, after I add a delay(100) after the digitalWrite. However, I also need Serial. When I enable Serial, it does not sleep anymore. Also, the serial output has a lot of excess weird characters. This happens at all baud rates, even 1200 (serial monitor set to same baud rate as in program). I think some interrupts are being called during digitalWrite and when the usart is powered on and it is messing with the sleep. I am a beginner regarding uC programming, and am really struggling with the datasheet and the code. Any help will be appreciated.
Here is the test code:
#include <avr/sleep.h>
#include <avr/power.h>
const byte tickPin = 4;// (do not use 3 and 11)
//byte intCounter = 0;
//byte leapCounter = 0;
int intCounter = 0;
int leapCounter = 0;
unsigned long prevTime = 0;
unsigned long currTime = 0;
// interrupt on Timer 2 compare "A" completion - does nothing
EMPTY_INTERRUPT (TIMER2_COMPA_vect);
void setup(){
pinMode (tickPin, OUTPUT);
Serial.begin(9600);
prevTime = millis();
Serial.print(" P: ");
Serial.println(prevTime);
// clock input to timer 2 from XTAL1/XTAL2
ASSR = bit (AS2);
// set up timer 2 to count up to 256 * 1024 (8 seconds)
TCCR2A = bit (WGM21); // CTC
TCCR2B = bit (CS20) | bit (CS21) | bit (CS22); // Prescaler of 1024
OCR2A = 255; // (zero-relative)
// enable timer interrupts
TIMSK2 |= bit (OCIE2A);
// disable ADC
ADCSRA = 0;
// turn off everything we can
power_twi_disable();
// power_timer0_disable();
// power_timer1_disable();
power_spi_disable();
power_usart0_disable();
power_adc_disable ();
// full power-down doesn't respond to Timer 2
set_sleep_mode (SLEEP_MODE_PWR_SAVE);
// get ready ...
sleep_enable();
} // end of setup
void loop(){
sleep_cpu ();
++intCounter;
power_usart0_enable();
Serial.print("I: ");
Serial.print(intCounter);
Serial.print(" L: ");
Serial.print(leapCounter);
currTime = millis();
Serial.print(" C: ");
Serial.print(currTime);
Serial.print(" E: ");
Serial.print(currTime - prevTime);
Serial.println();
prevTime = currTime;
power_usart0_disable();
delay(1000);
if ((leapCounter > 30) && (intCounter == 1)){
leapCounter = 0;
intCounter = 0;
}
if (intCounter > 89){
++leapCounter;
intCounter = 0;
digitalWrite (tickPin, ! digitalRead (tickPin));
delay(100);
}
// digitalWrite (tickPin, ! digitalRead (tickPin));
// delay(100);
} // end of loop
The chip is an Atmega88 (not P). It is drawing the same 6.5uA during sleep, with or without timer0 and timer1. So, I probably don't care if I have to leave them enabled.
I am planning to use a DHT11 and a ds18B20 and write the data to a w25Q64 flash, every 12 minutes. I'd prefer reading it all out via serial port every few weeks, without having to stop the uC.
update
Calling timer2 ISR, instead of handling wake up directly in main loop. Possibly more stable (not affected by Serial and digitalWrite)... but I am not sure.
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
//const byte tickPin = 4;// (do not use 3 and 11)
volatile bool t2flag = LOW;
volatile byte t2counter = 0;
byte leapCounter = 0;
//preventing digitalWrite from causing interrupt (did not help much)
EMPTY_INTERRUPT(PCINT2_vect);
void setup(){
pinMode (4, OUTPUT);
pinMode (1, INPUT_PULLUP); //set TX pin default HIGH
// clock input to timer 2 from XTAL1/XTAL2
ASSR = bit (AS2);
// set up timer 2 to count up to 256 * 1024 (8 seconds)
TCCR2A = bit (WGM21); // CTC
TCCR2B = bit (CS20) | bit (CS21) | bit (CS22); // Prescaler of 1024
OCR2A = 255; // (zero-relative)
// enable timer interrupts
TIMSK2 |= bit (OCIE2A);
// disable ADC
ADCSRA = 0;
// turn off everything we can
power_twi_disable();
// power_timer0_disable();
// power_timer1_disable();
power_spi_disable();
power_usart0_disable();
power_adc_disable();
wdt_disable();// reduces 6.5uA to 2.2uA @ 3.3V
// full power-down doesn't respond to Timer 2
set_sleep_mode (SLEEP_MODE_PWR_SAVE);
sleep_enable();
}
//ISR to handle timer2
ISR (TIMER2_COMPA_vect){
++t2counter;
if (t2counter > 89){t2flag = HIGH;}
}
void loop(){
if (t2flag == LOW){
power_usart0_enable();
Serial.begin(9600);
Serial.print("I: ");
Serial.print(t2counter);
Serial.println();
Serial.flush();
delay(10);
Serial.end();
power_usart0_disable();
//blip the tickPin every 8 sec
PORTD |= (1<<PD4);
delay(10);
PORTD &= ~(1<<PD4);
delay(100);//helps a lot
sleep_cpu();
return;
}
++leapCounter;
if (leapCounter == 30){
t2flag = LOW;
return; //delay another 8 sec every 6 hours
}
if (leapCounter > 30){leapCounter = 0;}
t2flag = LOW;
t2counter = 0;
power_usart0_enable();
Serial.begin(9600);
Serial.print("L: ");
Serial.print(leapCounter);
Serial.println();
Serial.flush();
delay(10);
Serial.end();
power_usart0_disable();
//long blip every 12 minutes
PORTD |= (1<<PD4);
delay(100);
PORTD &= ~(1<<PD4);
}
The problem is not always present. But when it appears, it happens the same way. After pressing reset button, first led blink is always after 8 seconds. After that, one of three things seem to happen. 1. Second flash is after 8 seconds and everything works as expected. 2. Second flash is after 3 seconds and all flashes after that are also after every 3 seconds. 3. Second flash happens immediately after first flash (and any delay() in the code) and this keeps on happening. In all cases, the serial output also shows the same pattern.
Sometimes it seems that wires connected to the serial or miso, mosi, sck may be causing this, but that is not always the case. The problem may occur even if these wires are not connected. Also, the problem may or may not occur with the same code (e.g. pressing reset after 30 sec may not show any problem, but pressing reset within 5 or 10 seconds leads to problem cases 2 and 3 above. So there is some kind of race condition, or buffer or interrupt noise or something.
I have to program with Arduino as ISP, as the bootloader is unable to sync with the ftdi chip for some reason while uploading sketch. But data transfer from the sketch with serial.print is working fine. So pulling out the miso mosi sck pins everytime is a hassle. Everything is on breadboard. I transferred full circuit to new breadboard (from old loose breadboard) but there is no change. So maybe not a breadboard issue.