XMEGA E3 RTC ignoring period register value

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a ATxmega32E5 bare chip I'm trying to get running for the first time and, of course, first job is to blink a light.  The following code inverts the LED pin in the RTC OVF interrupt, and the light does blinks, but at .25Hz (2 seconds on, 2 seconds off) instead of 2Hz as programmed.  Varying the PER register value makes no effect on the blink rate, it's as if the OVF interrupt is happening when the CNT overflows at 16 bits and ignores the comparison with the PER register value.  This is using GCC under Atmel Studio 7.  Probably a dumb mistake I'm just not seeing, but I've been trying to get it to work all weekend.  Thanks.

 

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

 

static void tick_init(void)
{
    OSC.CTRL |= OSC_RC32KEN_bm;        // Enable Internal 32.768 kHz RC Oscillator
    while ( !(OSC.STATUS & OSC_RC32KRDY_bm) ) ;        // Wait for 32kHz to stabilize
    CLK.RTCCTRL = CLK_RTCSRC_RCOSC32_gc | CLK_RTCEN_bm;        // Select RTC clock source and enable
    while (RTC.STATUS & RTC_SYNCBUSY_bm) ;        // Wait for RTC to sync
    RTC.CTRL = RTC_PRESCALER_DIV1_gc;        // Set RTC prescaler to 1
    RTC.INTCTRL = RTC_OVFINTLVL_LO_gc;        // Enable OVF interrupt LO
    RTC.INTFLAGS = RTC_OVFIF_bm;
    RTC.PER = 8192 - 1;        // Set RTC overflow period (2Hz)
    PMIC.CTRL |= PMIC_LOLVLEN_bm;            // Enable LO level interrupts
}

 

ISR(RTC_OVF_vect)
{
    PORTA.OUTTGL = PIN0_bm;        // Toggle LED
}

int main(void)
{
    PORTA.DIRSET = PIN0_bm;        // Enable LED output
    tick_init();
    sei();        // Enable interrupts
    
    while (1) 
    {
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The setting has failed because SYNCBUSY is not checked before setting RTC.PER.
As with timers in general, please finish all settings before activating. It is better to set RTC.CTRL at the end.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Waiting for SYNCBUSY to clear before every register access didn't change a thing.  However, moving setting RTC.CTRL after everything else looks like it worked.  The manual doesn't say anything about register loading sequence, but the AVR1314 app note does say something that seems to explain why this was the problem:

If the PER register is updated, one of the other registers must also be updated to synchronize PER value into RTC [clock] domain The mechanism is designed in this ways to ensure that corresponding PER and COMP values can be loaded in the same RTC cycle, while the RTC clock is running.

 Thanks for the quick help.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I added only one line to the # 1 program.
Will this work properly?

 

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



static void tick_init(void)
{
    OSC.CTRL |= OSC_RC32KEN_bm;        // Enable Internal 32.768 kHz RC Oscillator
    while ( !(OSC.STATUS & OSC_RC32KRDY_bm) ) ;        // Wait for 32kHz to stabilize
    CLK.RTCCTRL = CLK_RTCSRC_RCOSC32_gc | CLK_RTCEN_bm;        // Select RTC clock source and enable
    while (RTC.STATUS & RTC_SYNCBUSY_bm) ;        // Wait for RTC to sync
    RTC.CTRL = RTC_PRESCALER_DIV1_gc;        // Set RTC prescaler to 1
    RTC.INTCTRL = RTC_OVFINTLVL_LO_gc;        // Enable OVF interrupt LO
    RTC.INTFLAGS = RTC_OVFIF_bm;
    while (RTC.STATUS & RTC_SYNCBUSY_bm) ;        // <------------------------------------------- add
    RTC.PER = 8192 - 1;        // Set RTC overflow period (2Hz)
    PMIC.CTRL |= PMIC_LOLVLEN_bm;            // Enable LO level interrupts
}



ISR(RTC_OVF_vect)
{
    PORTA.OUTTGL = PIN0_bm;        // Toggle LED
}

int main(void)
{
    PORTA.DIRSET = PIN0_bm;        // Enable LED output
    tick_init();
    sei();        // Enable interrupts
    
    while (1)
    {
    }
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I actually tried running on 32E5, but according to the debugger, PER looks like it is set by code # 4, but it seems that it is not effective. It became effective when writing COMP at the same time.
I did not know this. After all setting it seems better to go with the RTC stopped.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dreamwaster wrote:
The manual doesn't say anything about register loading sequence
Isn't it simply a general principle of embedded engineering? Surely it's always the case that you configure all the other registers in a peripheral before you set the bit(s) that start it. Consider an ADC for example - you wouldn't set ADSC and start conversions until you had set reference, conversion speed, channel selection etc.

 

(it's also the same reason why you don't sei() until everything that will act as interrupt sources have been fully configured).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not necessarily.  Lots of code modifies those registers while the RTC is still running.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tried that, it didn't help.  But I'm still running at the default CPU clock rate, it's possible synchronization might become more of an issue when running faster.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wanted you to read along with #5.
Well already.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kabasan wrote:

I wanted you to read along with #5.
Well already.

 

Sumimasen.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


If you look at Atmel's RTC device class …… oh wait a minute.  I was dreaming.  I forgot that Atmel is still using hieroglyphics.   Well you can see how my RTC class does it.


   void Set_period(u_int16 value)   {
      while(status.sync_busy)
         ;
      period = value;
      }

 

If you don't believe me, you could look at the manual.