Configure the Timer/Counter 2 for asynchronous operation

Hello,

I'd like to use an ATmega328 as an "RTC" for test purposes. My starting point was this post. It is not too detailed about the process, but I found it interesting enough to try it out.

I've set up the breadboard, everthing works fine, uC is running from its internal clock, I can program it with an UNO board. I wrote a sketch for the time display (4 digit & TM1637) and it worked if the "unixTime" was updated with the millis() function. It was time to move on with Timer2 method, I've soldered the 32768Hz crsytal and the appropriate capacitors to the OSC1 (XTAL1), OSC2 (XTAL2) pins. After reading the Datasheet, Section 17.9 I uploaded this:

#include <TM1637Display.h>
#include <TimeLib.h>

const byte DISP_CLK_PIN = 0;
const byte DISP_DIO_PIN = 1;
const byte BUTTON_PIN = 2;

const bool LEAD_ZEROS = true;
const bool NO_LEAD_ZEROS = false;
const uint8_t NO_DOTS = 0;
const uint8_t MIDDLE_DOTS = B11100000;
const byte length4 = 4;
const byte position0 = 0;

TM1637Display display = TM1637Display(DISP_CLK_PIN, DISP_DIO_PIN);

tmElements_t TimeData;

volatile bool updateSecond = false;

byte buttonState = HIGH;                       //pull-up, reversed logic
byte lastButtonState = HIGH;                   //pull-up, reversed logic
unsigned long unixTime = 1610547300ul;
unsigned long lastDebounceTime = 0ul;
unsigned long dispRefreshed = 0ul;

void setup()
{
  pinMode(BUTTON_PIN, INPUT);
  display.setBrightness(2);
  display.clear();

  delay(2000); //The user is advised to wait for at least one second before using Timer/Counter2 after power-up or wake-up

  noInterrupts();
  //Asynchronous Operation of Timer/Counter2
  //The CPU main clock frequency must be more than four times the oscillator frequency
  //a. Disable the Timer/Counter2 interrupts by clearing OCIE2x and TOIE2
  TIMSK2 = 0;

  //b. Select clock source by setting AS2 as appropriate
  //When AS2 is written to one, Timer/Counter2 is clocked from a crystal oscillator
  //connected to the timer oscillator 1 (TOSC1) pin
  ASSR |= (1 << AS2);

  //c. Write new values to TCNT2, OCR2x, and TCCR2x
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2 = 0;

  //d. To switch to asynchronous operation: Wait for TCN2xUB, OCR2xUB, and TCR2xUB
  while (ASSR & 0x1F) {}

  //no need to change TCCR2A, normal counting mode
  //prescaler set to 128
  TCCR2B |= (1 << CS22) | (1 << CS20);

  //e. Clear the Timer/Counter2 interrupt flags
  TIFR2 = 0x07;

  //f. Enable interrupts, if needed
  TIMSK2 |= (1 << TOIE2);
  interrupts();
}

ISR(TIMER2_OVF)
{
  updateSecond = true;
}

void loop()
{
  if (updateSecond == true)
  {
    updateSecond = false;
    unixTime += 1ul;
    breakTime(unixTime, TimeData);
    display.showNumberDecEx( (((int)TimeData.Minute * 100u) + (int)TimeData.Second) , MIDDLE_DOTS, NO_LEAD_ZEROS, length4, position0);
  }
  readButton();
}


void readButton()     //pull-up, reversed logic
{
  int reading = digitalRead(BUTTON_PIN);

  if (reading != lastButtonState)
  {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > 50ul)
  {
    if (reading != buttonState)
    {
      buttonState = reading;

      if (buttonState == LOW)
      {
        unixTime += 1u;
        breakTime(unixTime, TimeData);
        display.showNumberDecEx( (((int)TimeData.Minute * 100u) + (int)TimeData.Second) , MIDDLE_DOTS, NO_LEAD_ZEROS, 4, 0);
      }
    }
  }
  lastButtonState = reading;
}

Result:
Time can only be updated with the button, and the chip resets roughly every second. If I don't set the TOIE2 (Timer/Counter2 Overflow Interrupt Enable) in the setup, the uC not resets, I can increment the timestamp with the button as long as I'd like to. Unfortunately I can't measure the quartz if it is working correctly, but I successfully used another one from this type with a Teensy 3.2 board, I hope this one is also okay.

I think the Timer/Counter2 configuration is not correct.
Could someone help to get it right?

Thanks in advance.

Okay, I should have written:

ISR(TIMER2_OVF_vect)
{
  updateSecond = true;
}

NOT

ISR(TIMER2_OVF)
{
  updateSecond = true;
}

With correct ISR name it's working fine.

What did I mess around with the incorrect name, so the uC reset?

The way the ISR macro is implemented makes it possible to put in whatever you want.

#include <avr/io.h>
#include <avr/interrupt.h>

ISR(thiswontwork) {
	
}

int main(void)
{
    while (1) 
    {
    }
}

This snippet compiles fine but it'll not do anything useful. TIMER2_OVF is not defined anywhere whereas TIMER2_OVF_vect is.

Strange thing, when the incorrect "ISR(TIMER2_OVF)" version was uploaded, the uC reset periodically.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.