aboutsummaryrefslogtreecommitdiffstats
path: root/source/arduino/analogwrite.rst
blob: a1057abd56de2de92715ae5a2910485100db0c35 (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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
.. highlight:: cpp

.. _arduino-analogwrite:

analogWrite()
=============

.. note::

   On the Maple, calling analogWrite() is the same as calling
   :ref:`wirish-pwmwrite`\ ; see that function's documentation for more
   information.

   This is because PWM is not true analog output (i.e., is not the
   output of a `DAC
   <http://en.wikipedia.org/wiki/Digital-to-analog_converter>`_\ ), so
   the function is badly named.  For instance, **analogWrite() has
   absolutely nothing to do with** :ref:`arduino-analogread`\ , which
   is potentially confusing.

   The alias of analogWrite() to pwmWrite() is provided (sigh) for the
   sake of compatibility with Arduino, but we recommend using
   :ref:`wirish-pwmwrite` when writing new software, for clarity.

.. contents:: Contents
   :local:

Arduino Compatibility
---------------------

There are a few important differences between Arduino's `analogWrite()
<http://arduino.cc/en/Reference/AnalogWrite>`_ and Maple's
:ref:`wirish-pwmwrite` that you should keep in mind.  In each case, we
have some recommendations you can use to help converting from Arduino
to Maple.

Difference 1: Duty cycle range is different
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The first and most important difference is that the largest possible
value for the duty cycle is much bigger on the Maple.  Using Arduino's
analogWrite(), the duty cycle ranges between 0--255 (always off --
always on)\ [#fbytemax]_\ .  Using Maple's pwmWrite(), the duty cycle
ranges from 0--65,535 by default\ [#fuint16max]_\ .

This is a good thing!  The greater range of values on the Maple gives
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 <arduino-map>` the argument to
analogWrite into the right range::

    // Arduino code:
    analogWrite(pin, duty);

    // Becomes Maple code:
    analogWrite(pin, map(duty, 0, 255, 0, 65535));

This will convert values in the range 0-255 to values in the range
0--65,635, which is the correct default range for all of the timers
which control PWM output.  See the :ref:`timers reference <timers>`
for more information.

Another fix is to consult the :ref:`pin mapping mega table
<pin-mapping-mega table>` to find the timer which controls PWM on the
pin you're using, then set 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 <arduino-attachinterrupt>` the timer controls) will
likely need to be modified as well.

Difference 2: You must use pinMode() to set up PWM
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The second difference is that on the Maple, you **must** set up the pin
for PWM output using :ref:`arduino-pinmode`\ , with argument ``PWM``.
This should just be one extra line of code in your
:ref:`arduino-setup` function.  Example::

    void setup() {
        // set up pin 9 for PWM
        pinMode(9, PWM);
    }

This also means that you can't later call :ref:`arduino-digitalread`
or :ref:`arduino-digitalwrite` on that pin (unless some time in
between, you use pinMode() to reconfigure that pin for ``INPUT`` or
``OUTPUT``; see the :ref:`arduino-pinmode` page for more information).

Difference 3: No PWM on pin 10
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

On the Maple, the pins which support PWM are: 0, 1, 2, 3, 5, 6, 7, 8,
9, 11, 12, and 14, or twelve pins in total.  That is at least as
*many* PWM pins as any Arduino board, but there are differences in
*which* pins support it.

* On **most Arduino boards** (those with the ATmega168 or ATmega328;
  this includes the **Arduino Uno**), this function works on pins 3,
  5, 6, 9, 10, and 11, or six pins total.  Note that these boards
  support PWM on pin 10, while Maple does not.

* On the **Arduino Mega**, PWM works on pins 2 through 13, or twelve pins
  total.  Note that this board supports PWM on pins 4, 10, and 13,
  while the Maple does not.  Maple supports PWM on pins 0, 1, and 14,
  which the Mega does not, making the total number of pins supporting
  PWM equal on these boards.

* **Older Arduino boards** with an ATmega8 only support analogWrite() on
  pins 9, 10, and 11.  Maple does not support PWM on pin 10.

In all cases, Arduino boards support PWM on pin 10, unlike Maple.  We
did our best to make PWM as pin-compatible as possible; however,
circuit layout constraints prevented us from achieving perfect
compatibility.

The "safest" pins to use for PWM output are pins 9 and 11.  These pins
work on any Arduino board and on Maple.  The "safe" pins, which work
on most recent Arduino boards, the Arduino Mega and the Maple, are
pins 3, 5, 6, 9, and 11.  Thus, if you want your project to be as
portable as possible between Maple and Arduino, we recommend using the
"safest" pins first, then the "safe" pins, as necessary.

Difference 4: PWM frequency
^^^^^^^^^^^^^^^^^^^^^^^^^^^

The frequency of the PWM signal (i.e., the frequency of a complete
on/off cycle) on the Arduino is approximately 490 Hz.

On the Maple, the frequency is configurable, defaulting to about 1100
Hz, or 1.1 KHz.  This is because the PWM frequency is the frequency of
the timer which controls PWM output on the particular pin (\
:ref:`the PWM tutorial has the details <pwm>`\ ).

If your application absolutely requires Arduino's PWM frequency (it
probably doesn't), then the steps are:

1. Figure out which timer controls PWM output on your pin (\ :ref:`this table <pwm-timer-table>` is your friend here).  Let's say it's ``Timern``\ , where ``n`` is some number 1, 2, 3, or 4.

2. Call ``Timern.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.  One example is :ref:`interrupts <timers-attachinterrupt>`\ .
You've been :ref:`warned <timers-pwm-conflicts>`\ .

See also
--------

-  :ref:`Maple PWM tutorial <pwm>`

.. rubric:: Footnotes

.. [#fbytemax] This is because the value for the duty cycle on Arduino
   must fit in 1 byte of memory, and an unsigned (i.e., nonnegative)
   integer with size 1 byte can hold the values between 0 and 255.

.. [#fuint16max] This is because the value for the duty cycle on the
   Maple uses 2 bytes of memory, and an unsigned (i.e., nonnegative)
   integer with size 2 bytes can hold the values between 0 and 65,535.


.. include:: cc-attribution.txt