Skip to main content
Arduino

You are not logged in. Your edit will be placed in a queue until it is peer reviewed.

We welcome edits that make the post easier to understand and more valuable for readers. Because community members review edits, please try to make the post substantially better than how you found it, for example, by fixing grammar or adding additional resources and hyperlinks.

Required fields*

Required fields*

atmega88 timer2 32.768KHz and Serial problem

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.

Answer*

Draft saved
Draft discarded
Cancel
5
  • Thanks. I will check if that fixes the serial issues. I did not know that millis would be halted during sleep, inspite of keeping timer0 enabled. Maybe I'll be able to check that if I can get serial to work reliably. However, I'm only using millis() as a rough estimate as it's running from the internal oscillator, so not a dealbreaker if it is messed up. Commented May 30, 2018 at 14:39
  • I checked, and your instructions fixed the garbled messages of the serial line. Also, millis() does indeed only count the wake time. However, it seems serial uses interrupts, so it is still causing some problems. I put the timer2 interrupt in an ISR, and it is slightly better. It causes a problem only if the serial wires are connected during reset. Commented May 30, 2018 at 23:29
  • @Indraneel: Re serial interrupts: see the edited answer. I don't know what you mean by "I put the timer2 interrupt in an ISR". Commented May 31, 2018 at 8:24
  • Thanks for the update. I'll see if that helps. I think, writing to the LED pin may also be causing an interrupt. It is helping to put a delay after the write. I have edited my question above with the updated code. Commented May 31, 2018 at 15:02
  • @Edgar_Bonet Problem is mostly during startup, like if I press the reset pin for too long (1-2 seconds, instead of small tap). But problem shows up only after 1st sleep cycle is complete (after 1st 8 seconds). No difference on adding 0.1uF capacitor to reset pin. Commented May 31, 2018 at 16:31

AltStyle によって変換されたページ (->オリジナル) /