diff options
| -rw-r--r-- | docs/source/lang/api/analogwrite.rst | 24 | ||||
| -rw-r--r-- | docs/source/lang/api/hardwaretimer.rst | 579 | ||||
| -rw-r--r-- | docs/source/timers.rst | 10 | ||||
| -rw-r--r-- | wirish/HardwareTimer.cpp | 217 | ||||
| -rw-r--r-- | wirish/HardwareTimer.h | 430 | ||||
| -rw-r--r-- | wirish/rules.mk | 1 | ||||
| -rw-r--r-- | wirish/wirish.h | 1 | 
7 files changed, 500 insertions, 762 deletions
diff --git a/docs/source/lang/api/analogwrite.rst b/docs/source/lang/api/analogwrite.rst index e789305..dd2192a 100644 --- a/docs/source/lang/api/analogwrite.rst +++ b/docs/source/lang/api/analogwrite.rst @@ -52,7 +52,7 @@ you much more precise control over the duty cycle of your PWM output.  If you're porting code from the Arduino and want a quick-and-dirty  fix, one solution is to :ref:`map <lang-map>` the argument to -analogWrite into the right range:: +analogWrite() into the right range::      // Arduino code:      analogWrite(pin, duty); @@ -71,8 +71,8 @@ that Timer's overflow to 255.  Subsequent calls to analogWrite()  should work as on the Arduino (with the same loss of precision).  Note, however, that that affects the overflow for the **entire  timer**, so other code relying on that timer (such as any -:ref:`interrupts <lang-attachinterrupt>` the timer controls) will -likely need to be modified as well. +:ref:`interrupts <lang-hardwaretimer-interrupts>` the timer controls) +will likely need to be modified as well.  Difference 2: You must use pinMode() to set up PWM  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -141,23 +141,27 @@ the steps are:  1. Figure out which :ref:`timer <lang-hardwaretimer>` controls PWM     output on your pin (\ :ref:`your board's Timer Pin Map -   <gpio-pin-maps>` is your friend here).  Let's say it's ``Timern``\ -   , where ``n`` is some number 1, 2, 3, or 4. +   <gpio-pin-maps>` is your friend here). -2. Call ``Timern.setPeriod(2041)``\ .  This will set the timer's -   period to approximately 2041 microseconds, which is a frequency of -   approximately 490 Hz. +2. Let's say it's timer ``n``, where ``n`` is some number.  You'll +   then need to put "``HardwareTimer timer(n);``" with your variables, +   as described in the :ref:`HardwareTimer +   <lang-hardwaretimer-getting-started>` reference. + +3. In your :ref:`lang-setup`, put "``timer.setPeriod(2041);``".  This +   will set the timer's period to approximately 2041 microseconds, +   which is a frequency of approximately 490 Hz.  Be aware that this will change the period for the **entire timer**\ ,  and will affect anything else in your program that depends on that  timer.  The important examples are :ref:`timer interrupts -<lang-hardwaretimer-attachinterrupt>` and :ref:`PWM +<lang-hardwaretimer-interrupts>` and :ref:`PWM  <timers-pwm-conflicts>`\ .  See Also  -------- --  :ref:`Maple PWM tutorial <pwm>` +- :ref:`pwm`  .. rubric:: Footnotes diff --git a/docs/source/lang/api/hardwaretimer.rst b/docs/source/lang/api/hardwaretimer.rst index 526beb6..09245f0 100644 --- a/docs/source/lang/api/hardwaretimer.rst +++ b/docs/source/lang/api/hardwaretimer.rst @@ -5,456 +5,341 @@  HardwareTimer  ============= -This class defines the public API for interfacing with the STM32's -built-in timer peripherals.  More information on these peripherals -(including code examples) is available in the :ref:`timers reference -<timers>`. +This page describes how to control the built-in timers.  It does not +describe how the timers work on your board.  For more information on +that, the :ref:`timers reference <timers>`. -.. FIXME [0.0.10] Updated HardwareTimer documentation, with deprecation +.. warning:: The timer interface is still taking shape, and is +   expected to change significantly between releases.  Because of +   that, the functionality described in this page shouldn't be +   considered stable. -.. warning:: This class has been deprecated.  It is not available in -   the current build. +   If you want a timer API that will be consistent between releases of +   the Maple IDE, your best bet for now is to use the low-level +   support in :ref:`libmaple-timer`. -Library Documentation ---------------------- +.. contents:: Contents +   :local: -HardwareTimer Class Reference -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. _lang-hardwaretimer-getting-started: -To interact with a particular timer, call one of the methods -documented below on one of the predefined ``HardwareTimer`` instances. -For example, to set the prescale factor on timer 1 to 5, call -``Timer1.setPrescaleFactor(5)``. +Getting Started +--------------- -.. TODO add tutorial-style examples +You'll first need to define a ``HardwareTimer`` variable, which you'll +use to control the timer.  Do this by putting the line +"``HardwareTimer timer(number);``" with your variables, where +``number`` is the timer's number. -.. cpp:class:: HardwareTimer +Here's an example (we'll fill in :ref:`setup() <lang-setup>` and +:ref:`loop() <lang-loop>` later):: -   Class for interacting with a timer.  There are four predefined -   instances available on the Maple: ``Timer1``, ``Timer2``, -   ``Timer3``, and ``Timer4``. +   // Use timer 1 +   HardwareTimer timer(1); -.. _lang-hardwaretimer-attachinterrupt: +   void setup() { +      // Your setup code +   } -.. cpp:function:: void HardwareTimer::attachInterrupt(int channel, voidFuncPtr handler) +   void loop() { +      // ... +   } -   Attach an interrupt handler to the given ``channel``.  This -   interrupt handler will be called when the timer's counter reaches -   the given channel :ref:`compare <lang-hardwaretimer-setcompare>` -   value. +Configuring the Prescaler and Overflow +-------------------------------------- -   ``handler`` should be a function which takes no arguments and has -   :ref:`void <lang-void>` value; i.e. it should have signature :: +After defining your ``timer`` variable, you'll probably want to +configure how fast your timer's counter changes (using the prescaler) +and when it gets reset to zero (using the overflow value).  You can do +that with the ``setPrescaleFactor()`` and ``setOverflow()`` functions. -       void handler(void); - -   You can later detach the interrupt using :ref:`detachInterrupt() -   <lang-hardwaretimer-detachinterrupt>`. - -   .. note:: The function (often called an *interrupt service -             routine*, or ISR) should attempt to return as quickly as -             possible.  :ref:`Blinking the LED <lang-toggleled>`, some -             logic, :ref:`PWM <pwm>` updates, and :ref:`Serial -             <lang-serial>` writes are fine; writing to -             :ref:`SerialUSB <lang-serialusb>` or :ref:`waiting -             <lang-waitforbuttonpress>` for user input can take a long -             time and prevent other interrupts from firing on time. - -             Tip: if you have a :ref:`delay() <lang-delay>` in your -             ISR, you're probably doing it wrong. - -.. cpp:function:: void HardwareTimer::attachCompare1Interrupt(voidFuncPtr handler) - -   Equivalent to :ref:`attachInterrupt -   <lang-hardwaretimer-attachinterrupt>`\ ``(1, handler)``. - -.. cpp:function:: void HardwareTimer::attachCompare2Interrupt(voidFuncPtr handler) - -   Equivalent to :ref:`attachInterrupt -   <lang-hardwaretimer-attachinterrupt>`\ ``(2, handler)``. - -.. cpp:function:: void HardwareTimer::attachCompare3Interrupt(voidFuncPtr handler) - -   Equivalent to :ref:`attachInterrupt -   <lang-hardwaretimer-attachinterrupt>`\ ``(3, handler)``. - -.. cpp:function:: void HardwareTimer::attachCompare4Interrupt(voidFuncPtr handler) - -   Equivalent to :ref:`attachInterrupt -   <lang-hardwaretimer-attachinterrupt>`\ ``(4, handler)``. - -.. _lang-hardwaretimer-setchannelmode: - -.. cpp:function:: void HardwareTimer::setChannelMode(int channel, TimerMode mode) - -   Set the given channel of this timer to the given :ref:`mode -   <lang-hardwaretimer-modes>`.  The parameter ``channel`` is one of -   1, 2, 3, and 4, and corresponds to the compare channel you would -   like to set.  Refer to your board's :ref:`master pin map -   <gpio-pin-maps>` to match up timer channels and pin numbers. - -.. cpp:function:: void HardwareTimer::setChannel1Mode(TimerMode mode) - -   Equivalent to :ref:`setChannelMode <lang-hardwaretimer-setchannelmode>`\ -   ``(1, mode)``. - -.. cpp:function:: void HardwareTimer::setChannel2Mode(TimerMode mode) - -   Equivalent to :ref:`setChannelMode <lang-hardwaretimer-setchannelmode>`\ -   ``(2, mode)``. - -.. cpp:function:: void HardwareTimer::setChannel3Mode(TimerMode mode) - -   Equivalent to :ref:`setChannelMode <lang-hardwaretimer-setchannelmode>`\ -   ``(3, mode)``. - -.. cpp:function:: void HardwareTimer::setChannel4Mode(TimerMode mode) - -   Equivalent to :ref:`setChannelMode <lang-hardwaretimer-setchannelmode>`\ -   ``(4, mode)``. - -.. _lang-hardwaretimer-getcompare: - -.. cpp:function:: uint16 HardwareTimer::getCompare(int channel) - -   Gets the compare value for the given ``channel``, from 1 to 4.  See -   :ref:`setCompare() <lang-hardwaretimer-setcompare>`. - -.. cpp:function:: uint16 HardwareTimer::getCompare1() - -   Equivalent to :ref:`getCompare <lang-hardwaretimer-getcompare>`\ -   ``(1, mode)``. - -.. cpp:function:: uint16 HardwareTimer::getCompare2() - -   Equivalent to :ref:`getCompare <lang-hardwaretimer-getcompare>`\ -   ``(2, mode)``. - -.. cpp:function:: uint16 HardwareTimer::getCompare3() - -   Equivalent to :ref:`getCompare <lang-hardwaretimer-getcompare>`\ -   ``(3, mode)``. - -.. cpp:function:: uint16 HardwareTimer::getCompare4() +.. _lang-hardwaretimer-setprescalefactor: -   Equivalent to :ref:`getCompare <lang-hardwaretimer-getcompare>`\ -   ``(4, mode)``. +.. doxygenfunction:: HardwareTimer::setPrescaleFactor +   :no-link: -.. _lang-hardwaretimer-setcompare: +.. _lang-hardwaretimer-setoverflow: -.. cpp:function:: void HardwareTimer::setCompare(int channel, uint16 compare) +.. doxygenfunction:: HardwareTimer::setOverflow +   :no-link: -   Sets the compare value for the given ``channel`` to ``compare``. -   If ``compare`` is greater than this timer's overflow value, it will -   be truncated to the overflow value.  The default compare value is -   65,535 (the largest unsigned 16-bit integer value). +For example:: -   When the counter reaches this value the interrupt for this channel -   will fire if the given ``channel`` :ref:`mode -   <lang-hardwaretimer-setchannelmode>` is ``TIMER_OUTPUTCOMPARE`` and -   an interrupt is :ref:`attached -   <lang-hardwaretimer-attachinterrupt>`. +   // Use timer 1 +   HardwareTimer timer(1); -   By default, this only changes 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. +   void setup() { +       timer.setPrescaleFactor(5); +       timer.setOverflow(255); +   } -.. cpp:function:: void HardwareTimer::setCompare1(uint16 compare) +   void loop() { +      // ... +   } -   Equivalent to :ref:`setCompare <lang-hardwaretimer-setcompare>`\ -   ``(1, compare)``. +You may also find the ``setPeriod()`` function useful: -.. cpp:function:: void HardwareTimer::setCompare2(uint16 compare) +.. _lang-hardwaretimer-setperiod: -   Equivalent to :ref:`setCompare <lang-hardwaretimer-setcompare>`\ -   ``(2, compare)``. +.. doxygenfunction:: HardwareTimer::setPeriod +   :no-link: -.. cpp:function:: void HardwareTimer::setCompare3(uint16 compare) +For example:: -   Equivalent to :ref:`setCompare <lang-hardwaretimer-setcompare>`\ -   ``(3, compare)``. +   // Use timer 1 +   HardwareTimer timer(1); -.. cpp:function:: void HardwareTimer::setCompare4(uint16 compare) +   void setup() { +       // Have the timer repeat every 20 milliseconds +       int microseconds_per_millisecond = 1000; +       timer.setPeriod(20 * microseconds_per_millisecond); +   } -   Equivalent to :ref:`setCompare <lang-hardwaretimer-setcompare>`\ -   ``(4, compare)``. +   void loop() { +      // ... +   } -.. cpp:function:: uint16 HardwareTimer::getCount() +.. _lang-hardwaretimer-interrupts: -   Gets the current timer count.  Due to function call overhead, the -   return value will be increasingly accurate with smaller prescale -   values.  Also see :ref:`setCount() <lang-hardwaretimer-setcount>`. +Using Timer Interrupts +---------------------- -.. _lang-hardwaretimer-setcount: +.. TODO [0.2.0] Improve the interrupts section, here or in timers.rst -.. cpp:function:: void HardwareTimer::setCount(uint16 val) +In order to use timer interrupts, we recommend the following sequence: -    Set the timer's current count to ``val``. +* Pause the timer. +* Configure the prescaler and overflow. +* Pick a timer channel to handle the interrupt and set the channel's +  :ref:`mode <lang-hardwaretimer-timermode>` to ``TIMER_OUTPUT_COMPARE``. +* Set the channel compare value appropriately (this controls what counter value, +  from 0 to overflow - 1).  If you just want to make the interrupt fire once +  every time the timer overflows, and you don't care what the timer count is, +  the channel compare value can just be 1. +* Attach an interrupt handler to the channel. +* Refresh the timer. +* Resume the timer. -    Note that there is some function call overhead associated with -    calling this method, so using it is not a robust way to get -    multiple timers to share a count value. +Here are two complete examples. -    If ``val`` exceeds the timer's :ref:`overflow value -    <lang-hardwaretimer-getoverflow>`, it is truncated to the overflow -    value. +**LED blink**: This example blinks the built-in LED without doing +anything in ``loop()``. :: +    #define LED_RATE 500000    // in microseconds; should give 0.5Hz toggles -.. _lang-hardwaretimer-detachinterrupt: - -.. cpp:function:: void HardwareTimer::detachInterrupt(int channel) +    // We'll use timer 2 +    HardwareTimer timer(2); -   Remove the interrupt handler attached to the given ``channel``, if -   any.  The handler will no longer be called by this timer. +    void setup() { +        // Set up the LED to blink +        pinMode(BOARD_LED_PIN, OUTPUT); -.. cpp:function:: void HardwareTimer::detachCompare1Interrupt() +        // Pause the timer while we're configuring it +        timer.pause(); -   Equivalent to :ref:`detachInterrupt -   <lang-hardwaretimer-detachinterrupt>`\ ``(1)``. +        // Set up period +        timer.setPeriod(LED_RATE); // in microseconds -.. cpp:function:: void HardwareTimer::detachCompare2Interrupt() +        // Set up an interrupt on channel 1 +        timer.setChannel1Mode(TIMER_OUTPUT_COMPARE); +        timer.setCompare(TIMER_CH1, 1);  // Interrupt 1 count after each update +        timer.attachCompare1Interrupt(handler_led); -   Equivalent to :ref:`detachInterrupt -   <lang-hardwaretimer-detachinterrupt>`\ ``(2)``. +        // Refresh the timer's count, prescale, and overflow +        timer.refresh(); -.. cpp:function:: void HardwareTimer::detachCompare3Interrupt() +        // Start the timer counting +        timer.resume(); +    } -   Equivalent to :ref:`detachInterrupt -   <lang-hardwaretimer-detachinterrupt>`\ ``(3)``. +    void loop() { +        // Nothing! It's all in the handler_led() interrupt: +    } -.. cpp:function:: void HardwareTimer::detachCompare4Interrupt() +    void handler_led(void) { +        toggleLED(); +    } -   Equivalent to :ref:`detachInterrupt -   <lang-hardwaretimer-detachinterrupt>`\ ``(4)``. +**Racing Counters**: This example shows how to use multiple timers at +the same time. :: -.. _lang-hardwaretimer-generateupdate: +    int count3 = 0; +    int count4 = 0; -.. cpp:function:: void HardwareTimer::generateUpdate() +    // We'll use timers 3 and 4 +    HardwareTimer timer3(3); +    HardwareTimer timer4(4); -   Re-initializes the counter (to 0 in upcounting mode, which is the -   default), and generates an update of the prescale and overflow -   registers. +    void setup() { +        // Set up the button for input +        pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP); -.. _lang-hardwaretimer-getoverflow: +        // Set up timers to add 1 to their counts each time +        // their interrupts fire. +        timer3.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE); +        timer4.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE); +        timer3.pause(); +        timer4.pause(); +        timer3.setCount(0); +        timer4.setCount(0); +        timer3.setOverflow(30000); +        timer4.setOverflow(30000); +        timer3.setCompare(TIMER_CH1, 1000);   // somewhere in the middle +        timer4.setCompare(TIMER_CH1, 1000); +        timer3.attachCompare1Interrupt(handler3); +        timer4.attachCompare1Interrupt(handler4); +        timer3.refresh(); +        timer4.refresh(); +        timer3.resume(); +        timer4.resume(); +    } -.. cpp:function:: uint16 HardwareTimer::getOverflow() +    void loop() { +        // Display the running counts +        SerialUSB.print("Count 3: "); +        SerialUSB.print(count3); +        SerialUSB.print("\t\tCount 4: "); +        SerialUSB.println(count4); + +        // While the button is held down, pause timer 4 +        for (int i = 0; i < 1000; i++) { +            if (digitalRead(BOARD_BUTTON_PIN)) { +                timer4.pause(); +            } else { +                timer4.resume(); +            } +            delay(1); +        } +    } -   Gets the timer's overflow value.  See :ref:`setOverflow() -   <lang-hardwaretimer-setoverflow>`. +    void handler3(void) { +        count3++; +    } -.. _lang-hardwaretimer-setoverflow: +    void handler4(void) { +        count4++; +    } -.. cpp:function:: void HardwareTimer::setOverflow(uint16 val) +``HardwareTimer`` Class Reference +--------------------------------- -    Sets the timer overflow (or "reload") value to ``val``. +This section gives a full listing of the capabilities of a +``HardwareTimer``. -    When the timer's counter reaches this, value it resets to -    zero. Its default value is 65535 (the largest unsigned 16-bit -    integer); setting the overflow to anything lower will cause -    interrupts to be called more frequently (see :ref:`setPeriod() -    <lang-hardwaretimer-setperiod>` function for a shortcut). +.. doxygenclass:: HardwareTimer +   :members: HardwareTimer, pause, resume, getPrescaleFactor, setPrescaleFactor, getOverflow, setOverflow, getCount, setCount, setPeriod, setMode, getCompare, setCompare, attachInterrupt, detachInterrupt, refresh -    After the next :ref:`timer update -    <lang-hardwaretimer-generateupdate>`, this number will be the -    maximum value for the timer's channel compare values. +.. _lang-hardwaretimer-timermode: -.. _lang-hardwaretimer-pause: +.. doxygenenum:: timer_mode -.. cpp:function:: void HardwareTimer::pause() +Deprecated Functionality +------------------------ -   Stop the timer's counter, without affecting its configuration. +The following functionality exists for now, but it has been +deprecated, and will be removed in a future Maple IDE release.  You +shouldn't use it in new programs, and you should change any of your +programs which do use them to use the up-to-date features described +above. -   The timer will no longer count or fire interrupts after this -   function is called, until it is resumed.  This function is useful -   during timer setup periods, in order to prevent interrupts from -   firing before the timer is fully configured. +The ``TimerMode`` type from previous releases has been renamed +``timer_mode``.  The mode ``TIMER_OUTPUTCOMPARE`` is still present, +but will be removed in a future release.  Use ``TIMER_OUTPUT_COMPARE`` +instead. -   Note that there is some function call overhead associated with this -   method, so using it in concert with :ref:`resume() -   <lang-hardwaretimer-resume>` is not a robust way to align multiple -   timers to the same count value. +.. cpp:function:: void HardwareTimer::attachCompare1Interrupt(voidFuncPtr handler) -.. _lang-hardwaretimer-setperiod: +   Use ``attachInterrupt(1, handler)`` instead. -.. cpp:function:: uint16 HardwareTimer::setPeriod(uint32 microseconds) +.. cpp:function:: void HardwareTimer::attachCompare2Interrupt(voidFuncPtr handler) -   Configure the :ref:`prescaler -   <lang-hardwaretimer-getprescalefactor>` and :ref:`overflow -   <lang-hardwaretimer-getoverflow>` values to generate a timer reload -   with a period as close to the given number of ``microseconds`` as -   possible. +   Use ``attachInterrupt(2, handler)`` instead. -   The return value is the new overflow value, which may be used to -   set channel compare values.  However, if a clock that fires an -   interrupt every given number of microseconds is all that is -   desired, and the relative "phases" are unimportant, channel compare -   values may all be set to 1. +.. cpp:function:: void HardwareTimer::attachCompare3Interrupt(voidFuncPtr handler) -.. _lang-hardwaretimer-getprescalefactor: +   Use ``attachInterrupt(3, handler)`` instead. -.. cpp:function:: uint16 HardwareTimer::getPrescaleFactor() +.. cpp:function:: void HardwareTimer::attachCompare4Interrupt(voidFuncPtr handler) -    Returns the timer's prescale factor.  See -    :ref:`setPrescaleFactor() <lang-hardwaretimer-setprescalefactor>`. +   Use ``attachInterrupt(4, handler)`` instead. -.. _lang-hardwaretimer-setprescalefactor: +.. _lang-hardwaretimer-setchannelmode: -.. cpp:function:: void HardwareTimer::setPrescaleFactor(uint16 factor) +.. cpp:function:: void HardwareTimer::setChannelMode(int channel, timer_mode mode) -    Set the timer's prescale factor to ``factor``. +   Use ``setMode(channel, mode)`` instead. -    The prescaler acts as a clock divider to slow down the rate at -    which the counter increments. +.. cpp:function:: void HardwareTimer::setChannel1Mode(timer_mode mode) -    For example, the system clock rate is 72MHz, so the counter will -    reach 65535 in (13.89 nanoseconds) × (65535 counts) = (910.22 -    microseconds), or about a thousand times a second. If the -    prescaler equals 1098, then the clock rate is effectively 72MHz / -    1098 = 65.56KHz, and the counter will reach 65536 in (15.25 -    microseconds) × (65536 counts) = (0.999 seconds), or about once -    per second. +   Use ``setMode(1, mode)`` instead. -    The :ref:`setPeriod() <lang-hardwaretimer-setperiod>` method may -    also be used as a convenient alternative. +.. cpp:function:: void HardwareTimer::setChannel2Mode(timer_mode mode) -.. _lang-hardwaretimer-resume: +   Use ``setMode(2, mode)`` instead. -.. cpp:function:: void HardwareTimer::resume() +.. cpp:function:: void HardwareTimer::setChannel3Mode(timer_mode mode) -    Resume a paused timer, without affecting its configuration. +   Use ``setMode(3, mode)`` instead. -    The timer will resume counting and firing interrupts as -    appropriate. +.. cpp:function:: void HardwareTimer::setChannel4Mode(timer_mode mode) -    Note that there is some function call overhead associated with -    using this method, so using it in concert with :ref:`pause() -    <lang-hardwaretimer-pause>` is not a robust way to align multiple -    timers to the same count value. +   Use ``setMode(4, mode)`` instead. -.. cpp:function:: timer_dev_num HardwareTimer::getTimerNum() +.. cpp:function:: uint16 HardwareTimer::getCompare1() -   Returns the :ref:`timer device number -   <lang-hardwaretimer-timer-dev-num>` associated with the timer.  For -   example, ``Timer1.getTimerNum()`` would return ``TIMER1``. +   Use ``getCompare(1, mode)`` instead. -   In most cases, you should not need to use this function.  If you do -   use it, be careful; the constant ``TIMER1`` is *not equal* to the -   number 1; similarly, ``TIMER2`` is *not* the number 2, etc.  Be -   sure to refer to the timer device number by name. +.. cpp:function:: uint16 HardwareTimer::getCompare2() -.. _lang-hardwaretimer-modes: +   Use ``getCompare(2, mode)`` instead. -Timer Modes -^^^^^^^^^^^ -.. doxygenenum:: TimerMode +.. cpp:function:: uint16 HardwareTimer::getCompare3() -.. _lang-hardwaretimer-timer-dev-num: +   Use ``getCompare(3, mode)`` instead. -Timer Device Numbers -^^^^^^^^^^^^^^^^^^^^ +.. cpp:function:: uint16 HardwareTimer::getCompare4() -These provide a lower-level interface for interacting with timers. -They are mostly useful in context with the :ref:`getTimer() -<lang-hardwaretimer-gettimer>` function.  **Be careful** when using -these not to confuse e.g. ``TIMER1`` with the number 1; they are -different. +   Use ``getCompare(4, mode)`` instead. -.. doxygenenum:: timer_dev_num +.. cpp:function:: void HardwareTimer::setCompare1(uint16 compare) -.. _lang-hardwaretimer-convenience: +   Use ``setCompare(1, compare)`` instead. -.. _lang-hardwaretimer-gettimer: +.. cpp:function:: void HardwareTimer::setCompare2(uint16 compare) -Other Functions -^^^^^^^^^^^^^^^ -.. doxygenfunction:: getTimer +   Use ``setCompare(2, compare)`` instead. -Examples -^^^^^^^^ +.. cpp:function:: void HardwareTimer::setCompare3(uint16 compare) -**LED blink**:: +   Use ``setCompare(3, compare)`` instead. -    #define LED_RATE 500000    // in microseconds; should give 0.5Hz toggles +.. cpp:function:: void HardwareTimer::setCompare4(uint16 compare) -    void handler_led(void); +   Use ``setCompare(4, compare)`` instead. -    void setup() -    { -        // Set up the LED to blink -        pinMode(BOARD_LED_PIN, OUTPUT); +.. cpp:function:: void HardwareTimer::detachCompare1Interrupt() -        // Setup Timer -        Timer2.setChannel1Mode(TIMER_OUTPUTCOMPARE); -        Timer2.setPeriod(LED_RATE); // in microseconds -        Timer2.setCompare1(1);      // overflow might be small -        Timer2.attachCompare1Interrupt(handler_led); -    } +   Use ``detachInterrupt(1)`` instead. -    void loop() { -        // Nothing! It's all in the interrupts -    } +.. cpp:function:: void HardwareTimer::detachCompare2Interrupt() -    void handler_led(void) { -        toggleLED(); -    } +   Use ``detachInterrupt(2)`` instead. -**Racing Counters**:: +.. cpp:function:: void HardwareTimer::detachCompare3Interrupt() -    void handler_count1(void); -    void handler_count2(void); +   Use ``detachInterrupt(3)`` instead. -    int count1 = 0; -    int count2 = 0; +.. cpp:function:: void HardwareTimer::detachCompare4Interrupt() -    void setup() -    { -        // Set up BUT for input -        pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP); +   Use ``detachInterrupt(4)`` instead. -        // 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(); -    } +.. cpp:function:: void HardwareTimer::generateUpdate() -    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); -        } -    } +   Use ``refresh()`` instead. -    void handler1(void) { -        count1++; -    } -    void handler2(void) { -        count2++; -    } +In previous releases, to interact with a particular timers, you would +use one of the predefined ``HardwareTimer`` instances ``Timer1``, +``Timer2``, ``Timer3``, and ``Timer4``.  These are still available for +now, but they are also deprecated, and will be removed in a future +release.  As detailed in :ref:`lang-hardwaretimer-getting-started`, +you should define your own ``HardwareTimer`` variables. diff --git a/docs/source/timers.rst b/docs/source/timers.rst index cb30081..9163e69 100644 --- a/docs/source/timers.rst +++ b/docs/source/timers.rst @@ -45,6 +45,16 @@ 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. +  Function Reference  ------------------ diff --git a/wirish/HardwareTimer.cpp b/wirish/HardwareTimer.cpp index 04d1c76..d0e32c3 100644 --- a/wirish/HardwareTimer.cpp +++ b/wirish/HardwareTimer.cpp @@ -22,204 +22,125 @@   * THE SOFTWARE.   *****************************************************************************/ -/* - * wirish timer class to manage the four 16-bit timer peripherals - */ - -#include "wirish.h"  #include "HardwareTimer.h" +#include "boards.h"             // for CYCLES_PER_MICROSECOND +#include "wirish_math.h" -HardwareTimer::HardwareTimer(timer_dev_num timerNum) { -    ASSERT(timerNum != TIMER_INVALID); +// TODO [0.1.0] Remove deprecated pieces -    this->timerNum = timerNum; -} +#ifdef STM32_MEDIUM_DENSITY +#define NR_TIMERS 4 +#elif defined(STM32_HIGH_DENSITY) +#define NR_TIMERS 8 +#else +#error "Unsupported density" +#endif -void HardwareTimer::resume(void) { -    timer_resume(this->timerNum); +#define MAX_RELOAD ((1 << 16) - 1) + +HardwareTimer::HardwareTimer(uint8 timerNum) { +    if (timerNum > NR_TIMERS) { +        ASSERT(0); +    } +    timer_dev *devs[] = { +        TIMER1, +        TIMER2, +        TIMER3, +        TIMER4, +#ifdef STM32_HIGH_DENSITY +        TIMER5, +        TIMER6, +        TIMER7, +        TIMER8, +#endif +    }; +    this->dev = devs[timerNum - 1];  }  void HardwareTimer::pause(void) { -    timer_pause(this->timerNum); +    timer_pause(this->dev);  } -uint16 HardwareTimer::getPrescaleFactor(void) { -    return timer_get_prescaler(this->timerNum) + 1; +void HardwareTimer::resume(void) { +    timer_resume(this->dev); +} + +uint32 HardwareTimer::getPrescaleFactor(void) { +    return timer_get_prescaler(this->dev) + 1;  } -void HardwareTimer::setPrescaleFactor(uint16 factor) { -    // The prescaler register is zero-indexed -    timer_set_prescaler(this->timerNum, factor-1); +void HardwareTimer::setPrescaleFactor(uint32 factor) { +    timer_set_prescaler(this->dev, (uint16)(factor - 1));  }  uint16 HardwareTimer::getOverflow() { -    return timer_get_reload(this->timerNum); +    return timer_get_reload(this->dev);  }  void HardwareTimer::setOverflow(uint16 val) { -    timer_set_reload(this->timerNum, val); +    timer_set_reload(this->dev, val);  }  uint16 HardwareTimer::getCount(void) { -    return timer_get_count(this->timerNum); +    return timer_get_count(this->dev);  }  void HardwareTimer::setCount(uint16 val) {      uint16 ovf = this->getOverflow(); -    timer_set_count(this->timerNum, min(val, ovf)); +    timer_set_count(this->dev, min(val, ovf));  } +// FIXME [0.0.10 beta] test!  uint16 HardwareTimer::setPeriod(uint32 microseconds) {      // Not the best way to handle this edge case? -    if(!microseconds) { -        setPrescaleFactor(1); -        setOverflow(1); +    if (!microseconds) { +        this->setPrescaleFactor(1); +        this->setOverflow(1);          return this->getOverflow();      } -    uint32 cycles = microseconds * CYCLES_PER_MICROSECOND; - -    // With a prescale factor of 1, there are CYCLES_PER_MICROSECOND -    // counts/ms -    uint16 ps = (uint16)((cycles >> 16) + 1); -    setPrescaleFactor(ps); - -    // Finally, this overflow will always be less than 65536 -    setOverflow((cycles/ps) - 1); - -    return this->getOverflow(); -} -void HardwareTimer::setChannelMode(int channel, TimerMode mode) { -    timer_set_mode(this->timerNum, channel, mode); +    uint32 period_cyc = microseconds * CYCLES_PER_MICROSECOND; +    uint16 prescaler = (uint16)(period_cyc / MAX_RELOAD); +    uint16 overflow = (uint16)round(period_cyc / prescaler); +    this->setPrescaleFactor(prescaler); +    this->setOverflow(overflow); +    return overflow;  } -void HardwareTimer::setChannel1Mode(TimerMode mode) { -    this->setChannelMode(1, mode); -} - -void HardwareTimer::setChannel2Mode(TimerMode mode) { -    this->setChannelMode(2, mode); -} - -void HardwareTimer::setChannel3Mode(TimerMode mode) { -    this->setChannelMode(3, mode); -} - -void HardwareTimer::setChannel4Mode(TimerMode mode) { -    this->setChannelMode(4, mode); +void HardwareTimer::setMode(int channel, timer_mode mode) { +    timer_set_mode(this->dev, (uint8)channel, (timer_mode)mode);  }  uint16 HardwareTimer::getCompare(int channel) { -    return timer_get_compare_value(this->timerNum, channel); -} - -uint16 HardwareTimer::getCompare1() { -    return this->getCompare(1); -} - -uint16 HardwareTimer::getCompare2() { -    return this->getCompare(2); -} - -uint16 HardwareTimer::getCompare3() { -    return this->getCompare(3); -} - -uint16 HardwareTimer::getCompare4() { -    return this->getCompare(4); +    return timer_get_compare(this->dev, (uint8)channel);  }  void HardwareTimer::setCompare(int channel, uint16 val) {      uint16 ovf = this->getOverflow(); -    timer_set_compare_value(this->timerNum, channel, min(val, ovf)); -} - -void HardwareTimer::setCompare1(uint16 val) { -    this->setCompare(1, val); -} - -void HardwareTimer::setCompare2(uint16 val) { -    this->setCompare(2, val); -} - -void HardwareTimer::setCompare3(uint16 val) { -    this->setCompare(3, val); -} - -void HardwareTimer::setCompare4(uint16 val) { -    this->setCompare(4, val); +    timer_set_compare(this->dev, (uint8)channel, min(val, ovf));  }  void HardwareTimer::attachInterrupt(int channel, voidFuncPtr handler) { -    timer_attach_interrupt(this->timerNum, channel, handler); -} - -void HardwareTimer::attachCompare1Interrupt(voidFuncPtr handler) { -    this->attachInterrupt(1, handler); -} - -void HardwareTimer::attachCompare2Interrupt(voidFuncPtr handler) { -    this->attachInterrupt(2, handler); -} - -void HardwareTimer::attachCompare3Interrupt(voidFuncPtr handler) { -    this->attachInterrupt(3, handler); -} - -void HardwareTimer::attachCompare4Interrupt(voidFuncPtr handler) { -    this->attachInterrupt(4, handler); +    timer_attach_interrupt(this->dev, (uint8)channel, handler);  }  void HardwareTimer::detachInterrupt(int channel) { -    timer_detach_interrupt(this->timerNum, channel); -} - -void HardwareTimer::detachCompare1Interrupt(void) { -    this->detachInterrupt(1); -} - -void HardwareTimer::detachCompare2Interrupt(void) { -    this->detachInterrupt(2); -} - -void HardwareTimer::detachCompare3Interrupt(void) { -    this->detachInterrupt(3); +    timer_detach_interrupt(this->dev, (uint8)channel);  } -void HardwareTimer::detachCompare4Interrupt(void) { -    this->detachInterrupt(4); +void HardwareTimer::refresh(void) { +    timer_generate_update(this->dev);  } -void HardwareTimer::generateUpdate(void) { -    timer_generate_update(this->timerNum); -} +/* -- Deprecated predefined instances -------------------------------------- */ -HardwareTimer Timer1(TIMER1); -HardwareTimer Timer2(TIMER2); -HardwareTimer Timer3(TIMER3); -HardwareTimer Timer4(TIMER4); +HardwareTimer Timer1(1); +HardwareTimer Timer2(2); +HardwareTimer Timer3(3); +HardwareTimer Timer4(4);  #ifdef STM32_HIGH_DENSITY -HardwareTimer Timer5(TIMER5);    // High-density devices only -HardwareTimer Timer8(TIMER8);    // High-density devices only +HardwareTimer Timer5(5); +HardwareTimer Timer6(6); +HardwareTimer Timer7(7); +HardwareTimer Timer8(8);  #endif - -HardwareTimer* getTimer(timer_dev_num timerNum) { -    switch (timerNum) { -    case TIMER1: -        return &Timer1; -    case TIMER2: -        return &Timer2; -    case TIMER3: -        return &Timer3; -    case TIMER4: -        return &Timer4; -#ifdef STM32_HIGH_DENSITY -    case TIMER5: -        return &Timer5; -    case TIMER8: -        return &Timer8; -#endif -    default: -        return 0; -    } -} diff --git a/wirish/HardwareTimer.h b/wirish/HardwareTimer.h index 4030adc..fd8ca9a 100644 --- a/wirish/HardwareTimer.h +++ b/wirish/HardwareTimer.h @@ -23,66 +23,45 @@   *****************************************************************************/  /** - *  @brief wirish timer class to manage the four 16-bit timer peripherals + *  @brief Wirish timer class.   */  #ifndef _HARDWARETIMER_H_  #define _HARDWARETIMER_H_ -#include "timers.h" +// TODO [0.1.0] Remove deprecated pieces, pick a better API + +#include "timer.h" + +/** Timer mode. */ +typedef timer_mode TimerMode; + +/** @brief Deprecated; use TIMER_OUTPUT_COMPARE instead. */ +#define TIMER_OUTPUTCOMPARE TIMER_OUTPUT_COMPARE  /** - * Interface to one of the 16-bit timer peripherals. - * - * User code should not instantiate this class directly; instead, use - * one of the predefined Timer<n> instances (Timer1, Timer2, etc.). - * - * HardwareTimer instances can be configured to generate periodic or - * delayed events with minimal work done by the microcontroller.  Each - * timer maintains a single 16-bit count that can be configured with a - * prescaler and overflow value. - * - * By default, a timer's counter is incremented once per clock cycle. - * The prescaler acts as a divider of the 72MHz Maple system clock; - * without prescaling, the timer's count would reach 65535 (2**16-1) - * and roll over over 1000 times per second. - * - * The overflow value is the maximum value the counter will reach.  It - * defaults to 65535; smaller values will cause the counter to reset - * more frequently. + * @brief Interface to one of the 16-bit timer peripherals.   */  class HardwareTimer { - private: -    timer_dev_num timerNum; - - public: -    HardwareTimer(timer_dev_num timer_num); +private: +    timer_dev *dev; +public:      /** -     * Return this timer's device number. For example, -     *  Timer1.getTimerNum() == TIMER1 +     * @brief Construct a new HardwareTimer instance. +     * @param timerNum number of the timer to control.       */ -    timer_dev_num getTimerNum() { return timerNum; } +    HardwareTimer(uint8 timerNum);      /** -     * Stop the counter, without affecting its configuration. -     * -     * The timer will no longer count or fire interrupts after this -     * function is called, until it is resumed.  This function is -     * useful during timer setup periods, in order to prevent -     * interrupts from firing before the timer is fully configured. -     * -     * Note that there is some function call overhead associated with -     * this method, so using it in concert with -     * HardwareTimer::resume() is not a robust way to align multiple -     * timers to the same count value. +     * @brief Stop the counter, without affecting its configuration.       *       * @see HardwareTimer::resume()       */      void pause(void);      /** -     * Resume a paused timer, without affecting its configuration. +     * @brief Resume a paused timer, without affecting its configuration.       *       * The timer will resume counting and firing interrupts as       * appropriate. @@ -97,66 +76,51 @@ class HardwareTimer {      void resume(void);      /** -     * Returns the timer's prescale factor. +     * @brief Get the timer's prescale factor. +     * @return Timer prescaler, from 1 to 65,536.       * @see HardwareTimer::setPrescaleFactor()       */ -    uint16 getPrescaleFactor(); +    uint32 getPrescaleFactor();      /** -     * Set the timer's prescale factor. +     * @brief Set the timer's prescale factor.       * -     * The prescaler acts as a clock divider to slow down the rate at -     * which the counter increments. +     * The new value won't take effect until the next time the counter +     * overflows.  You can force the counter to reset using +     * HardwareTimer::refresh().       * -     * For example, the system clock rate is 72MHz, so the counter -     * will reach 65535 in (13.89 nanoseconds) * (65535 counts) = -     * (910.22 microseconds), or about a thousand times a second. If -     * the prescaler equals 1098, then the clock rate is effectively -     * 65.56KHz, and the counter will reach 65536 in (15.25 -     * microseconds) * (65536 counts) = (0.999 seconds), or about once -     * per second. -     * -     * The HardwareTimer::setPeriod() method may also be used as a -     * convenient alternative. -     * -     * @param factor The new prescale value to set. -     * @see HardwareTimer::setPeriod() +     * @param factor The new prescale value to set, from 1 to 65,536. +     * @see HardwareTimer::refresh()       */ -    void setPrescaleFactor(uint16 factor); +    void setPrescaleFactor(uint32 factor);      /** -     * Gets the timer overflow value. +     * @brief Get the timer overflow value.       * @see HardwareTimer::setOverflow()       */      uint16 getOverflow();      /** -     * Sets the timer overflow (or "reload") value. +     * @brief Set the timer overflow (or "reload") value.       * -     * When the timer's counter reaches this, value it resets to -     * zero. Its default value is 65535 (the largest unsigned 16-bit -     * integer); setting the overflow to anything lower will cause -     * interrupts to be called more frequently (see the setPeriod() -     * function below for a shortcut). This number sets the maximum -     * value for the channel compare values. +     * The new value won't take effect until the next time the counter +     * overflows.  You can force the counter to reset using +     * HardwareTimer::refresh().       *       * @param val The new overflow value to set +     * @see HardwareTimer::refresh()       */      void setOverflow(uint16 val);      /** -     * Retrieve the current timer count. +     * @brief Get the current timer count.       *       * @return The timer's current count value       */      uint16 getCount(void);      /** -     * Set the current timer count. -     * -     * Note that there is some function call overhead associated with -     * calling this method, so using it is not a robust way to get -     * multiple timers to share a count value. +     * @brief Set the current timer count.       *       * @param val The new count value to set.  If this value exceeds       *            the timer's overflow value, it is truncated to the @@ -165,143 +129,50 @@ class HardwareTimer {      void setCount(uint16 val);      /** -     * Configure the prescaler and overflow values to generate a timer +     * @brief Set the timer's period in microseconds. +     * +     * Configures the prescaler and overflow values to generate a timer       * reload with a period as close to the given number of       * microseconds as possible.       * -     * The return value is the overflow, which may be used to set -     * channel compare values.  However, if a clock that fires an -     * interrupt every given number of microseconds is all that is -     * desired, and the relative "phases" are unimportant, channel -     * compare values may all be set to 1. -     * -     * @param microseconds the desired period of the timer. -     * @return the overflow value (and thus, the largest value that can be -     *         set as a compare). +     * @param microseconds The desired period of the timer.  This must be +     *                     greater than zero. +     * @return The new overflow value.       */      uint16 setPeriod(uint32 microseconds);      /** -     * Set the given channel of this timer to the given mode. -     * +     * @brief Configure a timer channel's mode.       * @param channel Timer channel, from 1 to 4       * @param mode Mode to set       */ -    void setChannelMode(int channel, TimerMode mode); - -    /** -     * Set channel 1 of this timer to the given mode. -     * -     * Note: Timer1.setChannel1Mode(TIMER_PWM) may not work as -     * expected; if you want PWM functionality on a channel make sure -     * you don't set it to something else! -     * -     * @see TimerMode -     */ -    void setChannel1Mode(TimerMode mode); - -    /** -     * Set channel 2 of this timer to the given mode. -     * @see TimerMode -     */ -    void setChannel2Mode(TimerMode mode); - -    /** -     * Set channel 3 of this timer to the given mode. -     * @see TimerMode -     */ -    void setChannel3Mode(TimerMode mode); - -    /** -     * Set channel 4 of this timer to the given mode. -     * @see TimerMode -     */ -    void setChannel4Mode(TimerMode mode); +    void setMode(int channel, timer_mode mode);      /** -     * Gets the compare value for the given channel. +     * @brief Get the compare value for the given channel.       * @see HardwareTimer::setCompare()       */      uint16 getCompare(int channel); -    /** Equivalent to getCompare(1) */ -    uint16 getCompare1(); - -    /** Equivalent to getCompare(2) */ -    uint16 getCompare2(); - -    /** Equivalent to getCompare(3) */ -    uint16 getCompare3(); - -    /** Equivalent to getCompare(4) */ -    uint16 getCompare4(); -      /** -     * Sets the compare value for the given channel. -     * -     * When the counter reaches this value the interrupt for this -     * channel will fire if the channel mode is TIMER_OUTPUTCOMPARE -     * and an interrupt is attached. -     * -     * By default, this only changes 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. +     * @brief Set the compare value for the given channel.       *       * @param channel the channel whose compare to set, from 1 to 4.       * @param compare The compare value to set.  If greater than this       *                timer's overflow value, it will be truncated to       *                the overflow value.       * -     * @see TimerMode -     * @see HardwareTimer::setChannelMode() +     * @see timer_mode +     * @see HardwareTimer::setMode()       * @see HardwareTimer::attachInterrupt()       */      void setCompare(int channel, uint16 compare);      /** -     * Equivalent to setCompare(1, compare). -     */ -    void setCompare1(uint16 compare); - -    /** -     * Equivalent to setCompare(2, compare). -     */ -    void setCompare2(uint16 compare); - -    /** -     * Equivalent to setCompare(3, compare). -     */ -    void setCompare3(uint16 compare); - -    /** -     * Equivalent to setCompare(4, compare). -     */ -    void setCompare4(uint16 compare); - -    /** -     * Attach an interrupt handler to the given channel.  This -     * interrupt handler will be called when the timer's counter -     * reaches the given channel compare value. -     * -     * The argument should be a function which takes no arguments and -     * has no return value; i.e. it should have signature +     * @brief Attach an interrupt handler to the given channel.       * -     *     void (*handler)(void); -     * -     * Note: The function (often called an interrupt service routine, -     * or ISR) should attempt to return as quickly as possible. -     * Blinking the LED, some logic, PWM updates, and Serial writes -     * are fine; writing to SerialUSB or waiting for user input can -     * take a long time and other compare interrupts won't fire. Tip: -     * if you have a delay() in your interrupt routine, you're probably -     * doing it wrong. +     * This interrupt handler will be called when the timer's counter +     * reaches the given channel compare value.       *       * @param channel the channel to attach the ISR to, from 1 to 4.       * @param handler The ISR to attach to the given channel. @@ -310,32 +181,10 @@ class HardwareTimer {      void attachInterrupt(int channel, voidFuncPtr handler);      /** -     * Equivalent to attachCompareInterrupt(1, handler). -     * @see HardwareTimer::attachCompareInterrupt() -     */ -    void attachCompare1Interrupt(voidFuncPtr handler); - -    /** -     * Equivalent to attachCompareInterrupt(2, handler). -     * @see HardwareTimer::attachCompareInterrupt() -     */ -    void attachCompare2Interrupt(voidFuncPtr handler); - -    /** -     * Equivalent to attachCompareInterrupt(3, handler). -     * @see HardwareTimer::attachCompareInterrupt() -     */ -    void attachCompare3Interrupt(voidFuncPtr handler); - -    /** -     * Equivalent to attachCompareInterrupt(4, handler). -     * @see HardwareTimer::attachCompareInterrupt() -     */ -    void attachCompare4Interrupt(voidFuncPtr handler); - -    /** -     * Remove the interrupt handler attached to the given channel, if -     * any.  The handler will no longer be called by this timer. +     * @brief Remove the interrupt handler attached to the given +     *        channel, if any. +     * +     * The handler will no longer be called by this timer.       *       * @param channel the channel whose interrupt to detach, from 1 to 4.       * @see HardwareTimer::attachInterrupt() @@ -343,71 +192,138 @@ class HardwareTimer {      void detachInterrupt(int channel);      /** -     * Equivalent to detachInterrupt(1). -     * @see HardwareTimer::detachInterrupt() +     * @brief Reset the counter, and update the prescaler and overflow +     *        values. +     * +     * This will reset the counter to 0 in upcounting mode (the +     * default).  It will also update the timer's prescaler and +     * overflow, if you have set them up to be changed using +     * HardwareTimer::setPrescaleFactor() or +     * HardwareTimer::setOverflow(). +     * +     * @see HardwareTimer::setPrescaleFactor() +     * @see HardwareTimer::setOverflow()       */ -    void detachCompare1Interrupt(void); +    void refresh(void); -    /** -     * Equivalent to detachInterrupt(2). -     * @see HardwareTimer::detachInterrupt() -     */ -    void detachCompare2Interrupt(void); +    /* -- Deprecated methods ----------------------------------------------- */ -    /** -     * Equivalent to detachInterrupt(3). -     * @see HardwareTimer::detachInterrupt() -     */ -    void detachCompare3Interrupt(void); +    /** @brief Deprecated; use setMode(channel, mode) instead. */ +    void setChannelMode(int channel, timer_mode mode) { +        setMode(channel, mode); +    } -    /** -     * Equivalent to detachInterrupt(4). -     * @see HardwareTimer::detachInterrupt() -     */ -    void detachCompare4Interrupt(void); +    /** @brief Deprecated; use setMode(TIMER_CH1, mode) instead. */ +    void setChannel1Mode(timer_mode mode) { setMode(TIMER_CH1, mode); } -    /** -     * Re-initializes the counter (to 0 in upcounting mode, which is -     * the default), and generates an update of the prescale and -     * overflow registers. -     */ -    void generateUpdate(void); +    /** @brief Deprecated; use setMode(TIMER_CH2, mode) instead. */ +    void setChannel2Mode(timer_mode mode) { setMode(TIMER_CH2, mode); } + +    /** @brief Deprecated; use setMode(TIMER_CH3, mode) instead. */ +    void setChannel3Mode(timer_mode mode) { setMode(TIMER_CH3, mode); } + +    /** @brief Deprecated; use setMode(TIMER_CH4, mode) instead. */ +    void setChannel4Mode(timer_mode mode) { setMode(TIMER_CH4, mode); } + +    /** @brief Deprecated; use return getCompare(TIMER_CH1) instead. */ +    uint16 getCompare1() { return getCompare(TIMER_CH1); } + +    /** @brief Deprecated; use return getCompare(TIMER_CH2) instead. */ +    uint16 getCompare2() { return getCompare(TIMER_CH2); } + +    /** @brief Deprecated; use return getCompare(TIMER_CH3) instead. */ +    uint16 getCompare3() { return getCompare(TIMER_CH3); } + +    /** @brief Deprecated; use return getCompare(TIMER_CH4) instead. */ +    uint16 getCompare4() { return getCompare(TIMER_CH4); } + +    /** @brief Deprecated; use setCompare(TIMER_CH1, compare) instead. */ +    void setCompare1(uint16 compare) { setCompare(TIMER_CH1, compare); } + +    /** @brief Deprecated; use setCompare(TIMER_CH2, compare) instead. */ +    void setCompare2(uint16 compare) { setCompare(TIMER_CH2, compare); } + +    /** @brief Deprecated; use setCompare(TIMER_CH3, compare) instead. */ +    void setCompare3(uint16 compare) { setCompare(TIMER_CH3, compare); } + +    /** @brief Deprecated; use setCompare(TIMER_CH4, compare) instead. */ +    void setCompare4(uint16 compare) { setCompare(TIMER_CH4, compare); } + +    /** @brief Deprecated; use attachInterrupt(TIMER_CH1, handler) instead. */ +    void attachCompare1Interrupt(voidFuncPtr handler) { +        attachInterrupt(TIMER_CH1, handler); +    } + +    /** @brief Deprecated; use attachInterrupt(TIMER_CH2, handler) instead. */ +    void attachCompare2Interrupt(voidFuncPtr handler) { +        attachInterrupt(TIMER_CH2, handler); +    } + +    /** @brief Deprecated; use attachInterrupt(TIMER_CH3, handler) instead. */ +    void attachCompare3Interrupt(voidFuncPtr handler) { +        attachInterrupt(TIMER_CH3, handler); +    } + +    /** @brief Deprecated; use attachInterrupt(TIMER_CH4, handler) instead. */ +    void attachCompare4Interrupt(voidFuncPtr handler) { +        attachInterrupt(TIMER_CH4, handler); +    } + +    /** @brief Deprecated; use detachInterrupt(TIMER_CH1) instead. */ +    void detachCompare1Interrupt(void) { detachInterrupt(TIMER_CH1); } + +    /** @brief Deprecated; use detachInterrupt(TIMER_CH2) instead. */ +    void detachCompare2Interrupt(void) { detachInterrupt(TIMER_CH2); } + +    /** @brief Deprecated; use detachInterrupt(TIMER_CH3) instead. */ +    void detachCompare3Interrupt(void) { detachInterrupt(TIMER_CH3); } + +    /** @brief Deprecated; use detachInterrupt(TIMER_CH4) instead. */ +    void detachCompare4Interrupt(void) { detachInterrupt(TIMER_CH4); } + +    /** @brief Deprecated; use refresh() instead. */ +    void generateUpdate(void) { refresh(); }  }; -/** Pre-instantiated timer for use by user code. */ +/* -- The rest of this file is deprecated. --------------------------------- */ + +/** + * @brief Deprecated. + * + * Pre-instantiated timer. + */  extern HardwareTimer Timer1; -/** Pre-instantiated timer for use by user code. */ +/** + * @brief Deprecated. + * + * Pre-instantiated timer. + */  extern HardwareTimer Timer2; -/** Pre-instantiated timer for use by user code. */ +/** + * @brief Deprecated. + * + * Pre-instantiated timer. + */  extern HardwareTimer Timer3; -/** Pre-instantiated timer for use by user code. */ +/** + * @brief Deprecated. + * + * Pre-instantiated timer. + */  extern HardwareTimer Timer4;  #ifdef STM32_HIGH_DENSITY -/** Pre-instantiated timer for use by user code, on devices with -    more than four timers (this does not include the Maple). */ -extern HardwareTimer Timer5; -/** Pre-instantiated timer for use by user code, on devices with -    more than four timers (this does not include the Maple). */ -extern HardwareTimer Timer8; -#endif -  /** - * Get one of the pre-instantiated HardwareTimer instances, given a - * timer device number. - * - * Be careful not to pass an actual number to this function.  For - * example, getTimer(1) will not return Timer1.  Use a real - * timer_dev_num, e.g. TIMER1, TIMER2, etc. + * @brief Deprecated.   * - * @param timerNum the timer device number, e.g. TIMER1. - * - * @return Pointer to the HardwareTimer instance corresponding to the - * given timer device number.  If timerNum is TIMER_INVALID, returns a - * null pointer. + * Pre-instantiated timer. + */ +extern HardwareTimer Timer5; +/** + * @brief Deprecated.   * - * @see timer_dev_num + * Pre-instantiated timer.   */ -HardwareTimer* getTimer(timer_dev_num timerNum); - +extern HardwareTimer Timer8;  #endif +#endif diff --git a/wirish/rules.mk b/wirish/rules.mk index c3608e3..6999288 100644 --- a/wirish/rules.mk +++ b/wirish/rules.mk @@ -23,6 +23,7 @@ cppSRCS_$(d) := wirish_math.cpp		 \                  boards/maple_RET6.cpp	 \                  comm/HardwareSerial.cpp	 \                  comm/HardwareSPI.cpp	 \ +		HardwareTimer.cpp	 \                  usb_serial.cpp		 \                  cxxabi-compat.cpp	 \  		wirish_shift.cpp	 \ diff --git a/wirish/wirish.h b/wirish/wirish.h index d30ad20..82a9897 100644 --- a/wirish/wirish.h +++ b/wirish/wirish.h @@ -44,6 +44,7 @@  #include "wirish_time.h"  #include "HardwareSPI.h"  #include "HardwareSerial.h" +#include "HardwareTimer.h"  #include "usb_serial.h"  /* Arduino wiring macros and bit defines  */  | 
