How to enable rtc in fe310 with 1sec resolution in rtcs?


In my board, RTC is clocked with 32.768 khz crystal with following settings:

  /* Disable interrupt */
  csrw mie, 0;

(gdb) x 0x10000040 => RTC config register
0x10000040: 0x1000100f => scale 15 and enabled

and hoping to read the rtcs ticking up for every 1sec.

  li t0, AON_BASE;

  /* init rtc high & low to 0 */
  sw zero, RTC_COUNT_HI_OFST(t0);
  sw zero, RTC_COUNT_LO_OFST(t0);

  li t1, 0x100F; /* Enable and set scale F */

  sw t1, RTC_CFG_OFST(t0);

  /* read rtccounthi (offset 0x04C) - high bits counter */
  lw t2, RTC_COUNT_HI_OFST(t0);

  /* read rtccountlo (offset 0x048) - low bits counter */
  lw t3, RTC_COUNT_LO_OFST(t0);

I can read the high and low count as below & it keeps ticking up.

(gdb) x 0x10000048
0x10000048:	0x000a1009  => lower 32 bits
(gdb) x 0x1000004C
0x1000004c:	0x00000000=> upper 16 bits 

(gdb) x 0x1000004C
0x1000004c: 0x00000000

(gdb) x 0x10000048
0x10000048: 0x004faac6

The FE310 manual mentions that the value of rtcs is memory-mapped and can be read as a single 32-bit register over the AON TileLink bus.

Now, when tried to read from 0x10000050 (mmap addr to rtcs), its incrementing quickly. I am expecting it to increment by 1 every sec. But its not.
Within few seconds on my computer, it hit

(gdb) x 0x10000050
0x10000050: 0x0000023f

I did NOT change clock settings, with default power up, when rtc is enabled, assuming would be clocked with 32.768 ext crystal.

Here are the lf clk settings:

(gdb) x 0x10000070
0x10000070: 0xc0100004 => lfosc enabled and ready, with divisor value

(gdb) x 0x1000007C
0x1000007c: 0x00000000 => Here the lfextclk_sel is also 0, lfextclk_mux_status is also 0.
Does this mean lfosc is used to clock rtc?

Great to see you @bsvtgc
Using RTCS to toggle a GPIO line once a second seems to work for me.

First, note that the power-up default settings (trim=16, div=4) for the LFR block on the FE310-G002 SoC give 22,915 KHz which is a little bit different than 32,768 KHz which is noted in the Manual. This was found experimentally and described at Demonstrating-PRCI: The LF Ring Oscillator frequency in Hz is 1 / (a * (1 - (trim - 16) / b)) and its design constants are a=8.728, b=31.

You are correct, the power-up default for lfextclk_sel is the internal LFR block. I don’t have an external LF source so I can’t test the other setting, unfortunately.

Here is what works for me.

GPIO setup for scope and/or LED monitor:

.equ GPIO_BASE, 0x10012000
.equ GPIO_OUTPUT_EN,  0x08
.equ GPIO_IOF_EN,     0x38

  li t6, GPIO_BASE
  li t5, (1<<21)         # GPIO21

  not t5, t5

  lw t0, 0x38(t6)        # x = gpio_iof_en
  and t0, t0, t5         # x &= ~GPIO21
  sw t0, 0x38(t6)        # gpio_output_iof_en = x

  not t5, t5

  lw t0, 0x08(t6)        # x = gpio_output_en
  or t0, t0, t5          # x |= GPIO21
  sw t0, 0x08(t6)        # gpio_output_en = x

RTC configuration and simple timing loop. I do all the configuration settings with the RTC counter/timer disabled (CFG=0), then (re)enable it at the end; this might have something to do with your strange observations. Also remember that RTCCOUNT_HI is a 16-bit value (its upper 16 bits are always 0) while RTCCOUNT_LO is a full 32-bits.

.equ AON_BASE, 0x10000000
.equ AON_LFROSCCFG,   0x070
.equ AON_RTCCFG,      0x040
.equ AON_RTCCOUNT_LO, 0x048
.equ AON_RTCS,        0x050
.equ AON_RTCCMP0,     0x060
.equ AON_RTCCFG_ENALWAYS, 0x00001000  # [12]

  li t0, AON_BASE

  sw x0, AON_RTCCFG(t0)               # 
  sw x0, AON_RTCCOUNT_HI(t0)          # reset count
  sw x0, AON_RTCCOUNT_LO(t0)          # reset count
  sw x0, AON_RTCS(t0)                 # 
  sw x0, AON_RTCCMP0(t0)              # 
  li t2, (AON_RTCCFG_ENALWAYS | 0xF)  # scale 0..15
  sw t2, AON_RTCCFG(t0)               # 

  li t2, 0     # initial value
  lw t1, AON_RTCS(t0)
  beq t1, t2, rtc_loop
  mv t2, t1
  lw t3, GPIO_OUTPUT_VAL(t6)
  xor t3, t3, t5              # gpio_output_val ^= GPIO21
  sw t3, GPIO_OUTPUT_VAL(t6)
  j rtc_loop

Personally, I never really tried using the scale feature, but indeed it does work as advertized. You could also do a wrap-less counter value check as below:

  li t2, 4                    # 4 = 100us * 32768 cyc/sec; 122us, actually
  lw t1, AON_RTCCOUNT_LO(t0)  # current time
  remu t1, t1, t2             # wrap-less
  bnez t1, rtc_loop           # while (count < (count0 + 100us))
  lw t3, GPIO_OUTPUT_VAL(t6)
  xor t3, t3, t5              # gpio_output_val ^= GPIO21
  sw t3, GPIO_OUTPUT_VAL(t6)
  j rtc_loop

Because they are very similar, all the above work equally well with the WDT watchdog counter/timer. Note, however, you would need to write WDOGCFG_KEYVAL to register WDOGKEY every time you write WDOGCFG, WDOG_COUNT, WDOGS, and WDOG_CMP0.

1 Like

Good to hear from you @pds .

the wrap-down counter is awesome and it never popped on my mind. I wonder what do you mean by you don’t have an external LF source? There is a external 32.768 khz on board as per schematics and as per my experiment.

Here is my progress and able to tick rtc at 1sec resolution.

   /* rtccfg (offset 0x040) */
  li t0, AON_BASE;

  /* disable lf osc */
  lw t1, LF_OSCCFG_OFST(t0);
  addi t2, zero, 1
  slli t2, t2, 30
  not t2, t2;
  and t1, t1, t2;
  sw t1, LF_OSCCFG_OFST(t0);

  /* sel 32.768 khz clock for lf */
  lw t1, LF_EXTCLK_SEL_OFST(t0);
  ori t1, t1, 1;
  sw t1, LF_EXTCLK_SEL_OFST(t0);

  /* init rtc high & low to 0 */
  sw zero, RTC_COUNT_HI_OFST(t0);
  sw zero, RTC_COUNT_LO_OFST(t0);

  /* Enable rtc with scale val 15 */
  li t1, 0x100F; 
  sw t1, RTC_CFG_OFST(t0);

0x10000050: 0x00000072
(gdb) x /x 0x10000050
0x10000050: 0x00000073

Just with eyes, it seems ticking at 1 sec. Didn’t verify with probe.
I appreciate your time and effort for this.

I do have a follow up question if you dont mind, with the attached picture, shoud n’t the external xtal 32.768 khz clock rtc at reset ?

Looks like the picture in manual may not be correct.