|
NetBurner 3.5.7
PDF Version |
Topics | |
| High Resolution Delay Timer | |
| High-precision microsecond delay functionality. | |
| Interval Timer | |
| Stopwatch Timer | |
NetBurner provides three hardware timer APIs plus one software tick-based task delay:
| API | Header | Purpose |
|---|---|---|
HiResDelay (DelayObject) | HiResDelay.h | Blocking microsecond-precision delays |
| IntervalTimer | IntervalTimer.h | Periodic callbacks, semaphore posts, or flag sets |
| StopWatch | stopwatch.h | High-resolution elapsed time measurement |
| OSTimeDly() | nbrtos.h | Block the calling task for N RTOS system ticks (no hardware timer consumed) |
Each hardware API allocates timers from the underlying CPU's hardware timer peripherals. The number of available timers and the specific hardware used varies by CPU family. This document maps each platform to its timer hardware and documents resource limits.
OSTimeDly() is a software delay built on the existing RTOS system tick — it does not consume any hardware timer from the pools described below. See the OSTimeDly (Software Task Delay) section near the end of this document.
| Platform | CPU | Architecture | Timer Hardware |
|---|---|---|---|
| MOD5441X | MCF5441X | ColdFire | DMA Timers + PIT Timers |
| NANO54415 | MCF5441X | ColdFire | DMA Timers + PIT Timers |
| SB800EX | MCF5441X | ColdFire | DMA Timers + PIT Timers |
| MODM7AE70 | SAME70 | Cortex-M7 | TC (Timer Counter) Channels |
| SBE70LC | SAME70 | Cortex-M7 | TC Channels |
| SOMRT1061 | MIMXRT10xx | Cortex-M7 | Quad Timers (QTimer) |
| MODRT1171 | MIMXRT11xx | Cortex-M7 | Quad Timers (QTimer) |
| CPU Family | HiResDelay Pool | IntervalTimer Pool | StopWatch Source | Total HW Timers |
|---|---|---|---|---|
| MCF5441X | 4 DMA timers (shared with StopWatch) | 2 PIT timers (PIT 1-2) | 1 DMA timer (shared from same 4) | 4 DMA + 4 PIT |
| SAME70 | 12 TC channels (shared pool) | 12 TC channels (shared pool) | SysTick (no timer consumed) | 12 TC |
| MIMXRT10xx | 12 QTimer channels (shared pool) | 12 QTimer channels (shared pool) | System QTimer pair (no user timer consumed) | 12 QTimer |
| MIMXRT11xx | 12 QTimer channels (shared pool) | 12 QTimer channels | System QTimer pair (no user timer consumed) | 12 QTimer |
Each CPU reserves certain timer hardware for the RTOS system tick. These timers are not available to user code and are already excluded from the timer API allocation pools.
| CPU | Reserved Hardware | Purpose | Configured In |
|---|---|---|---|
| MCF5441X | PIT 0 | RTOS system tick (OSTickISR) | platform/*/source/hal.cpp via sim2.pit[0] |
| PIT 3 | Debugger | platform/*/source/hal.cpp via sim2.pit[3] | |
| SAME70 | ARM SysTick | RTOS system tick (SysTick_Handler) | platform/*/source/hal.cpp via SysTick_Config() |
| MIMXRT10xx/11xx | TMR4 channels 2-3 | RTOS system tick (SysTick_Handler) | platform/*/source/hal.cpp via SysTmrLo/SysTmrHi on TMR4 |
Key points:
Platforms: MOD5441X, NANO54415, SB800EX
The MCF5441X has 4 DMA timers (DMA Timer 0-3), accessed through sim2.timer[0..3]. These are 32-bit free-running timers clocked at CPU_CLOCK / 2 (~75 MHz at 150 MHz CPU clock).
DelayObject allocates one DMA timer. Up to 4 DelayObject instances can exist simultaneously. The timer is held for the lifetime of the object.StopWatch instance allocates one DMA timer. All subsequent StopWatch instances share that same timer (singleton initialization via bTimerInit flag).DelayObject instances take timers 1 and 2, only timer 3 remains.Timer allocation: FIRST_UNUSED_TIMER scans sim2.timer[0..3], selecting the first timer whose TMR register bit 0 is clear (timer disabled).
Clock and resolution:
CPU_CLOCK / 2 (prescale = 1), typically 75 MHz2 / CPU_CLOCK seconds per tick (~13.3 ns at 150 MHz)CountResolution() returns 2.0 / CPU_CLOCKConvert(ticks) returns ticks * 2 / CPU_CLOCKShort-delay busy-wait: Delays <= 20 us use a hand-tuned busy-wait loop instead of the hardware timer to avoid semaphore overhead. The loop uses nop instructions calibrated for the ColdFire pipeline.
Max single delay: The 32-bit reference register allows delays up to 0xFFFFFFFF / (CPU_CLOCK/2) seconds (~57 seconds at 75 MHz).
Source files:
arch/coldfire/cpu/MCF5441X/source/HiResDelay.cpparch/coldfire/cpu/MCF5441X/source/stopwatch.cppThe MCF5441X has 4 PIT (Programmable Interrupt Timer) modules. PIT 0 is reserved for the RTOS system tick, and PIT 3 is reserved for the debugger. PIT 1 and PIT 2 are available for application IntervalTimer use.
FindUnusedPit() scans PIT 1, 2, and 3 checking the pcsr enable bit. However, ISR handlers and configuration functions only exist for PIT 1 and PIT 2 (NbPit1_ISR, NbPit2_ISR), so effectively only 2 IntervalTimers can be active simultaneously.Prescaler: The prescaler is auto-selected to fit the desired frequency within the 16-bit counter range. Divider values range from 2 to 32768 (4-bit field, powers of 2).
Minimum frequency: The code checks num_per_sec < 1 (returns -2), so the practical minimum is 1 Hz. The header documentation recommends >= 20 Hz.
Source files:
arch/coldfire/cpu/MCF5441X/source/IntervalTimer.cpparch/coldfire/cpu/MCF5441X/source/pitr_sem.cppPlatforms: MODM7AE70, SBE70LC
The SAME70 has 4 TC blocks (TC0-TC3), each with 3 channels, totaling 12 TC channels (timers 0-11). These are managed by a unified dispatch system (timer_dispatch.cpp) with a 16-bit timerInUse bitmask.
DelayObject calls AllocateTimer() to reserve a TC channel from the shared 12-channel pool. The channel is freed on destruction via FreeTimer().IntervalOSSem(), IntervalOSFlag(), or IntervalInterruptCallback() call allocates a TC channel from the same shared 12-channel pool.DelayObject and an IntervalOSSem() each consume one timer.Timer dispatch architecture (timer_dispatch.cpp):
AllocateTimer(handler, extra, timer): Allocates a timer, registers ISR handler. Returns timer number or -1/-2 on failure.FreeTimer(timer): Releases a timer back to the pool.GetTc(timer): Maps timer number (0-11) to TcChannel* via tc[timer/3]->TC_CHANNEL[timer%3].GetTimerPeriphID(timer): Maps timer number to NVIC IRQ number (TC0_IRQn through TC11_IRQn).TC0_Handler() through TC11_Handler() forward to registered handlers.Clock selection (IntervalTimer): The driver auto-selects the clock source that minimizes frequency error:
OSC_CLOCK)PERIPH_CLOCK / 8PERIPH_CLOCK / 32PERIPH_CLOCK / 128Each option is evaluated with ClockCheck() and the best-fit is chosen. The 16-bit compare register limits the maximum divider per clock source to 65535.
Clock (HiResDelay): Uses TC_CMR_TCCLKS_TIMER_CLOCK2 (PERIPH_CLOCK / 8). At 300 MHz CPU, PERIPH_CLOCK is typically 150 MHz, giving 18.75 MHz timer clock (75/4 ticks per microsecond).
Short-delay busy-wait: Delays <= 20 us use a calibrated busy-wait loop (magic number 55).
Max single HiResDelay: ~3400 us per hardware delay cycle (16-bit compare register at 18.75 MHz). Longer delays are handled by chaining multiple 3001 us delays.
StopWatch on SAME70 uses the ARM SysTick timer, which is already running for the RTOS tick. No additional hardware timer is consumed.
GetNow() combines SysTick->VAL (down-counter) with the TimeTick software counter to produce a 64-bit timestamp at CPU clock resolution.TimeTick increments between two reads of SysTick->VAL and compensates. Also checks for pending SysTick ISR when called from interrupt context.Resolution: 1 / CPU_CLOCK seconds per tick (~3.3 ns at 300 MHz).
Source files:
arch/cortex-m7/cpu/SAME70/source/HiResDelay.cpparch/cortex-m7/cpu/SAME70/source/IntervalTimer.cpparch/cortex-m7/cpu/SAME70/source/stopwatch.cpparch/cortex-m7/cpu/SAME70/source/timer_dispatch.cppPlatforms: SOMRT1061
The MIMXRT10xx has 3 QTimer modules (TMR1[0..2]), each with 4 channels, totaling 12 QTimer channels (timers 0-11). HiResDelay and IntervalTimer share this pool.
FindUnusedTimer().DelayObject is implemented within IntervalTimer.cpp and allocates from the same 12-channel pool via FindUnusedTimer(). It registers the shared IntervalTmrCB callback and uses the semaphore-based interval context for wake-up.intervalCtx[12] array tracks allocations; FindUnusedTimer() checks both the context type and hardware COMP1/COMP2 registers to find free channels.Timer allocation** (FindUnusedTimer()): Iterates modules 0-2, channels 0-3 (12 total). A channel is free if intervalCtx[].type == None AND COMP1 == 0 AND COMP2 == 0.
Prescaling (IntervalTimer): 8 hardware prescale levels (QTMR_PRI_CLK_DIV_1 through QTMR_PRI_CLK_DIV_128, shifting PERIPH_CLOCK by 0-7 bits). If prescale 7 is still insufficient for the desired frequency, a software divider (swDiv = 0xF, dividing by 16) extends the range further. The 16-bit compare register limits the count per prescale level to 65535.
Clock (HiResDelay): Uses QTMR_PRI_CLK_DIV_1 (no prescale), counting at PERIPH_CLOCK (typically 132 MHz on SOMRT1061). This gives ~132 counts per microsecond.
Short-delay busy-wait: Delays <= 21 us use a calibrated busy-wait loop (magic number 63 for inner loop, 58 for startup).
Max single HiResDelay: ~498 us per hardware delay cycle (0xFFFF / (PERIPH_CLOCK / 1000000)). Longer delays are handled by chaining multiple 497 us delays.
StopWatch on MIMXRT10xx uses a pre-allocated linked QTimer pair (SysTmrLo / SysTmrHi) that is already set up by the HAL for system timekeeping. No user QTimer channel is consumed.
GetNow() reads SysTmrLo.CNTR + SysTmrHi.HOLD * (SysTmrLo.COMP1 + 1) and combines with TimeTick for a 64-bit timestamp.Resolution: 1 / (PERIPH_CLOCK / 16) seconds per tick. At 132 MHz PERIPH_CLOCK, this is 1 / 8,250,000 = ~121 ns.
Source files:
arch/cortex-m7/cpu/MIMXRT10xx/source/IntervalTimer.cpp (includes HiResDelay implementation)arch/cortex-m7/cpu/MIMXRT10xx/source/stopwatch.cppPlatforms: MODRT1171
The MIMXRT11xx has the same 3 QTimer modules x 4 channels = 12 QTimer channels as MIMXRT10xx. The IntervalTimer implementation is structurally identical to MIMXRT10xx.
Key difference from MIMXRT10xx: The MIMXRT11xx IntervalTimer.cpp does not include the DelayObject (HiResDelay) implementation. There is no separate HiResDelay.cpp for this CPU. HiResDelay is not available on MIMXRT11xx platforms.
Identical to MIMXRT10xx. Uses the pre-allocated SysTmrLo / SysTmrHi QTimer pair. No user timer consumed.
Resolution: 1 / (PERIPH_CLOCK / 16) seconds per tick, same as MIMXRT10xx.
Source files:
arch/cortex-m7/cpu/MIMXRT11xx/source/IntervalTimer.cpparch/cortex-m7/cpu/MIMXRT11xx/source/stopwatch.cppAll three APIs accept FIRST_UNUSED_TIMER (defined as -1 in constants.h) as the default timer parameter. This triggers automatic allocation of the next available hardware timer.
| Return Value | Meaning |
|---|---|
| >= 0 | Success: allocated timer number |
| -1 | No hardware timer available (all in use) |
| -2 | Invalid frequency (IntervalTimer: < 1 Hz in code, recommended >= 20 Hz) |
valid() to check allocation success.IntervalOSSem() / IntervalOSFlag() / IntervalInterruptCallback() call. Must call IntervalStop(timer_number) to release.| CPU | Max Concurrent DelayObjects | Max Concurrent IntervalTimers | StopWatch Cost |
|---|---|---|---|
| MCF5441X | 3 (if StopWatch uses 1 DMA timer) | 2 (PIT 1-2) | 1 DMA timer (shared) |
| SAME70 | 12 minus active IntervalTimers | 12 minus active DelayObjects | Free (SysTick) |
| MIMXRT10xx | 12 minus active IntervalTimers | 12 minus active DelayObjects | Free (system QTimer) |
| MIMXRT11xx | N/A (not available) | 12 | Free (system QTimer) |
| CPU | HiResDelay | IntervalTimer | StopWatch | Timer Dispatch |
|---|---|---|---|---|
| MCF5441X | arch/coldfire/cpu/MCF5441X/source/HiResDelay.cpp | arch/coldfire/cpu/MCF5441X/source/IntervalTimer.cpp + pitr_sem.cpp | arch/coldfire/cpu/MCF5441X/source/stopwatch.cpp | N/A (direct register access) |
| SAME70 | arch/cortex-m7/cpu/SAME70/source/HiResDelay.cpp | arch/cortex-m7/cpu/SAME70/source/IntervalTimer.cpp | arch/cortex-m7/cpu/SAME70/source/stopwatch.cpp | arch/cortex-m7/cpu/SAME70/source/timer_dispatch.cpp |
| MIMXRT10xx | Combined in IntervalTimer.cpp | arch/cortex-m7/cpu/MIMXRT10xx/source/IntervalTimer.cpp | arch/cortex-m7/cpu/MIMXRT10xx/source/stopwatch.cpp | N/A (inline in IntervalTimer.cpp) |
| MIMXRT11xx | Not available | arch/cortex-m7/cpu/MIMXRT11xx/source/IntervalTimer.cpp | arch/cortex-m7/cpu/MIMXRT11xx/source/stopwatch.cpp | N/A (inline in IntervalTimer.cpp) |
nbrtos/include/HiResDelay.h - DelayObject classnbrtos/include/IntervalTimer.h - IntervalOSSem, IntervalOSFlag, IntervalInterruptCallback, IntervalStopnbrtos/include/stopwatch.h - StopWatch class| CPU | StopWatch Resolution | StopWatch Convert |
|---|---|---|
| MCF5441X | 2.0 / CPU_CLOCK sec/tick | ticks * 2.0 / CPU_CLOCK seconds |
| SAME70 | 1.0 / CPU_CLOCK sec/tick | ticks / CPU_CLOCK seconds |
| MIMXRT10xx/11xx | 1.0 / (PERIPH_CLOCK / 16) sec/tick | ticks / (PERIPH_CLOCK / 16) seconds |
| CPU | Clock Variable | Typical Value | StopWatch Tick |
|---|---|---|---|
| MCF5441X | CPU_CLOCK | 150 MHz | ~13.3 ns |
| SAME70 | CPU_CLOCK | 300 MHz | ~3.3 ns |
| MIMXRT10xx | PERIPH_CLOCK | 132 MHz | ~121 ns |
| MIMXRT11xx | PERIPH_CLOCK | 240 MHz | ~66.7 ns |
OSTimeDly() is the RTOS primitive for delaying the currently executing task by a number of system ticks. Unlike the three hardware timer APIs above, it is built on the existing RTOS system tick and does not allocate a hardware timer from any pool.
Declaration:
to_count — number of RTOS system ticks to block the calling task.nbrtos.hOSTimeWaitUntil(to_count + TimeTick).The number of system ticks per second is defined by TICKS_PER_SECOND in nbrtos/include/constants.h. The default is 20 ticks/second (50 ms per tick). Always express delays in terms of TICKS_PER_SECOND rather than a hard-coded count so the code remains correct if the tick rate is changed:
| Characteristic | OSTimeDly() | DelayObject (HiResDelay) |
|---|---|---|
| Resolution | 1 system tick (50 ms default) | Microseconds |
| Hardware cost | None | 1 hardware timer per object |
| Behavior | Task-level reschedule; other tasks run during delay | Blocks on semaphore/busy-wait; short delays busy-wait |
| Typical use | Polling loops, periodic task work, pacing network retries | Precise pulse widths, microsecond-accurate bus timing |
| Callable from ISR | No | No (constructor must not run in ISR) |
Use OSTimeDly() for any delay coarser than a few tick periods where microsecond accuracy is not required. It costs no hardware timer resources and is the idiomatic way to pace task loops in NetBurner applications.
| Function | Purpose |
|---|---|
OSTimeDly(ticks) | Delay for ticks system ticks relative to now |
OSTimeWaitUntil(tickValue) | Delay until TimeTick reaches an absolute value |
OSChangeTaskDly(prio, ticks) | Change an already-delayed task's wake-up to ticks from now |
See also: OSTimeWaitUntil(), OSChangeTaskDly(), TimeTick, TICKS_PER_SECOND.
Source: nbrtos/include/nbrtos.h