aboutsummaryrefslogtreecommitdiffstats
path: root/source/timers.rst
diff options
context:
space:
mode:
Diffstat (limited to 'source/timers.rst')
-rw-r--r--source/timers.rst206
1 files changed, 55 insertions, 151 deletions
diff --git a/source/timers.rst b/source/timers.rst
index 56dd686..cb30081 100644
--- a/source/timers.rst
+++ b/source/timers.rst
@@ -5,6 +5,8 @@
Timers
======
+.. FIXME [0.0.10] links to systick.h in a few places on this page
+
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
@@ -43,164 +45,66 @@ 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.
-libmaple Reference
+Function Reference
------------------
-The libmaple API for interacting with timers is documented at the
-:ref:`HardwareTimer reference <lang-hardwaretimer>`.
+* :ref:`HardwareTimer <lang-hardwaretimer>`
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:`ASSERT() <language-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
+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 the following table to match up timer
-channels and Maple header pin numbers:
-
-.. _timers-pin-channel-map:
-
-.. csv-table::
- :header: Timer, Ch. 1 pin, Ch. 2 pin, Ch. 3 pin, Ch. 4 pin
-
- ``Timer1``, 6, 7, 8, --
- ``Timer2``, 2, 3, 1, 0
- ``Timer3``, 12, 11, 27, 28
- ``Timer4``, 5, 9, 14, 24
-
-**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.
-
-.. compound::
-
- **Jitter:** other interrupts (USB, Serial, SysTick, or other
- timers) can and will get called before or during the timer
- interrupt routines, causing pseudorandom delays and other
- frustrations.
-
- Disabling the 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>`).
-
- Disabling SysTick with ``systick_disable()`` helps as well.
- However, calling this function will break the ``micros()`` and
- ``millis()`` functions.
-
-**General:** working with timers and interrupts can be tricky and hard
-to debug; they are a somewhat "advanced" topic. Start simple, test
-with :ref:`ASSERT() <language-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 (e.g. USB,
-Serial, SysTick) if those other interrupts are important for your
-program.
-
-SysTick Peripheral
-------------------
-
-The SysTick peripheral allows another, simple way to perform periodic
-or delayed events. This separate timer does not conflict with any
-other peripherals, but the associated 1kHz interrupt can jitter the
-general purpose timer interrupts; this is clearly seen when running
-VGA code, where the timing jitters are transformed into visual jags in
-the image. The SysTick peripheral can be disabled by calling
-``systick_disable()``, and re-enabled using ``systick_resume()``.
-
-Code Examples
--------------
-
-LED blink
-^^^^^^^^^
-
-::
-
- #define LED_RATE 500000 // in microseconds; should give 0.5Hz toggles
-
- void handler_led(void);
-
- void setup()
- {
- // Set up the LED to blink
- pinMode(BOARD_LED_PIN, OUTPUT);
-
- // Setup Timer
- Timer2.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer2.setPeriod(LED_RATE); // in microseconds
- Timer2.setCompare1(1); // overflow might be small
- Timer2.attachCompare1Interrupt(handler_led);
- }
-
- void loop() {
- // Nothing! It's all in the interrupts
- }
-
- void handler_led(void) {
- toggleLED();
- }
-
-Racing Counters
-^^^^^^^^^^^^^^^
-
-::
-
- void handler_count1(void);
- void handler_count2(void);
-
- int count1 = 0;
- int count2 = 0;
-
- void setup()
- {
- // Set up BUT for input
- pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP);
-
- // Setup Counting Timers
- Timer3.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer3.pause();
- Timer4.pause();
- Timer3.setCount(0);
- Timer4.setCount(0);
- Timer3.setOverflow(30000);
- Timer4.setOverflow(30000);
- Timer3.setCompare1(1000); // somewhere in the middle
- Timer4.setCompare1(1000);
- Timer3.attachCompare1Interrupt(handler1);
- Timer4.attachCompare1Interrupt(handler2);
- Timer3.resume();
- Timer4.resume();
- }
-
- void loop() {
- // Display the running counts
- SerialUSB.print("Count 1: ");
- SerialUSB.print(count1);
- SerialUSB.print("\t\tCount 2: ");
- SerialUSB.println(count2);
-
- // Run... while BUT is held, pause Count2
- for(int i = 0; i<1000; i++) {
- if(digitalRead(BOARD_BUTTON_PIN)) {
- Timer4.pause();
- } else {
- Timer4.resume();
- }
- delay(1);
- }
- }
-
- void handler1(void) {
- count1++;
- }
- void handler2(void) {
- count2++;
- }
+the same program. Refer to your board's :ref:`Timer Pin Map
+<gpio-pin-maps>` to match up timer channels and pin numbers.
+
+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 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_resume() <libmaple-systick_resume>`.
+However, be aware that calling ``systick_disable()`` will stop the
+values coming from :ref:`lang-micros` and :ref:`lang-millis` from
+increasing.