cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4xx RTC issue: inconsistent TR, SSR values near update time - befuddled!!

cygnus
Associate II
Posted on March 20, 2013 at 17:36

I'm having an issue wherein TR and SSR values don't logically match up, on an approximately 1 Hz read cycle where reads occur very close to the RTC update time. I'm perplexed, and almost ready to throw my board onto the interstate and get a job as a bagger at my grocery store.

Summary: - µC is STM32F405RG. SYSCLK is 168 MHz and PCLK1 is 42 MHz. - RTC is configured and started once (board has a backup battery) on startup when not already configured. - RTC is clocked by 768 KHz LSE. - PREDIV_S is set to 1024 to provide millisecond time resolution. - An external device delivers messages to the µC every 1 sec (±20 ms or so) via a USART, and as a first test I added a call to fetch RTC time on (after) receipt of these messages. Sometimes, if the timing is just right (such that the time fetch occurs close to the 1 Hz RTC update), I’ll see times like this:

RTC: 2013/03/20 08:48:024

RTC: 2013/03/20 08:48:026

RTC: 2013/03/20 08:48:027

RTC: 2013/03/20 08:48:025

RTC: 2013/03/20 08:49:993

<-- hey, it did NOT take that long!

RTC: 2013/03/20 08:49:015

<-- whoa, we moved backward in time?

RTC: 2013/03/20 08:49:995

RTC: 2013/03/20 08:49:995

RTC: 2013/03/20 08:49:015

RTC: 2013/03/20 08:49:994

RTC: 2013/03/20 08:49:982

RTC: 2013/03/20 08:49:015

RTC: 2013/03/20 08:49:994

RTC: 2013/03/20 08:49:994

RTC: 2013/03/20 08:49:014

RTC: 2013/03/20 08:49:993

Here is the time fetch procedure: 1) Clear RTC_ISR.RSF and wait for it to assert (tried manually and via RTC_WaitForSynchro()).

2) Read RTC_TR, RTC_SSR, and RTC_DR registers, in that order (also tried swapping TR/SSR read).

For absolute clarity, here's the code:

void TESTRTC()
{
uint8_t year, month, day, dow, hour, minute, second;
uint32_t treg, dreg;
uint16_t fracsec;
if (RTC_WaitForSynchro() != SUCCESS)
SIGNAL_FATAL_FAULT(FAULT_RTCRead);
treg = RTC->TR;
fracsec = RTC->SSR;
dreg = RTC->DR;
fracsec = fracsec - fracsec / 42;
year = BCD2ToByte((dreg >> 16) & 0xff);
month = BCD2ToByte((dreg >> 8) & 0x1f);
day = BCD2ToByte(dreg & 0x3f);
hour = BCD2ToByte((treg >> 16) & 0x3f);
minute = BCD2ToByte((treg >> 8) & 0x7f);
second = BCD2ToByte(treg & 0x7f);
printf(''RTC: 20%02d/%02d/%02d %02d:%02d:%02d.%03d\n'',
year, month, day, hour, minute, second, fracsec);
}

Anyone have any suggestions or observations to offer? I'd even be somewhat less surprised if the fetch attempts were acting odd with the SSR returning 1023, but they're significantly farther away from the RTC ''tick'' than that. (The millisecond value of 993 in the sample output above corresponds to an SSR value of 1)

Many thanks in advance!! #stm32f4-f4-rtc-subsecond
10 REPLIES 10
Posted on March 20, 2013 at 17:58

This looks bogus

fracsec = fracsec - fracsec / 42;

The formula is documented to work like this float frac; frac = (float)(PREDIV_S - fracsec) / (float)(PREDIV_S + 1); so I'm not immediately surprised you think it goes backward.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on March 20, 2013 at 18:24

While OP's problem appears to lay in the fact that the synchronous prescaler is a downcounter indeed, meantime I had a look at the ''library'' function to find two bugs:

#define RTC_RSF_MASK            ((uint32_t)0xFFFFFF5F)

  /* Clear RSF flag */

  RTC->ISR &= (uint32_t)RTC_RSF_MASK;

In most of cases harmless (and the first one completely benign if the register description in datasheet is correct), nonetheless a bug to be corrected (ST, do you listen?)

JW

cygnus
Associate II
Posted on March 20, 2013 at 18:45

It's not bogus, Clive. It calculates milliseconds from the counter value using integers, to a sufficient degree of accuracy for my application (within about 0.6 ms deviation max).

Since the RTC S prescaler is set to 1024, the counter value in SSR will go from 0 to 1023. Calculate 1023 / 42 as an integer divide: it's 24. Subtract 24 from the count (1023): 999. That's the millisecond equivalent.

cygnus
Associate II
Posted on March 20, 2013 at 18:49

OH! What you wrote just clicked! My apologies, I missed the fact the first time, and didn't catch it until I read JW's response:

SSR is a DOWNcounting register!

That's it. Utter relief!

THANK YOU, Clive and JW!!
Posted on March 20, 2013 at 18:58

Btw. (1023-fracsec)/1024 sounds to be faster than fracsec - fracsec/42... 😉

JW

Posted on March 20, 2013 at 18:59

Double post because of server throwing error to my posts (thrice).

cygnus
Associate II
Posted on March 20, 2013 at 19:28

JW,

In integer math, (1023 - fracsec) / 1024 = 0, always. Were you thinking of floating point?

The corrected calculation is fracsec = 999 - (fracsec - fracsec/42). That's integer milliseconds, again.

I agree with your assessment of the forum software, btw!! SharePoint - ugh. =P

Posted on March 20, 2013 at 19:57

> In integer math, (1023 - fracsec) / 1024 = 0, always.

Getting late here... 🙂

> Were you thinking of floating point?

Nah.

1000 *  (1023 - fracsec) / 1024

mul/shift should be faster than div; although div by constant is converted by any half-intelligent compiler to mul too, so...

  fracsec = 999 - (fracsec - fracsec/42);

 8000204:    f240 0300     movw    r3, #0

 8000208:    f2c2 0300     movt    r3, #8192    ; 0x2000

 800020c:    f640 4231     movw    r2, #3121    ; 0xc31

 8000210:    6818          ldr    r0, [r3, #0]

 8000212:    6819          ldr    r1, [r3, #0]

 8000214:    0840          lsrs    r0, r0, #1

 8000216:    f2c3 02c3     movt    r2, #12483    ; 0x30c3

 800021a:    b410          push    {r4}

  fracsec = 999 - (fracsec - fracsec/42);

 800021c:    fba2 4200     umull    r4, r2, r2, r0

 8000220:    ebc1 0292     rsb    r2, r1, r2, lsr #2

 8000224:    f202 32e7     addw    r2, r2, #999    ; 0x3e7

 8000228:    601a          str    r2, [r3, #0]

  fracsec = 1000 * (1023 - fracsec) / 1024;

 800022a:    6819          ldr    r1, [r3, #0]

 800022c:    f64f 4218     movw    r2, #64536    ; 0xfc18

 8000230:    f6cf 72ff     movt    r2, #65535    ; 0xffff

 8000234:    fb02 f201     mul.w    r2, r2, r1

 8000238:    f502 2279     add.w    r2, r2, #1019904    ; 0xf9000

 800023c:    f602 4218     addw    r2, r2, #3096    ; 0xc18

 8000240:    0a92          lsrs    r2, r2, #10

 8000242:    601a          str    r2, [r3, #0]

Hard to say without trying to simulate/emulate, but I'd say mine is marginally faster.

Not that it means anything - especially if waiting for RSF means you are likely to waste 1/32.768 ms anyway...

Btw. ST, if you listen, this really could bear some clarification: why would waiting for RSF needed for ''read accesses to the calendar in a time interval smaller than 2 RTCCLK periods''?

JW

cygnus
Associate II
Posted on March 20, 2013 at 20:06

JW,

Looks like you're probably right. I ought to have a look at what my own compiler produces. And even though you're right - I'm waiting for RSF and that wait will blow away any speed differences - well, there's something to be said for wanting to go through the exercise in the first place. It's what separates coders and engineers, after all.

I'm still mortified by my 'forest-for-the-trees' moment (SSR downcounting). On the other hand, so far as I've been able to tell, nowhere in the Reference Manual is that made explicit. One has to infer it from the equation Clive pointed out, which is a note under the subsecond field description for RTC_SSR in the Reference Manual.