ATSAMD21: RTC module not counting in calendar mode when GCLK_RTC < ~3kHz

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

Hello everyone,

 

I'm currently trying to get the RTC module inside the ATSAMD21 working in calendar mode.

The datasheet therefore states: 

The selected clock source and RTC prescaler must be configured to provide a 1Hz clock to the counter for correct operation in this mode.

My current plan is therefore to use an external 32kHz oscillator, use a GCLK to divide XOSC32K by 32, and then set the RTC 10-bit prescaler to 1024 to correctly get a CLK_RTC_CNT at 1Hz

 

This is my code:

    /* Assign external 32kHz to GCLK3, divide it by 32 */
    GCLK_GENDIV_Type gendiv_reg;                                        // Gendiv struct
    gendiv_reg.bit.ID = GCLK_CLKCTRL_GEN_GCLK3_Val;                     // Select gclk3
    gendiv_reg.bit.DIV = DIVIDER HERE!!!;                                            // Divide by 32
    while ((GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) != 0);             // Wait for sync
    GCLK->GENDIV = gendiv_reg;                                          // Write register
    GCLK_GENCTRL_Type genctrl;                                          // Genctrl struct
    genctrl.reg = 0;                                                    // Reset temp var
    genctrl.bit.ID = GCLK_CLKCTRL_GEN_GCLK3_Val;                        // Select gclk3
    genctrl.bit.SRC = GCLK_GENCTRL_SRC_XOSC32K_Val;                     // Assign external 32kHz
    genctrl.bit.GENEN = 1;                                              // Enable generator
    genctrl.bit.DIVSEL = 0;                                             // Divide clock by gendiv.div
    genctrl.bit.OE = 1;                                                 // Do not output clock
    genctrl.bit.RUNSTDBY = 1;                                           // Run in standby
    while ((GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) != 0);             // Wait for sync
    GCLK->GENCTRL = genctrl;                                            // Write register

    /* Set GCLK Multiplexer 4 (for GCLK_RTC) to 1kHz GCLK3 */
    GCLK_CLKCTRL_Type clkctrl;                                          // Clkctrl struct
    clkctrl.reg = GCLK_CLKCTRL_ID_RTC;                                  // Disable RTC clock generator
    clkctrl.bit.GEN = GCLK_CLKCTRL_GEN_GCLK2_Val;                       // Default value
    while ((GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) != 0);             // Wait for sync
    GCLK->CLKCTRL = clkctrl;                                            // Write register
    while ((GCLK->CLKCTRL.reg & GCLK_CLKCTRL_CLKEN) != 0);              // Wait for clock disable
    clkctrl.reg = 0;                                                    // Reset temp var
    clkctrl.bit.ID = GCLK_CLKCTRL_ID_RTC_Val;                           // Select RTC input
    clkctrl.bit.GEN = GCLK_CLKCTRL_GEN_GCLK3_Val;                       // Select gclk3
    clkctrl.bit.CLKEN = 1;                                              // Enable generator
    while ((GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) != 0);             // Wait for sync
    GCLK->CLKCTRL = clkctrl;                                            // Write register

    /* Setup RTC module in calendar mode */
    while((RTC->MODE2.STATUS.reg & RTC_STATUS_SYNCBUSY) != 0);          // Wait for sync
    RTC->MODE2.CTRL.reg = 0;                                            // Disable RTC
    while((RTC->MODE2.STATUS.reg & RTC_STATUS_SYNCBUSY) != 0);          // Wait for sync
    RTC->MODE2.CTRL.reg = RTC_MODE2_CTRL_SWRST;                         // Reset RTC
    while((RTC->MODE2.STATUS.reg & RTC_STATUS_SYNCBUSY) != 0);          // Wait for sync
    while((RTC->MODE2.CTRL.reg & RTC_MODE2_CTRL_SWRST) != 0);           // Wait for end of reset
    RTC_MODE2_CTRL_Type rtc_ctrl_reg;                                   // rtc ctrl struct
    rtc_ctrl_reg.reg = RTC_MODE1_CTRL_ENABLE;                           // Enable module
    rtc_ctrl_reg.bit.CLKREP = 0;                                        // 24 hour mode
    rtc_ctrl_reg.bit.MODE = RTC_MODE2_CTRL_MODE_CLOCK_Val;              // Calendar mode
    rtc_ctrl_reg.bit.PRESCALER = RTC_MODE2_CTRL_PRESCALER_DIV1024_Val;  // Divide 1.024kHz signal by 1024
    while((RTC->MODE2.STATUS.reg & RTC_STATUS_SYNCBUSY) != 0);          // Wait for sync
    RTC->MODE2.CTRL = rtc_ctrl_reg;                                     // Write register
    //RTC->MODE2.DBGCTRL.bit.DBGRUN = 1;                                  // Allow normal operation during debug mode

Here's the odd thing: when debugging with an Atmel-ICE, I can only see the CLOCK register counting up when the frequency of GCLK_RTC is roughly above ~3kHz (eg when gendiv_reg.bit.DIV is set to something smaller than 10).

Here are the different scenarios / checks I have tested, without success:

- several synchronization waits

- trying different GCLK: in the code above I am using GCLK3 but also have tested #1 (not #2 because of 5 division factor bits) #5 (even output it on a gpio) & #7

- switched my MCU main clock to 32kHz to make sure I was not encountering synchronization problems

For information, in my custom platform I have made sure XOSC32K is working, I have setup the DFLL in closed loop for a 48M GCLK0 and correctly configured 1 wait state for the on-board flash.

Thanks in advance for your help!

 

My electronic projects blog >> www.limpkin.fr

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

Possibly you should add

    RTC->MODE2.READREQ.reg |= RTC_READREQ_RCONT | RTC_READREQ_RREQ;
    while((RTC->MODE2.STATUS.reg & RTC_STATUS_SYNCBUSY) != 0);          // Wait for sync

to have continuous read request for CLOCK (should give visible updates in the debugger). But I don't know why the clock frequency would make a difference for this.
/Lars

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

that did it! thanks!

That's quite surprising though... I'd be very eager to know why...

My electronic projects blog >> www.limpkin.fr