aboutsummaryrefslogtreecommitdiffstats
path: root/docs/source/timers.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/source/timers.rst')
-rw-r--r--docs/source/timers.rst123
1 files changed, 123 insertions, 0 deletions
diff --git a/docs/source/timers.rst b/docs/source/timers.rst
new file mode 100644
index 0000000..0fa0976
--- /dev/null
+++ b/docs/source/timers.rst
@@ -0,0 +1,123 @@
+.. highlight:: cpp
+
+.. _timers:
+
+Timers
+======
+
+There are four general purpose timers in the Maple microcontroller
+that can be configured to generate periodic or delayed events with
+minimal work done by the microcontroller. For example, the :ref:`PWM
+<pwm>` channels can generate regular square-wave signals on specific
+output pins without consuming extra clock cycles. By attaching
+interrupt handlers to these channels (instead of just changing the
+voltage on an external pin), more complex events can be scheduled.
+
+.. contents:: Contents
+ :local:
+
+Introduction
+------------
+
+.. _timers-prescale:
+
+The four timers each have four separate compare channels. Each channel
+has an associated 16-bit counter that can be configured with a 16-bit
+prescaler and a 16-bit overflow value. The prescaler determines how
+fast the counter changes, while the overflow value determines when it
+gets reset.
+
+The prescaler acts as a divider of the 72MHz system clock. That is,
+with a prescaler of 1, the channel's counter increments with a
+frequency of 72MHz, rolling over (passing the maximum 16-bit unsigned
+integer value of 65,535) more than a thousand times a second. With a
+prescaler of 7200, it has a frequency of (72/7200) MHz = 10 KHz,
+rolling over approximately every 6.55 seconds.
+
+The overflow value is the maximum value the counter will go up to. It
+defaults to the full 65,535; smaller values will cause the counter to
+reset to zero more frequently.
+
+Whenever a channel's counter reaches its overflow value, an "update
+event" interrupt is generated. You can configure the Maple to notify
+you when this takes place, by registering an interrupt handler, which
+is a function that will be called when the update event occurs.
+
+By default, different compare values only change the relative offsets
+between events on a single timer ("phase"). They don't control the
+frequency with which they occur. However, a common trick is to
+increment the compare value manually in the interrupt handler so that
+the event will fire again after the increment period. There can be a
+different increment value for each channel, so this trick allows
+events to be programmed at 4 different rates on a single timer. Note
+that function call overheads mean that the smallest increment rate is
+at least a few microseconds.
+
+Library Documentation
+---------------------
+
+See the :ref:`HardwareTimer <lang-hardwaretimer>` reference for more
+information on controlling the built-in timers.
+
+Caveats
+-------
+
+Working with timers and interrupts can be tricky; they are a somewhat
+"advanced" topic. The following subsections explain some common
+problems associated with using timers and timer interrupts.
+
+In general: start simple, test with :ref:`lang-assert`, and don't try
+to do too much in your interrupt handlers! Make sure that what you're
+trying to do in a handler isn't going to block other interrupts from
+firing, if those other interrupts are important for your program.
+
+.. _timers-pwm-conflicts:
+
+PWM Conflicts
+^^^^^^^^^^^^^
+
+Because PWM functionality on a given pin depends on the configuration
+of the timer and channel, you must chose your channels carefully if
+you want to use both timer interrupts and PWM in the same program.
+Refer to your board's timer pin map to match up timer channels and pin
+numbers:
+
+* :ref:`Maple <maple-timer-map>`
+* :ref:`Maple RET6 Edition <maple-ret6-timer-map>`
+* :ref:`Maple Mini <maple-mini-timer-map>`
+* :ref:`Maple Native Beta <maple-native-b-timer-map>`
+
+Overhead
+^^^^^^^^
+
+There is some overhead associated with function and interrupt calls
+(loading and unloading the stack, preparing state, etc.) and this
+overhead can fudge your timing. Imperfect code branching also means
+that, e.g., channel 1 interrupts may get called a couple clock cycles
+sooner than a channel 4 interrupt, all other configuration being the
+same.
+
+Jitter
+^^^^^^
+
+Other interrupts can and will get called before or during the timer
+interrupt routines, causing pseudorandom delays and other
+frustrations.
+
+Disabling the :ref:`USB <usb>` port (by calling ``SerialUSB.end()``,
+or just running off a battery) helps a lot, but then you lose the
+auto-reset and communications functionality. This will require that
+you put your Maple into :ref:`perpetual bootloader mode
+<troubleshooting-perpetual-bootloader>` before uploading a new program
+to it (or somehow causing your program to re-enable serial over USB
+using :ref:`SerialUSB.begin() <lang-serialusb-begin>`).
+
+The :ref:`SysTick <systick>` peripheral another way to perform
+periodic or delayed events. Its separate timer does not conflict with
+any other peripherals, but the associated 1 kHz interrupt can jitter
+the general purpose timer interrupts. The SysTick peripheral can be
+disabled by calling :ref:`systick_disable()
+<libmaple-systick-disable>`, and re-enabled using
+:ref:`systick_enable() <libmaple-systick-enable>`. However, be aware
+that calling ``systick_disable()`` will stop the values coming from
+:ref:`lang-micros` and :ref:`lang-millis` from increasing.