aboutsummaryrefslogtreecommitdiffstats
path: root/notes/timers.txt
blob: 647e92e072971e5381f46fcb0fe5e5da619ee313 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
Timers
======

Medium-density chips have timers 1 through 4.  High- and XL-density
chips additionally have timers 5 through 8.  XL-density chips
additionally have timers 9--14, which we don't support yet.

Timer Capabilities
------------------

Each of timers 1--4 has 4 capture/compare (C/C) channels (also numbered
1--4). These are directly used by PWM, but may serve other purposes as
well (including handling user-specified periodic interrupts). The
STM32 implementation is particularly featureful, with, e.g., the
ability to chain together timers.

Timers 1 and 8 are an advanced timers, with many more features.
Wirish just uses just their capture/compare interrupts and enables MOE
during initialization, essentially treating them as general purpose
timers (like timers 2--5).  Advanced timers also have separate break,
update, and trigger interrupts that we only provide low-level
(i.e. libmaple proper) support for.

Timers 6 and 7 are basic timers, without C/C channels.  They are still
useful for interrupts (via NVIC_TIMER6, NVIC_TIMER7 IRQs, which can
fire upon an update event), but they're most useful for controlling
periodic DAC output.

Known Issues and Other Caveats
------------------------------

There are some conflicts between timer C/C outputs and USART 1 and 2
TX/RX.  Wirish tries to handle this gracefully, but (as of 7 April
2011) not all the bugs are sorted yet.  In particular, if you call
HardwareSerial::disable(), then try to use PWM, the USART TX pins
don't cooperate.

Resetting the prescaler or reload value only takes effect at the next
update event.  You can use timer_generate_update() to generate an
update event via software.

Other interrupts (SysTick, USB, Serial, etc.) can interfere with
timing-critical applications.  If your program requires precise
timing, you should probably at least disable USB and SysTick.  Note
that this also disables the bootloader and stops millis()/micros()
from counting.

Getting really good timing is a bit of an art.  If things don't work
at first, you need to fiddle with an oscilloscope and the exact
overflow/compare numbers to get precise behavior.

TODO
----

- Document more carefully (e.g., determine clock-wise and
  overflow-wise behavior for each function).

- Track down and handle pin conflicts.

- Input capture interface.  DON'T WRITE pulseIn() IN TERMS OF THIS.
  Do that as a simple, Arduino style implementation that just
  busy-waits and uses micros(), to allow a pulseIn() on arbitrary
  pins.  Eventually, expose the more precise/harder to use timer-based
  API via a convenience library.

- Complementary outputs, with convenient break/dead time interface.

- Additional modes (center-aligned PWM, one pulse mode, etc.) and
  count configuration (down, up/down).

Alternative Wirish Implementations
----------------------------------

The current Wirish API is big and clunky.  Its inclusion by default
also threatens making everyone's sketches bigger unnecessarily.  We
need to deprecate the parts of it that are bad for 0.0.10, and remove
them when 0.1.0 comes out.

Current implementation was inspired by Timer1 Library for Arduino:

http://arduino.cc/pipermail/developers_arduino.cc/2010-June/002845.html

Here's one of the more standard libaries out there:

http://www.arduino.cc/playground/Code/Timer1

        void initialize(long microseconds=1000000);
        void start();
        void stop();
        void restart();
        void setPeriod(long microseconds);
        void pwm(char pin, int duty, long microseconds=-1);
        void setPwmDuty(char pin, int duty);
        void disablePwm(char pin);
        void attachInterrupt(void (*isr)(), long microseconds=-1);
        void detachInterrupt();