Using a K64FN1M0M12, we tried to log some events with a millisecond resolution. To do so, we use the TPR register from RTC peripheral.
millisec = base->TPR;
millisec = (millisec * 1000) / 32768;
We have a problem with some consecutive reads: the value read from the register can have a lower value than the previous read. To highlight the problem, we implemented a single task which only reads the TPR register every millisecond and prints the value on a console. After about 30 minutes, we have 3 occurrences of the issue. Each read gives the TPR value incremented by 32 or 33. Here are 2 occurrences of the problem with the values of RTC->TPR :
Millisecond | TPR read value | Is value correct? | TPR expected value |
479 | 15711 | YES | - |
476 | 15616 (0x3D00) | NO | 15755 (0x3D80) |
481 | 15776 | YES | - |
Millisecond | TPR read value | Is value correct | TPR expected value |
577 | 18911 | YES | - |
562 | 18432 (0x4800) | NO | 18944 (0x4A00) |
579 | 18976 | YES | - |
As you can notice, there is a one bit difference between the read value and the expected value. Is there something we do wrong? Is this a known issue? Is there a way to prevent this from happening other than reading the register multiple times?
已解决! 转到解答。
The general solution for reading multiple bytes across different clock domains is:
uint16_t t1,t2;
do{
t1 = RTC->TPR
t2 = RTC->TPR
}while( t1 != t2 );
t1 is now valid at this point.
I've run in the same problem and rather than use the RTC, I ended up using a PIT requesting an interrupt every 1ms (actually every 100us in my application) which avoids the issue.
myke
http://www.ganssle.com/tem/tem355.html#article6 explains the general problem with multiple byte reads involving interrupts. Then throw in that RTC is in a different clock domain...
It is important to note the distinction between simultaneous (the hardware ticking) and concurrent (the software reading the hardware with interrupts).