diff --git a/doc/dmd-running-figure.dox b/doc/dmd-running-figure.dox
index b4da2d78..9207d519 100644
--- a/doc/dmd-running-figure.dox
+++ b/doc/dmd-running-figure.dox
@@ -70,7 +70,7 @@ always 16). We must also call DMD::loop() repeatedly from the application's
main loop() function to ensure that the display is kept refreshed.
Sometimes it can be inconvenient to arrange for DMD::loop() to be called
-regularly. An alternative is to use Timer1 and
+regularly. An alternative is to use Timer1 or Timer2 and
\ref dmd_interrupts "interrupt-driven display refresh":
\dontinclude DMD/examples/RunningFigureISR/RunningFigureISR.pde
@@ -78,6 +78,9 @@ regularly. An alternative is to use Timer1 and
\until loop()
\until }
+In the case of Timer2, \c TIMER2_OVF_vect and \ref DMD::enableTimer2() "enableTimer2()"
+would be used in place of \c TIMER1_OVF_vect and \ref DMD::enableTimer1() "enableTimer1()".
+
The full source code for the example follows:
\include DMD/examples/RunningFigure/RunningFigure.pde
diff --git a/libraries/DMD/DMD.cpp b/libraries/DMD/DMD.cpp
index bd493b52..547c48d7 100644
--- a/libraries/DMD/DMD.cpp
+++ b/libraries/DMD/DMD.cpp
@@ -95,6 +95,24 @@
* }
* \endcode
*
+ * If Timer1 is already in use by some other part of your application,
+ * then Timer2 can be used as an alternative interrupt source:
+ *
+ * \code
+ * #include
+ *
+ * DMD display;
+ *
+ * ISR(TIMER2_OVF_vect)
+ * {
+ * display.refresh();
+ * }
+ *
+ * void setup() {
+ * display.enableTimer2();
+ * }
+ * \endcode
+ *
* DMD can also be used with third-party timer libraries such as
* TimerOne:
*
@@ -540,7 +558,7 @@ void DMD::refresh()
* If timer interrupts are being used to update the display, then it is
* unnecessary to call loop().
*
- * \sa refresh(), disableTimer1(), setDoubleBuffer()
+ * \sa refresh(), disableTimer1(), enableTimer2(), setDoubleBuffer()
*/
void DMD::enableTimer1()
{
@@ -599,6 +617,66 @@ void DMD::disableTimer1()
TIMSK1 &= ~_BV(TOIE1);
}
+/**
+ * \brief Enables Timer2 overflow interrupts for updating this display.
+ *
+ * The application must also provide an interrupt service routine for
+ * Timer2 that calls refresh():
+ *
+ * \code
+ * #include
+ *
+ * DMD display;
+ *
+ * ISR(TIMER2_OVF_vect)
+ * {
+ * display.refresh();
+ * }
+ *
+ * void setup() {
+ * display.enableTimer2();
+ * }
+ * \endcode
+ *
+ * If timer interrupts are being used to update the display, then it is
+ * unnecessary to call loop().
+ *
+ * \sa refresh(), disableTimer2(), enableTimer1(), setDoubleBuffer()
+ */
+void DMD::enableTimer2()
+{
+ // Configure Timer2 for the period we want. With the prescaler set
+ // to 128, then 256 increments of Timer2 gives roughly 4 ms between
+ // overflows on a system with a 16 MHz clock. We adjust the prescaler
+ // accordingly for other clock frequencies.
+ TCCR2A = 0;
+ if (F_CPU >= 32000000)
+ TCCR2B = _BV(CS22) | _BV(CS21); // Prescaler = 256
+ else if (F_CPU >= 16000000)
+ TCCR2B = _BV(CS22) | _BV(CS20); // Prescaler = 128
+ else if (F_CPU >= 8000000)
+ TCCR2B = _BV(CS22); // Prescaler = 64
+ else
+ TCCR2B = _BV(CS21) | _BV(CS20); // Prescaler = 32
+
+ // Reset Timer2 to kick off the process.
+ TCNT2 = 0;
+
+ // Turn on the Timer2 overflow interrupt (also turn off OCIE2A and OCIE2B).
+ TIMSK2 = _BV(TOIE2);
+}
+
+/**
+ * \brief Disables Timer2 overflow interrupts.
+ *
+ * \sa enableTimer2()
+ */
+void DMD::disableTimer2()
+{
+ // Turn off the Timer2 overflow interrupt.
+ TIMSK2 &= ~_BV(TOIE2);
+}
+
/**
* \brief Converts an RGB value into a pixel color value.
*
diff --git a/libraries/DMD/DMD.h b/libraries/DMD/DMD.h
index 1bc46570..e07a61c4 100644
--- a/libraries/DMD/DMD.h
+++ b/libraries/DMD/DMD.h
@@ -42,6 +42,9 @@ public:
void enableTimer1();
void disableTimer1();
+ void enableTimer2();
+ void disableTimer2();
+
static Color fromRGB(uint8_t r, uint8_t g, uint8_t b);
private: