mega4809 RTC PIT scaling for events not what I expected

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


As stated in another thread, I have been working with the Microchip 4908 Curiosity Nano to pipe the RTC PIT, clocked by the external crystal, to TCB0 using the event system.  The event configuration uses the RTC PIT period / 64 to generate events. 

 

I got things working nicely until I tried to change the prescaler for the RTC.   As I read the documentation and the associated figures, the RTC and the PIT use the same prescaler.  However, I found when I changed the prescaler setting, the event period did not change, while the RTC based interrupt period did change.   Am I missing something or is the documentation off somehow?

 

 

Here's the proof.  I wrote a program that sets up the RTC interrupt to toggle pin PB3 at 32 RTC counts (PER set to 32) and to route PIT/64 to via the event system to pin PB2.  Here is the setup:

 

 

In the following diagrams the RTC trace is on top, the PIT + EVSYS trace is on the bottom.

 

Now if I run the prescaler at 1 I get

 

 

and if I run the prescaler at DIV2 I get

 

 

Here is the code:

 

#ifdef F_CPU
#undef F_CPU
#endif
#define F_CPU 5000000L
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>


/* Wait for user button press to start application code. */
void nano_button_wait() {
  uint8_t st = 1;			/* switch state */
  uint8_t lc;				/* led counter */

  TCB0.CCMP = 333;			/* debounce time */
  TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | TCB_ENABLE_bm;
  PORTF.DIRSET = PIN5_bm;		/* LED output */
  
  while (st) {
    switch (st) {
    case 1: if ((PORTF.IN & PIN6_bm) == 0) st = 2; break;
    case 2: if ((PORTF.IN & PIN6_bm) != 0) st = 0; break;
    }
    if (lc++ == 0) PORTF.OUTTGL = PIN5_bm; /* toggle LED */
    while ((TCB0.INTFLAGS & 0x01) == 0);   /* wait for bounce */
    TCB0.INTFLAGS = 0x01;		   /* reset flag */
  }

  /* Restore MCU state. */
  PORTF.DIRCLR = PIN5_bm;
  TCB0.CTRLA = 0x00;
  TCB0.CCMP = 0;
  TCB0.INTFLAGS = 0x01;
}


void init_sys_clk() {
 _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSC20M_gc);
 _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm);
 while ((CLKCTRL.MCLKSTATUS & 0x11) != 0x10); /* wait for stable OSC20M */
}


#define RTC_DIV 4

#if RTC_DIV == 1
#define RTC_PRESCALER_gc RTC_PRESCALER_DIV1_gc
#elif RTC_DIV == 2
#define RTC_PRESCALER_gc RTC_PRESCALER_DIV2_gc
#elif RTC_DIV == 4
#define RTC_PRESCALER_gc RTC_PRESCALER_DIV4_gc
#else
#error "invalid RTC_DIV"
#endif

void init_rtc_pit() {
  _PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, 0x33);
  while ((CLKCTRL.MCLKSTATUS & 0x41) != 0x40); /* wait for stable XOSC32K */

  RTC.CLKSEL = RTC_CLKSEL_TOSC32K_gc;	/* external crystal for RTC/PIT */

  RTC.INTCTRL = RTC_CMP_bm;
  RTC.PER = 31;				/* 1/2 of 64 */

  while (RTC.STATUS != 0);
  RTC.CTRLA = RTC_PRESCALER_gc | RTC_RTCEN_bm;;

  while ((RTC.PITSTATUS & 0x1) != 0);	/* wait for steady PITCTRLA */
  RTC.PITCTRLA = RTC_PERIOD_OFF_gc | RTC_PITEN_bm; 
}

volatile uint8_t cnt = 0;

ISR(RTC_CNT_vect) {
  RTC.INTFLAGS = RTC_CMP_bm;
  PORTB.OUTTGL = PIN3_bm;		  /* toggle PB3 */
  if (cnt++ == 0) PORTF.OUTTGL = PIN5_bm; /* toggle LED */
}

void config_evsys() {
  EVSYS.CHANNEL7 = 0x0B;	       /* RTC_PIT DIV64 -> channel7 */
  EVSYS_USEREVOUTB = EVSYS_CHANNEL_CHANNEL7_gc; /* chan7 => EVOUTB=PB2 */
}
  
int main(void) {

  nano_button_wait();			/* wait for button-press */
  
  PORTF.DIRSET = PIN5_bm;		/* set LED/PF5 as output */
  PORTF.OUTSET = PIN5_bm;		/* LED off */

  PORTB.DIRSET = PIN3_bm;		/* RTC */
  PORTB.DIRSET = PIN2_bm;		/* PIT */

  init_sys_clk();
  init_rtc_pit();
  config_evsys();

  _PROTECTED_WRITE(WDT.CTRLA, WDT_PERIOD_8KCLK_gc); /* 8 sec watchdog */
  sei();
  while (1) {
    wdt_reset();			/* reset watchdog */
  }

}

 

This topic has a solution.
Last Edited: Sun. Aug 16, 2020 - 08:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My ultimate concern here is understanding if the RTC calibration capability for the RTC peripheral does or does not affect the RTC PIT event period.  The figure above indicates it should.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

>However, I found when I changed the prescaler setting, the event period did not change

 

The event you choose selects a tap of the prescaler output, and doesn't change which tap the pit period selected, or which tap the rtc prescaler uses. You chose div64 for the event, and that is what you will get until you change the event source to select a different prescaler tap.

 

The calibration correction is applied to the clock entering the prescaler, so will apply to pit/rtc.

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

Yes, that picture is misleading. The fact is that at the hardware level, prescalers usually are binary counters clocked by some base clock. Each bit corresponds to a frequency divider.

 

00000000
00000001
00000010
00000011
00000100
00000101
00000110
00000111
00001000
.   ||||
.   ||||
.   ||||
etc.||||
    ||||
    |||+--div2
    ||+---div4
    |+----div8
    +-----div16

The PIT is connected to all these lines, that's why it can generate several events at once. The PIT interrupt is also connected to one of these lines. We can say that the PIT is not a counter, but just the frontend to the prescaler, which is an actual counter.

 

Now, the RTC is an actual separate counter, that can use any of the signals from the prescaler as clock. That's why the PIT always counts at the same speed, while the RTC can be prescaled.

 

 

edit: another thing - you never know what is the count value of the PIT, i.e., of the prescaler, since it's not available as a register.

Last Edited: Sun. Aug 16, 2020 - 08:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks folks.   That makes a lot of sense.  Off to compute average clk_per cycles per PIT.

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

MattRW wrote:
  4908 Curiosity Nano 

 

ATmega4809 Curiosity Nano

 

 

MattRW wrote:
 I got things working nicely until I tried to change the prescaler for the RTC.   As I read the documentation and the associated figures, the RTC and the PIT use the same prescaler.  However, I found when I changed the prescaler setting, the event period did not change, while the RTC based interrupt period did change.   Am I missing something or is the documentation off somehow? 

 

http://ww1.microchip.com/downloa...

 

 

The truth is more important than the facts.

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

 

Thanks much for that link.  I started looking for the errata but never got there.  Good to have, but I found nothing appropriate to this case.

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

The truth is more important than the facts.

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

poftamunk wrote:

 

So what.  I write to RTC.CTRLA once during initialization.   The above says that the binary counters from which the RTC and PIT event output are picked off is reset.  That doesn't affect which lines get picked off.  I was assuming the pre-scaled RTC line was fed into the PIT EVENT scaling, but apparently it is not.   The diagram is misleading (to me).  It should show the pickoff of the EVSYS.