Skip to content

Commit f14461d

Browse files
Fix-Pointlinguini1
authored andcommitted
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>
1 parent 99ca0db commit f14461d

File tree

2 files changed

+11
-4
lines changed

2 files changed

+11
-4
lines changed

include/nuttx/timers/clkcnt.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ void clkcnt_best_multshift(uint32_t freq, uint32_t scale,
8484
{
8585
uint32_t logfreq = log2floor(freq);
8686

87-
/* Be careful of the round-nearest behavior here.
87+
/* Do not use the round-nearest behavior here.
8888
* It may lead to the converted result is larger than the
8989
* integer division.
9090
* 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,
103103
* affecting the accuracy of time compensation.
104104
*/
105105

106-
*mult = (((uint64_t)scale << logfreq) + (freq >> 1)) / freq;
106+
*mult = ((uint64_t)scale << logfreq) / freq;
107107
*shift = logfreq;
108108
}
109109

include/nuttx/timers/oneshot.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
* Pre-processor Definitions
4545
****************************************************************************/
4646

47+
#define ONESHOT_NSEC_TOLERANT 5
48+
4749
/* IOCTL commands ***********************************************************/
4850

4951
/* 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,
293295
&lower->cnt2nsec_mult,
294296
&lower->cnt2nsec_shift);
295297

296-
/* Ensure the maximum error of the mult-shift is less than 5ns. */
298+
/* Ensure the maximum error of the mult-shift is less than
299+
* ONESHOT_NSEC_TOLERANT.
300+
*/
297301

298302
result = clkcnt_delta_cnt2nsec_fast(frequency, lower->cnt2nsec_mult,
299303
lower->cnt2nsec_shift);
300304

301-
ASSERT(NSEC_PER_SEC - 5 <= result && NSEC_PER_SEC + 5 >= result);
305+
ASSERT(NSEC_PER_SEC - ONESHOT_NSEC_TOLERANT <= result &&
306+
NSEC_PER_SEC >= result);
302307

303308
# ifdef CONFIG_ONESHOT_FAST_DIVISION
304309
/* invdiv requires the invariant-divsor > 1. */
@@ -402,6 +407,8 @@ int oneshot_current(FAR struct oneshot_lowerhalf_s *lower,
402407
cnt -= sec * freq;
403408
ts->tv_nsec = oneshot_delta_cnt2nsec(lower, cnt);
404409
ts->tv_sec = sec;
410+
411+
DEBUGASSERT(cnt < freq && ts->tv_nsec < NSEC_PER_SEC);
405412
#else
406413
ret = lower->ops->current(lower, ts);
407414
#endif

0 commit comments

Comments
 (0)