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?
Solved! Go to Solution.
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).
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.
Thank you for your reply. It solved the problem we had.