2013-03-20 09:36 AM
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-subsecond2013-03-20 09:58 AM
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.
2013-03-20 10:24 AM
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?) JW2013-03-20 10:45 AM
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.2013-03-20 10:49 AM
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!!2013-03-20 10:58 AM
Btw. (1023-fracsec)/1024 sounds to be faster than fracsec - fracsec/42... ;)
JW2013-03-20 10:59 AM
Double post because of server throwing error to my posts (thrice).
2013-03-20 11:28 AM
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. =P2013-03-20 11:57 AM
> 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''? JW2013-03-20 12:06 PM
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.