Skip to content

Commit 043e38b

Browse files
committed
Update documentation
1 parent 17be03c commit 043e38b

File tree

2 files changed

+109
-1
lines changed

2 files changed

+109
-1
lines changed

docs/source/information/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Information
55
:maxdepth: 1
66

77
/_inc/Sming/building
8+
events
89
interrupts
910
timers
1011
debugging

docs/source/information/timers.rst

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
Timers
2-
------
2+
======
3+
4+
.. highlight:: c++
5+
6+
Generally, timers in Sming fall into two categories: Callback Timers and Polled Timers
7+
8+
Callback Timers
9+
---------------
10+
11+
A callback timer is operated by programming a time interval, then arming it. When the timer
12+
'fires' a function of your choosing gets called. Timers can be 'one-shot', for timing single
13+
events, or 'auto-reset' repetitive timers. A repetitive timer will ensure that time intervals
14+
between successive callbacks are consistent.
15+
16+
There are two categories of callback timer.
317

418
Hardware timers
519
The ESP8266 has two main hardware timers. Timer1 is a countdown timer, which triggers
@@ -24,3 +38,96 @@ Software timers
2438
and delegate callback functions so you can use it with class methods, capturing lambdas, etc.
2539

2640
The *SimpleTimer* class uses less RAM, but only supports regular function callbacks.
41+
42+
Polled timers
43+
-------------
44+
45+
Polled timers can be used to measure elapsed time intervals or to check for timeouts within code loops.
46+
Traditionally one might do this as follows::
47+
48+
#define TIMEOUT_MS 100
49+
50+
int timeout = millis() + TIMEOUT_MS;
51+
while(millis() < timeout) {
52+
// do some stuff
53+
}
54+
int elapsed = millis() - start;
55+
Serial.print("Elapsed time: ");
56+
Serial.print(elapsed);
57+
Serial.println("ms");
58+
59+
This looks OK, and will work until millis() approaches MAXINT at which point it falls over, a little under 25 days.
60+
With microseconds it'll happen in less than an hour. It should always be coded like this::
61+
62+
int start = millis();
63+
while(millis() - start < TIMEOUT_MS) {
64+
// do some stuff
65+
}
66+
67+
The easy way to get it right is to use a Polled Timer, like this::
68+
69+
OneShotFastMs timer(TIMEOUT_MS);
70+
while(!timer.expired()) {
71+
// do some stuff
72+
}
73+
auto elapsed = timer.elapsedTime(); // This obtains a `Time` object, containing a value plus time unit
74+
Serial.print("Elapsed time: ");
75+
Serial.println(elapsed); // Includes units in the elapsed time interval
76+
77+
If you prefer to use microseconds, use *OneShotFastUs* instead. You can work with other units
78+
of time like this::
79+
80+
OneShotElapseTimer<NanoTime::Seconds>;
81+
82+
Another advantage of polled timers is speed. Every call to millis (or micros) requires a calculation
83+
from clock ticks into milliseconds (or microseconds). It's also a function call.
84+
85+
Polled timers measure time using hardware clock ticks, and queries the hardware timer register directly.
86+
The code is also compiled inline so there is no function call overhead. This makes them a much better
87+
choice for tight timing loops.
88+
89+
See *PolledTimer.h* for more details.
90+
91+
Clocks
92+
------
93+
94+
Timers and their capabilities can vary considerably. For example, Timer1 can be configured with
95+
a prescaler of 1, 16 or 256 which affects both the resolution and range of the timer. One might
96+
also consider the CPU cycle counter to have a selectable prescaler of 1 or 2, depending on
97+
whether it's running at 80MHz or 160MHz.
98+
99+
Each hardware timer has an associated *Clock* definition in `Platform/Clocks.h`, each of which
100+
simply defines the properties for each Clock source. It's defined as a class template.
101+
102+
Clocks are made more useful by *TimeSource*, another class template defined in *NanoTime.h*.
103+
Any time you need to convert between time values and tick values, it'll be through a method
104+
of a TimeSource.
105+
106+
Let's say we want a microsecond source using Timer2::
107+
108+
TimeSource<Timer2Clock, NanoTime::Microseconds, uint32_t> t2source;
109+
110+
We can now call methods of *t2source* like this::
111+
112+
// What's the maximum Timer2 value in microseconds?
113+
Serial.println(t2source.maxClockTime());
114+
115+
// How many clock ticks per microsecond ?
116+
Serial.println(t2source.ticksPerUnit()); // 5/1
117+
118+
// How many clock ticks for 100us ?
119+
Serial.println(t2source.template timeConst<100>().ticks());
120+
121+
Note that all of these values are computed at compile time. Some runtime conversions::
122+
123+
Serial.println(t2source.timeToTicks(100));
124+
Serial.println(t2source.ticksToTime(10000));
125+
126+
The results of conversions are rounded rather than truncated, which provides more accurate
127+
results and reduces timing jitter.
128+
129+
For debugging purposes you can print a description::
130+
131+
Serial.println(t2source.toString()); // "Timer2Clock/5MHz/32-bit/microseconds"
132+
133+
See *NanoTime.h* for further details.

0 commit comments

Comments
 (0)