mirror of
https://github.com/apache/nuttx.git
synced 2026-08-18 02:38:18 +00:00
timers/oneshot: Fix converted tv_nsec > NSEC_PER_SEC.
In rare case, the round-nearest behavior in the clkcnt_best_multshift may result in converted tv_nsec > NSEC_PER_SEC. This commit fixed the issue. Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
This commit is contained in:
parent
99ca0dbf9d
commit
f14461db2e
2 changed files with 11 additions and 4 deletions
|
|
@ -84,7 +84,7 @@ void clkcnt_best_multshift(uint32_t freq, uint32_t scale,
|
|||
{
|
||||
uint32_t logfreq = log2floor(freq);
|
||||
|
||||
/* Be careful of the round-nearest behavior here.
|
||||
/* Do not use the round-nearest behavior here.
|
||||
* It may lead to the converted result is larger than the
|
||||
* integer division.
|
||||
* In rare cases, this can cause the converted tick to be greater
|
||||
|
|
@ -103,7 +103,7 @@ void clkcnt_best_multshift(uint32_t freq, uint32_t scale,
|
|||
* affecting the accuracy of time compensation.
|
||||
*/
|
||||
|
||||
*mult = (((uint64_t)scale << logfreq) + (freq >> 1)) / freq;
|
||||
*mult = ((uint64_t)scale << logfreq) / freq;
|
||||
*shift = logfreq;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@
|
|||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define ONESHOT_NSEC_TOLERANT 5
|
||||
|
||||
/* IOCTL commands ***********************************************************/
|
||||
|
||||
/* These commands are used by applications to access the oneshot lower-half
|
||||
|
|
@ -293,12 +295,15 @@ void oneshot_count_init(FAR struct oneshot_lowerhalf_s *lower,
|
|||
&lower->cnt2nsec_mult,
|
||||
&lower->cnt2nsec_shift);
|
||||
|
||||
/* Ensure the maximum error of the mult-shift is less than 5ns. */
|
||||
/* Ensure the maximum error of the mult-shift is less than
|
||||
* ONESHOT_NSEC_TOLERANT.
|
||||
*/
|
||||
|
||||
result = clkcnt_delta_cnt2nsec_fast(frequency, lower->cnt2nsec_mult,
|
||||
lower->cnt2nsec_shift);
|
||||
|
||||
ASSERT(NSEC_PER_SEC - 5 <= result && NSEC_PER_SEC + 5 >= result);
|
||||
ASSERT(NSEC_PER_SEC - ONESHOT_NSEC_TOLERANT <= result &&
|
||||
NSEC_PER_SEC >= result);
|
||||
|
||||
# ifdef CONFIG_ONESHOT_FAST_DIVISION
|
||||
/* invdiv requires the invariant-divsor > 1. */
|
||||
|
|
@ -402,6 +407,8 @@ int oneshot_current(FAR struct oneshot_lowerhalf_s *lower,
|
|||
cnt -= sec * freq;
|
||||
ts->tv_nsec = oneshot_delta_cnt2nsec(lower, cnt);
|
||||
ts->tv_sec = sec;
|
||||
|
||||
DEBUGASSERT(cnt < freq && ts->tv_nsec < NSEC_PER_SEC);
|
||||
#else
|
||||
ret = lower->ops->current(lower, ts);
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue