| 339 | template <hw_timer_clkdiv_t clkdiv, NanoTime::Unit unit, typename TimeType> |
| 340 | struct Timer1TestSource : public Timer1Clock<clkdiv> { |
| 341 | static TimeType timeToTicks_test1(const TimeType& time) |
| 342 | { |
| 343 | /* |
| 344 | * Refactorise to eliminate overflow when scaling down and avoid division by |
| 345 | * using pre-defined constant values. |
| 346 | * |
| 347 | * Original code: |
| 348 | * |
| 349 | * if(us > 0x35A) |
| 350 | * return (us / 4) * (frequency / 250000) + (us % 4) * (frequency / 1000000); |
| 351 | * |
| 352 | * This only works for /16 prescale. It's also un-necessary since the ratio reduces to 5:1, |
| 353 | * i.e. it's just a x5 multiplication. |
| 354 | * |
| 355 | * However, with /256 prescale it's a little tricker. This code is used in the |
| 356 | * `ets_timer_arm_new` function for converting milliseconds into ticks: |
| 357 | * |
| 358 | * if(ms > 13743) |
| 359 | * return (ms / 4) * (frequency / 250) + (ms % 4) * (frequency / 1000) |
| 360 | * |
| 361 | * In this case the ratio is 625:2 which limits the range to 1'54"31.947, but this |
| 362 | * calculation offers an improvement to 3'49"25.92. It is probably slightly faster |
| 363 | * as well. |
| 364 | * |
| 365 | * Converting from microseconds the ratio is 16:5. |
| 366 | * |
| 367 | * The advantage of muldiv is that it is generic and will work with any ratio. |
| 368 | * In most cases it's just as fast, offers overflow detection and a greater range by |
| 369 | * using 64-bit calculations when necessary. |
| 370 | * |
| 371 | * Ideally all time conversions should be pre-calculated so that time-critical code |
| 372 | * (e.g. within ISRs) operates using the timer tick values. |
| 373 | * |
| 374 | */ |
| 375 | constexpr uint32_t prediv = 4; |
| 376 | constexpr auto unitTicks = NanoTime::unitTicks[unit]; |
| 377 | constexpr auto frequency = Timer1TestSource::frequency(); |
| 378 | constexpr uint32_t mul = frequency * unitTicks.den / (unitTicks.num / prediv); |
| 379 | constexpr uint32_t div = frequency * unitTicks.den / unitTicks.num; |
| 380 | |
| 381 | if(clkdiv == TIMER_CLKDIV_16) { |
| 382 | // debug_i("prediv = %u, frequency = %u, mul = %u, div = %u", prediv, frequency, mul, div); |
| 383 | return (time / prediv) * mul + (time % prediv) * div; |
| 384 | } |
| 385 | |
| 386 | using R = std::ratio<frequency * unitTicks.den, unitTicks.num>; |
| 387 | return muldiv<R::num, R::den>(time); |
| 388 | } |
| 389 | |
| 390 | TimeType timeToTicks_test2(const TimeType& time) |
| 391 | { |