cancel
Showing results for 
Search instead for 
Did you mean: 

RTC reading counter issue

juraj
Associate II
Posted on April 16, 2008 at 12:18

RTC reading counter issue

4 REPLIES 4
juraj
Associate II
Posted on May 17, 2011 at 12:30

Are these function from ST:

Code:

u32 RTC_GetCounter(void) {

u16 tmp = RTC->CNTL;

return (((u32)RTC->CNTH << 16 ) | tmp) ;

}

and

Code:

u32 RTC_GetDivider(void) {

u32 tmp = 0x00;

tmp = ((u32)RTC->DIVH & (u32)0x000F) << 0x10;

tmp |= RTC->DIVL;

return tmp;

}

safe to get always right information? Meaning that after reading first part of u32 value, the counter can be updated with overflow from lo-word to hi-word and the return values of these functions are not correct.

Am I right?

__________________

Then, I found in the firmware more times the same as here, in the RTC_GetDivider(void) there is:

Code:

u32 tmp = 0x00;

which is not needed operation. Why is this used widely?

Thanks.

togrady
Associate II
Posted on May 17, 2011 at 12:30

Yes I too think this is a problem. I changed it to keep reading until it gets two values the same which in 99.999% of cases will take just two reads.

Code:

u32 RTC_GetCounter(void)

{

u32 ticks, last_ticks = 0;

for (;;)

{

ticks = (((u32)RTC->CNTH << 16 ) | RTC->CNTL);

if (ticks == last_ticks)

break;

last_ticks = ticks;

}

return ticks;

}

daviddavid99
Associate
Posted on May 17, 2011 at 12:30

I would have heped that the RTC Count would have been a 32 bit register. Maybe it is a peripheral that originated in 16 bit land and has just been dropped in.

14 bit ADCs and 16 bit counters on 8 bit micros have this coherency problem, one of the solutions is for the low value to be latched into a low shadow register when the high register is read or vice versa. If this were the case then we would have been told surely, lets assume no such mechanism was implemented.

Any time that the low register is about to rollover we have danger. ie everytime CNTL == 0xFFFF we are in jeopardy. The nature of the error is read order dependent.

Assume rolover between reads:

CNTL = 0xFFFF -> 0x0000

CNTH = CNTH   -> CNTH + 1

L before H: Result is ((CNTH + 1) << 16) | 0xFFFF

H before L Result is ((CNTH + 0) << 16) | 0x0000

Should be            ((CNTH + 1) << 16) | 0x0000

Error = 0xFFFF or 0x10000

Be very careful.

Note that if CNTH is 0x0000 and we read H before L then incorrectly we read ticks as 0x0

Check against last_ticks which is 0x0

return 0x0 instead of 0x10000

Gut feeling is to set the initial value of last ticks as far from 0xnnnnFFFF and 0xnnnn0000 as possible eg 0x00007FFF

picguy2
Associate II
Posted on May 17, 2011 at 12:30

The general way of reading a running two part counter is

Loop:

  tempHi = ctrHi  //must read this one first

  tempLo = ctrLo

  if (tempHi != ctrHi) goto Loop

  return tempHi:tempLo

The extra read of ctrHi when we “goto Loop� is more than offset by the simplicity of the above and the rareness of the goto event.