# Maple Reference Documentation: PWM

Pulse Width Modulation is a basic technique to create repeated square waves (digital high/low voltage transitions) of user defined length and duty cycle. It can be used as a way to encode an "analog" signal on a single digital (high/low) line using the time between transitions ("pulse width") as the variable; this technique is commonly used to send servo position and motor speed commands. Another use is to use to the ratio of "high" and "low" time to approximate a voltage output; this technique can be used to dim an LED or even (with careful filtering) generate audio waveforms.

- Overview
- Background
- Function Reference
- Recommended Reading

## Overview

The Maple has a large number of 16-bit PWM outputs, each connected to one of 4 timers. Some configuration, such as the clock rate or prescaling, must be common to the entire timer; see the timer docs for more information!

Note that unlike the Arduino, the Maple does not have PWM functionality on pin D10; all other pins are compatible.

The following table shows which timer generates which PWM outputs. See the pin mapping table to track down exactly which timer channel corresponds to each pin.

Timer | PWM Headers
--- | ---
Timer1 | D6,D7,D8
Timer2 | D0,D1,D2,D3
Timer3 | D11,D12,D27,D28
Timer4 | D5,D9,D14,D24

## Background

In it's simplest form the device is a single counter with two variables. The counter starts at zero and the output starts at "high". The counter increments every clock cycle until it reaches the first variable number, at which point the output goes "low". The counter continues incrementing until it reaches the second variable at which point the output goes "high" again and the counter resets to zero. The time spent with output high is called the pulse duration or duty; the total time before repeat is the period.

This simple functionality could be approximated in software by setting a GPIO high or low, but the beauty of PWM is that the usercode simply has to configure the device and set the two variables and the device will function on it's own; no further microprocessor cycles will be consumed and a repeated HIGH/LOW waveform will spew out.

The Maple has 16-bit PWM resolution, which means that the counter and variables can be as large as 65535, as opposed to 255 with 8-bit resolution. With a 72MHz clock rate, a PWM output could have maximum period of about one millisecond; using a prescaler (clock divider) in front of the counter and can increase this maximum period (eg, an 8x prescaler would result in around an 8ms maximum duty cycle). The setting the period variable to something other than the maximum value gives further control over the total length of the waveform, but effectively limits the resolution with which the duty can be modified: the duty must be lower than or equal to the period.

Here are some commonly used PWM configurations (note: double check our math!):

Purpose | Period (ms) | Duty (ms) | Prescaler | Period | Duty
--- | --- | --- | --- | --- | ---
LED Throb | 0.020ms | 0 to 0.020ms | 1 (none) | 65535 (default) | 0 to 767
Servo Control | 20ms | 1.25 (0deg) 1.50ms (90deg) 1.75 (180deg) | 21 21 21 | 65535 (default) 65535 (default) 65535 (default) | 4096 4915 5734

## Function Reference

`pinMode(pin_num, PWM)`
  This command is usually called from `setup()` to tell the microcontroller that `pin_num` should be configured to PWM output. PWM implies regular driven OUTPUT (not open drain etc).
`pwmWrite(pin_num, value)`
  This command sets the PWM duty. User code is expected to determine and honor the maximum value (based on the configured period). As a convenience, `analogWrite` is an alias of `pwmWrite` to ease porting Arduino code, though period and duty will have to be recalibrated (see compatibility.html).
`Timer1.setPrescaleFactor(prescale)`
  Find the appropriate timer for a given PWM header using the table above, then set the prescaler. This function is normally called once from `setup()`, but the timer can be reconfigured with a new prescaler at any time. The default prescaler is 1 (eg, no prescaling).
`Timer1.setOverflow(overflow)`
  This function sets the period ("reload" or "overflow") value for an entire PWM timer bank. The value is 16bit (0 to 65535) and determines the maximum value that can be written with `pwmWrite()` corresponding to 100% duty cycle. This also affects the PWM frequency: the higher reload is, the lower the PWM frequency will be.

## Recommended Reading

- Wikipedia Article on Pulse-width modulation
- Arduino tutorial on PWM
- " Secrets of Arduino PWM" by Ken Shirriff
- STMicro documentation for STM32F103RB microcontroller:
  - All
  - Datasheet (pdf)
  - Reference Manual (pdf)

### About this Document

A more recent version of this document may be available from the LeafLabs website. Our documentation is versioned on github; you can track changes to the master branch at this link.

This documentation is released under a Creative Commons Attribution-Share Alike 3.0 license.

Translations are welcomed; give us a ping to make sure we aren't in the process of revising or editing first.