aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/_static/img/jtag-wiring.pngbin0 -> 40550 bytes
-rw-r--r--source/bootloader.rst2
-rw-r--r--source/gpio.rst168
-rw-r--r--source/i2c.rst87
-rw-r--r--source/jtag.rst66
-rw-r--r--source/language.rst10
-rw-r--r--source/pwm.rst159
-rw-r--r--source/spi.rst66
-rw-r--r--source/timers.rst310
-rw-r--r--source/usart.rst94
-rw-r--r--source/usb.rst186
11 files changed, 1089 insertions, 59 deletions
diff --git a/source/_static/img/jtag-wiring.png b/source/_static/img/jtag-wiring.png
new file mode 100644
index 0000000..9c63e82
--- /dev/null
+++ b/source/_static/img/jtag-wiring.png
Binary files differ
diff --git a/source/bootloader.rst b/source/bootloader.rst
index c4c5da2..fea1f35 100644
--- a/source/bootloader.rst
+++ b/source/bootloader.rst
@@ -88,6 +88,8 @@ bootloader was attractive, it became clear, after much toiling, we
were going to have to write some custom drivers across several
platforms to make everything work this way.
+.. _bootloader-rev3:
+
Maple Rev3
----------
diff --git a/source/gpio.rst b/source/gpio.rst
index 2567221..9104fed 100644
--- a/source/gpio.rst
+++ b/source/gpio.rst
@@ -22,6 +22,8 @@ that pin), while some are not.
.. contents:: Contents
:local:
+.. _pin-mapping-mega-table:
+
Pin Mapping Mega Table
----------------------
@@ -34,53 +36,121 @@ above).
.. csv-table::
:header: "Pin", "STM32", ":ref:`ADC <adc>`", ":ref:`Timer <timers>`", ":ref:`I2C <i2c>`", ":ref:`UART <usart>`", ":ref:`SPI <spi>`", "5v?"
- "D0", "PA3", "ADC3", "TIM2_CH4", "-", "USART2_RX", "-", "No"
- "D1", "PA2", "ADC2", "TIM2_CH3", "-", "USART2_TX", "-", "No"
- "D2", "PA0", "ADC0", "TIM2_CH1_ETR", "-", "USART2_CTS", "-", "No"
- "D3", "PA1", "ADC1", "TIM2_CH2", "-", "USART2_RTS", "-", "No"
- "D4", "PB5", "-", "-", "ISC1_SMBA", "-", "-", "No"
- "D5", "PB6", "-", "TIM4_CH1", "I2C1_SCL", "-", "-", "Yes"
- "D6", "PA8", "-", "TIM1_CH1", "-", "USART1_CK", "-", "Yes"
- "D7", "PA9", "-", "TIM1_CH2", "-", "USART1_TX", "-", "Yes"
- "D8", "PA10", "-", "TIM1_CH3", "-", "USART1_RX", "-", "Yes"
- "D9", "PB7", "-", "TIM4_CH2", "I2C1_SDA", "-", "-", "Yes"
- "D10", "PA4", "ADC4", "-", "-", "USART2_CK", "SPI1_NSS", "No"
- "D11", "PA7", "ADC7", "TIM3_CH2", "-", "-", "SPI1_MOSI", "No"
- "D12", "PA6", "ADC6", "TIM3_CH1", - - SPI1_MISO No
- D13 PA5 ADC5 - - - SPI1_SCK No
- D14 PB8 - TIM4_CH3 - - - Yes
-
- Analog header
-
- D15 PC0 ADC10 - - - - No
- D16 PC1 ADC11 - - - - No
- D17 PC2 ADC12 - - - - No
- D18 PC3 ADC13 - - - - No
- D19 PC4 ADC14 - - - - No
- D20 PC5 ADC15 - - - - No
-
- External header
-
- D21 PC13 - - - - - No
- D22 PC14 - - - - - No
- D23 PC15 - - - - - No
- D24 PB9 - TIM4_CH4 - - - Yes
- D25 PD2 - TIM3_ETR - - - Yes
- D26 PC10 - - - - - Yes
- D27 PB0 ADC8 TIM3_CH3 - - - No
- D28 PB1 ADC9 TIM3_CH4 - - - No
- D29 PB10 - - I2C2_SCL USART3_TX - Yes
- D30 PB11 - - I2C2_SDA USART3_RX - Yes
- D31 PB12 - TIM1_BKIN I2C2_SMBAL USART3_CK SPI2_NSS Yes
- D32 PB13 - TIM1_CH1N - USART3_CTS SPI2_SCK Yes
- D33 PB14 - TIM1_CH2N - USART3_RTS SPI2_MISO Yes
- D34 PB15 - TIM1_CH3N - - SPI2_MOSI Yes
- D35 PC6 - - - - - Yes
- D36 PC7 - - - - - Yes
- D37 PC8 - - - - -
-
-
-Stub (unfinished).
+ "D0", "PA3", "ADC3", "TIM2_CH4", "-", "USART2_RX", "-", "No"
+ "D1", "PA2", "ADC2", "TIM2_CH3", "-", "USART2_TX", "-", "No"
+ "D2", "PA0", "ADC0", "TIM2_CH1_ETR", "-", "USART2_CTS", "-", "No"
+ "D3", "PA1", "ADC1", "TIM2_CH2", "-", "USART2_RTS", "-", "No"
+ "D4", "PB5", "-", "-", "ISC1_SMBA", "-", "-", "No"
+ "D5", "PB6", "-", "TIM4_CH1", "I2C1_SCL", "-", "-", "Yes"
+ "D6", "PA8", "-", "TIM1_CH1", "-", "USART1_CK", "-", "Yes"
+ "D7", "PA9", "-", "TIM1_CH2", "-", "USART1_TX", "-", "Yes"
+ "D8", "PA10", "-", "TIM1_CH3", "-", "USART1_RX", "-", "Yes"
+ "D9", "PB7", "-", "TIM4_CH2", "I2C1_SDA", "-", "-", "Yes"
+ "D10", "PA4", "ADC4", "-", "-", "USART2_CK", "SPI1_NSS", "No"
+ "D11", "PA7", "ADC7", "TIM3_CH2", "-", "-", "SPI1_MOSI", "No"
+ "D12", "PA6", "ADC6", "TIM3_CH1", "-", "-", "SPI1_MISO", "No"
+ "D13", "PA5", "ADC5", "-", "-", "-", "SPI1_SCK", "No"
+ "D14", "PB8", "-", "TIM4_CH3", "-", "-", "-", "Yes"
+ "D15", "PC0", "ADC10", "-", "-", "-", "-", "No"
+ "D16", "PC1", "ADC11", "-", "-", "-", "-", "No"
+ "D17", "PC2", "ADC12", "-", "-", "-", "-", "No"
+ "D18", "PC3", "ADC13", "-", "-", "-", "-", "No"
+ "D19", "PC4", "ADC14", "-", "-", "-", "-", "No"
+ "D20", "PC5", "ADC15", "-", "-", "-", "-", "No"
+ "D21", "PC13", "-", "-", "-", "-", "-", "No"
+ "D22", "PC14", "-", "-", "-", "-", "-", "No"
+ "D23", "PC15", "-", "-", "-", "-", "-", "No"
+ "D24", "PB9", "-", "TIM4_CH4", "-", "-", "-", "Yes"
+ "D25", "PD2", "-", "TIM3_ETR", "-", "-", "-", "Yes"
+ "D26", "PC10", "-", "-", "-", "-", "-", "Yes"
+ "D27", "PB0", "ADC8", "TIM3_CH3", "-", "-", "-", "No"
+ "D28", "PB1", "ADC9", "TIM3_CH4", "-", "-", "-", "No"
+ "D29", "PB10", "-", "-", "I2C2_SCL", "USART3_TX", "-", "Yes"
+ "D30", "PB11", "-", "-", "I2C2_SDA", "USART3_RX", "-", "Yes"
+ "D31", "PB12", "-", "TIM1_BKIN", "I2C2_SMBAL", "USART3_CK", "SPI2_NSS", "Yes"
+ "D32", "PB13", "-", "TIM1_CH1N", "-", "USART3_CTS", "SPI2_SCK", "Yes"
+ "D33", "PB14", "-", "TIM1_CH2N", "-", "USART3_RTS", "SPI2_MISO", "Yes"
+ "D34", "PB15", "-", "TIM1_CH3N", "-", "-", "SPI2_MOSI", "Yes"
+ "D35", "PC6", "-", "-", "-", "-", "-", "Yes"
+ "D36", "PC7", "-", "-", "-", "-", "-", "Yes"
+ "D37", "PC8", "-", "-", "-", "-", "-", "Yes"
+
+.. _gpio-modes:
+
+GPIO Modes
+----------
+
+``OUTPUT``
+
+ Basic digital output: when the pin set high the voltage is held at
+ +3.3V (|vcc|) and when set low it is pulled down to ground.
+
+``OUTPUT_OPEN_DRAIN``
+
+ In open drain mode, the pin indicates "low" by accepting current
+ flow to ground and "high" by providing increased impedance. An
+ example use would be to connect a pin to a bus line (which is
+ pulled up to a positive voltage by a separate supply through a
+ large resistor). When the pin is high, not much current flows
+ through to ground and the line stays at positive voltage; when the
+ pin is low the bus "drains" to ground with a small amount of
+ current constantly flowing through the large resistor from the
+ external supply. In this mode no current is ever actually
+ *sourced* from the pin.
+
+``INPUT`` (or ``INPUT_FLOATING``)
+
+ Basic digital input. The pin voltage is sampled; when it is closer
+ to 3.3V (|vcc|) the pin status is high, and when it is closer to
+ 0V (ground) it is low. If no external circuit is pulling the pin
+ voltage to high or low, it will tend to randomly oscillate and be
+ very sensitive to noise (e.g., a breath of air across the pin will
+ cause the state to flip).
+
+``INPUT_PULLUP``
+
+ The state of the pin in this mode is reported the same way as with
+ INPUT, but the pin voltage is gently "pulled up" towards
+ +3.3V. This means the state will be high unless an external device
+ is specifically pulling the pin down to ground, in which case the
+ "gentle" pull up will not effect the state of the input.
+
+``INPUT_PULLDOWN``
+
+ The state of the pin in this mode is reported the same way as with
+ INPUT, but the pin voltage is gently "pulled down" towards
+ 0V. This means the state will be low unless an external device is
+ specifically pulling the pin up to 3.3V, in which case the
+ "gentle" pull down will not effect the state of the input.
+
+``INPUT_ANALOG``
+
+ This is a special mode for when the pin will be used for analog
+ (not digital) reads. See the :ref:`ADC <adc>` page.
+
+``PWM``
+
+ This is a special mode for when the pin will be used for PWM
+ output (a special case of digital output). See the :ref:`PWM
+ <pwm>` page.
+
+.. TODO PWM_OPEN_DRAIN needs documentation
+
+Function Reference
+------------------
+
+``pinMode(pin_number, MODE)``
+
+ Usually called from within `setup()`_ to configure the pin. MODE
+ is one of the set listed :ref:`above <gpio-modes>`.
+
+``digitalRead(pin_number)``
+
+ Returns ``HIGH`` (|vcc|) or ``LOW`` (0V).
+
+``digitalWrite(pin_number, value)``
+
+ Sets the pin to ``HIGH`` or ``LOW``.
.. _gpio-recommended-reading:
@@ -90,5 +160,5 @@ Recommended Reading
STMicro documentation for STM32F103RB microcontroller:
* `All <http://www.st.com/mcu/devicedocs-STM32F103RB-110.html>`_
- * `Datasheet (pdf) <http://www.st.com/stonline/products/literature/ds/13587.pdf>`_
- * `Reference Manual (pdf) <http://www.st.com/stonline/products/literature/rm/13902.pdf>`_
+ * `Datasheet <http://www.st.com/stonline/products/literature/ds/13587.pdf>`_ (pdf)
+ * `Reference Manual <http://www.st.com/stonline/products/literature/rm/13902.pdf>`_ (pdf)
diff --git a/source/i2c.rst b/source/i2c.rst
index 34bd57c..564ca0e 100644
--- a/source/i2c.rst
+++ b/source/i2c.rst
@@ -4,4 +4,89 @@
|i2c|
=====
-Stub.
+.. note::
+
+ The i2c interface is currently only available from the 'i2c' branch
+ of the github `libmaple <http://github.com/leaflabs/libmaple>`_
+ repository.
+
+|i2c| is a crude and easy-to-hack serial protocol that requires only
+two wires/channels for communication between many devices. Every
+message passed on the bus is between a *master* (who initiates the
+message) and a *slave* device. Slaves are addressed using 7-bit
+addresses (up to 127 unique devices); 10-bit addressing is possible,
+but currently unimplemented. Every message consists of an arbitrary
+combination of 8-bit reads and writes as requested by the master.
+Higher level functionality, such as reading a particular register
+value, is achieved by writing to set the memory location then reading
+to pull out the data.
+
+Note that the master/slave designation is on a message-by-message
+basis. The Maple can act as both a master (messages initiated by user
+code) and slave device (responding to requests via configurable
+interrupt handlers) at the same time.
+
+.. contents:: Contents
+ :local:
+
+Hardware/Circuit Design
+-----------------------
+
+The Maple has two |i2c| ports. Port 1 (i2c1) has SDA on header D9 and
+SCL on D5; Port 2 (i2c2) has SDA on D30 and SCL on D29.
+
+The Maple reliably communicates with up to a 400kHz clock speed; this
+doesn't translate into a 400kbps data rate except in extreme cases
+because of addressing and protocol overhead. We have tested clock
+speeds up to a megahertz and have had mixed results; in theory it
+could be possible to achieve even higher rates, but signal quality
+degrades rapidly and the bus becomes unreliable.
+
+Proper wiring and pull-up resistor selection are essential when
+incorporating |i2c| into a circuit, especially with data rates above
+100kHz. In the lab, we usually use approximately 5kΩ resistors with
+|vcc| (3.3V) as the high voltage, and try to connect the pullup
+voltage as close to the SDA and SCL pins as possible. We recommend
+looking at the ST reference website for |i2c| (see the
+:ref:`recommended reading <i2c-recommended-reading>` below), starting
+with a slow clock rate (10kHz), and, if possible, using an
+oscilloscope to debug any issues.
+
+Function Reference
+------------------
+
+The function API for |i2c| is not finished! See the `source code
+<http://github.com/leaflabs/libmaple/blob/i2c/libmaple/i2c.h>`_ for
+now.
+
+.. TODO link to libmaple I2C docs once (1) finished, (2) in master
+
+SMBus
+-----
+
+The STM32 microcontroller has hardware support for SMBus; we simply
+have not written software for it. The SMBAL line for i2c1 is on header
+D4 and for i2c2 is on D31.
+
+.. TODO link to libmaple SMBus docs once (1) finished, (2) in master
+
+.. _i2c-recommended-reading:
+
+Recommended Reading
+-------------------
+
+* `i2c-bus.org <http://www.i2c-bus.org/>`_
+* `Wikipedia Article on i2c <http://en.wikipedia.org/wiki/I%C2%B2C>`_
+* `Arduino i2c/TWI reference <http://www.arduino.cc/playground/Learning/I2C>`_
+* STMicro documentation for STM32F103RB microcontroller:
+
+ * `All <http://www.st.com/mcu/devicedocs-STM32F103RB-110.html>`_
+ * `Datasheet
+ <http://www.st.com/stonline/products/literature/ds/13587.pdf>`_
+ (pdf)
+ * `Reference Manual
+ <http://www.st.com/stonline/products/literature/rm/13902.pdf>`_
+ (pdf)
+ * `Application Note on Advanced I2C Usage
+ <http://www.st.com/stonline/products/literature/an/15021.pdf>`_
+ (pdf)
diff --git a/source/jtag.rst b/source/jtag.rst
index e94229f..5301a18 100644
--- a/source/jtag.rst
+++ b/source/jtag.rst
@@ -4,4 +4,68 @@
JTAG
======
-Stub.
+JTAG is an interface for low-level debugging of digital devices. It
+gives instruction by instruction control over the microprocessor and
+allows data to be read and written to arbitrary memory and register
+locations. It is typically used with a debugging tool like `gdb
+<http://www.gnu.org/software/gdb/>`_ when hacking low level routines
+and hardware peripherals (we use it when working on :ref:`libmaple
+<libmaple>`) or to flash a new bootloader.
+
+Note that the STM32 on the Maple has a built-in low level serial
+debugger which could also be used to flash bootloaders, and that the
+:ref:`ASSERT <language-assert>` framework allows basic debugging over
+a USART serial channel. We expect only advanced users to use this
+feature.
+
+.. contents:: Contents
+ :local:
+
+
+Wiring Diagram
+--------------
+
+.. figure:: /_static/img/jtag-wiring.png
+ :align: center
+ :alt: JTAG wiring diagram
+
+ JTAG wiring diagram to connect a standard 20-pin ARM JTAG device to
+ the 8-pin JTAG port on the Maple.
+
+.. TODO jtag wiring diagram (above) looks terrible; replace it
+
+The Maple has holes for a 8-pin JTAG header but that header is not
+soldered on by default. If you know ahead of time that you'll be
+needing it, and you order `straight from LeafLabs
+<http://leaflabs.com/store/>`_, add a comment to your order and we can
+probably solder one on for no charge. Otherwise, you can simply
+attach standard 0.1" pitch male header pins (either the exact 4x2
+block or two 4-pin pieces of breakaway straight header). For a one-off
+usage hack, the header can be jammed in the holes and twisted to
+ensure electrical contact; this is what we do to flash our bootloader.
+
+The above schematic assumes that the header has been soldered on to
+the *bottom* of the board, not the top; most ribbon cable connectors
+will interfere with the power header. If you don't want a header
+coming off the bottom, you can use a slim connector and invert this
+diagram appropriately.
+
+
+Compatible Devices
+------------------
+
+We have had good experience with the `Olimex ARM-USB-OCD
+<http://www.olimex.com/dev/arm-usb-ocd.html>`_ device, which costs
+about 55 euro plus shipping (as of October 2010).
+
+
+Recommended Reading
+-------------------
+
+* `Wikipedia Article on Joint Test Action Group (JTAG) <http://en.wikipedia.org/wiki/Joint_Test_Action_Group>`_
+* `STM32/gdb/OpenOCD HOWTO <http://fun-tech.se/stm32/OpenOCD/gdb.php>`_
+* STMicro documentation for STM32F103RB microcontroller:
+
+ * `All <http://www.st.com/mcu/devicedocs-STM32F103RB-110.html>`_
+ * `Datasheet (pdf) <http://www.st.com/stonline/products/literature/ds/13587.pdf>`_
+ * `Reference Manual (pdf) <http://www.st.com/stonline/products/literature/rm/13902.pdf>`_
diff --git a/source/language.rst b/source/language.rst
index 6eb5bc7..36cb801 100644
--- a/source/language.rst
+++ b/source/language.rst
@@ -484,6 +484,10 @@ Recommended Reading
* STMicro documentation for STM32F103RB microcontroller:
* `All documents <http://www.st.com/mcu/devicedocs-STM32F103RB-110.html>`_
- * `Datasheet (pdf) <http://www.st.com/stonline/products/literature/ds/13587.pdf>`_
- * `Reference Manual (pdf) <http://www.st.com/stonline/products/literature/rm/13902.pdf>`_
- * `Programming Manual (pdf) <http://www.st.com/stonline/products/literature/pm/15491.pdf>`_ (assembly language and register reference)
+ * `Datasheet (pdf)
+ <http://www.st.com/stonline/products/literature/ds/13587.pdf>`_
+ * `Reference Manual (pdf)
+ <http://www.st.com/stonline/products/literature/rm/13902.pdf>`_
+ * `Programming Manual (pdf)
+ <http://www.st.com/stonline/products/literature/pm/15491.pdf>`_
+ (assembly language and register reference)
diff --git a/source/pwm.rst b/source/pwm.rst
index c01e415..8d3a8d9 100644
--- a/source/pwm.rst
+++ b/source/pwm.rst
@@ -4,4 +4,161 @@
Pulse-Width Modulation (PWM)
==============================
-Stub.
+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.
+
+.. contents:: Contents
+ :local:
+
+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 :ref:`timer
+documentation <timers>` for more information.
+
+Note that unlike the Arduino, the Maple does not have PWM
+functionality on pin D10; all other pins are :ref:`compatible
+<compatibility>`.
+
+The following table shows which :ref:`timer <timers>` generates which
+PWM outputs. See the :ref:`pin mapping table <pin-mapping-mega-table>`
+to track down exactly which timer *channel* corresponds to each pin.
+
+.. _pwm-timer-table:
+
+.. csv-table::
+ :header: Timer, PWM Headers
+ :delim: |
+
+ Timer1 | D6,D7,D8
+ Timer2 | D0,D1,D2,D3
+ Timer3 | D11,D12,D27,D28
+ Timer4 | D5,D9,D14,D24
+
+Background
+----------
+
+In its 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 user code simply has
+to configure the device and set the two variables and the device will
+function on its 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 :ref:`prescaler
+<pwm-prescaler>` (clock divider) in front of the counter can increase
+this maximum period. Setting the :ref:`period <pwm-overflow>` to
+something other than the maximum value gives further control over the
+total length of the waveform. However, this effectively limits the
+resolution with which the duty can be modified: the duty must be less
+than or equal to the period.
+
+Here are some commonly used PWM configurations (note that servos are
+notoriously variable, especially the lower cost models):
+
++-------------+----------+-----------+---------+---------------+------+
+|**Purpose** |**Period**|**Duty** |Prescaler|Period |Duty |
+| |(ms) |(ms) | | | |
++=============+==========+===========+=========+===============+======+
+|LED throb |0.020 |0--0.020 |1 (none) |65535 (default)|0--767|
+| | | | | | |
++-------------+----------+-----------+---------+---------------+------+
+|Servo control|20 |1.25 (0°) |21 |65535 (default)|4096 |
+| | | | | | |
+| | |1.50 (90°) |21 |65535 (default)|4915 |
+| | | | | | |
+| | |1.75 (180°)|21 |65535 (default)|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; ``PWM_OPEN_DRAIN`` is
+ also available (see the list of :ref:`GPIO modes <gpio-modes>` for
+ more information).
+
+.. _pwm-pwmwrite:
+
+``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 for ``pwmWrite`` to ease
+ porting Arduino code, though period and duty will have to be
+ recalibrated (see :ref:`compatibility <compatibility>`).
+
+.. _pwm-overflow:
+
+``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
+ :ref:`pwmWrite() <pwm-pwmwrite>` corresponding to 100% duty
+ cycle. This also affects the PWM frequency: the higher reload is,
+ the lower the PWM frequency will be.
+
+ The PWM output pin starts HIGH, then the timer begins counting up
+ from zero (with frequency equal to 72MHz/:ref:`prescaler
+ <pwm-prescaler>`) until it hits the duty value, at which point it
+ drops to LOW. The timer then continues counting up until it hits
+ the total period (set with this function), at which point the
+ cycle starts again.
+
+.. _pwm-prescaler:
+
+``Timer[1,2,3,4].setPrescaleFactor(prescale)``
+
+ Find the appropriate timer for a given PWM header using the table
+ :ref:`above <pwm-timer-table>`, then set the prescaler. A
+ prescaler is a clock divider. The timer will normally count with
+ frequency equal to the STM32's normal clock (72MHz); this
+ corresponds to setting ``prescale`` to 1 (which is the default).
+
+ If a longer frequency is desired, use a larger ``prescale`` value.
+ For instance, an 8MHz frequency can be achieved by setting
+ ``prescale`` to 9, since 72MHz / 9 = 8MHz.
+
+ This function is normally called once from, `setup()`_, but the
+ timer can be reconfigured with a new prescaler at any time.
+
+Recommended Reading
+-------------------
+
+* `Wikipedia Article on Pulse-width modulation
+ <http://en.wikipedia.org/wiki/Pulse-width_modulation>`_
+* `Arduino tutorial on PWM <http://www.arduino.cc/en/Tutorial/PWM>`_
+* `Secrets of Arduino PWM
+ <http://www.arcfn.com/2009/07/secrets-of-arduino-pwm.html>`_ by Ken
+ Shirriff
+* `So You Want To Use PWM, Eh? <http://www.arcfn.com/2009/07/secrets-of-arduino-pwm.html>`_ at Non-Lexical Vocables
+* STMicro documentation for STM32F103RB microcontroller:
+
+ * `All <http://www.st.com/mcu/devicedocs-STM32F103RB-110.html>`_
+ * `Datasheet (pdf) <http://www.st.com/stonline/products/literature/ds/13587.pdf>`_
+ * `Reference Manual (pdf) <http://www.st.com/stonline/products/literature/rm/13902.pdf>`_
diff --git a/source/spi.rst b/source/spi.rst
index 8518f3c..3c29b79 100644
--- a/source/spi.rst
+++ b/source/spi.rst
@@ -4,4 +4,68 @@
SPI
=====
-Stub.
+The Maple has two SPI ports. The first has NSS on D10, MOSI on D11,
+MISO on D12, and SCK on D13. The second has NSS on D31, SCK on D32,
+MISO on D33, and MOSI on D34.
+
+.. _spi-speeds:
+
+Each port can be configured at one of the following speeds:
+
+* ``SPI_18MHZ``: 18 MHz
+* ``SPI_9MHZ``: 9 MHz
+* ``SPI_4_5MHZ``: 4.5 MHz
+* ``SPI_2_25MHZ``: 2.25 MHz
+* ``SPI_1_125MHZ``: 1.124 MHz
+* ``SPI_562_500KHZ``: 562.500 KHz
+* ``SPI_281_250KHZ``: 281.250 KHz
+* ``SPI_140_625KHZ``: 140.625 KHz
+
+.. contents:: Contents
+ :local:
+
+Function Reference
+------------------
+
+``HardwareSPI Spi(number);``
+
+ This declaration must be included at the start of any sketch or
+ program that uses the SPI interface. The argument number is either
+ 1 or 2 and specifies which port to use.
+
+``Spi.begin(freq, endianness, mode)``
+
+ ``begin`` is usually called in `setup()`_ to configure the
+ baudrate of the given SPI port and to set up the header pins
+ appropriately. ``freq`` is one of the set listed :ref:`above
+ <spi-speeds>`; ``endianness`` is either ``LSBFIRST`` or
+ ``MSBFIRST``; mode is one of 0, 1, 2, 3, and specifies which "SPI
+ Mode" is used (see specification docs linked below).
+
+``Spi.begin()``
+
+ A default ``begin`` with no arguments is provided for the lazy; it
+ is equivalent to ``Spi.begin(SPI_1_125MHZ, MSBFIRST, 0)``.
+
+``Spi.send(data, size)``
+
+ Writes data into the port buffer to be transmitted as soon as
+ possible. ``data`` should be an array of type ``byte*``; ``size``
+ should be the number of elements in ``data``.
+
+Recommended Reading
+-------------------
+
+* `Wikipedia Article on Serial Peripheral Interface Bus (SPI)
+ <http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus>`_
+* `Arduino reference on SPI
+ <http://www.arduino.cc/playground/Code/Spi>`_
+* `Hardcore SPI on Arduino <http://klk64.com/arduino-spi/>`_ by kik64
+* STMicro documentation for STM32F103RB microcontroller:
+
+ * `All <http://www.st.com/mcu/devicedocs-STM32F103RB-110.html>`_
+ * `Datasheet (pdf)
+ <http://www.st.com/stonline/products/literature/ds/13587.pdf>`_
+ * `Reference Manual (pdf)
+ <http://www.st.com/stonline/products/literature/rm/13902.pdf>`_
+
diff --git a/source/timers.rst b/source/timers.rst
index c156d4f..e0e57cb 100644
--- a/source/timers.rst
+++ b/source/timers.rst
@@ -1,7 +1,315 @@
+.. highlight:: cpp
+
.. _timers:
========
Timers
========
-Stub.
+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
+<pwm>` channels, once enabled, generate regular square-wave signals on
+specific output pins that will continue even if the microcontroller is
+busy crunching numbers or handling communications interrupts. By
+attaching interrupt handlers to these channels (instead of just
+changing the voltage on an external pin), more complex events like
+printing to a serial port, updating a variable, or emitting a whale
+mating call can be scheduled. You can even modify the configuration of
+the timer itself at a regular interval; the possibilities are endless!
+
+The four timers each have four separate compare channels. Each timer
+is a single 16-bit counter that can be configured with both a
+prescaler and an overflow value. The prescaler acts as a divider of
+the 72MHz system clock; without prescaling the counter would get up to
+65536 (2 to the 16th power) and roll over more than a thousand times a
+second; even with the full prescaler it rolls over about once a
+minute. The overflow value is the maximum value the counter will go up
+to. It defaults to the full 65535; smaller values will cause the
+counter to reset to zero more frequently.
+
+
+Caveats
+-------
+
+**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 full :ref:`pin mapping table
+<pin-mapping-mega-table>` to match up timer channels and Maple header
+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.
+
+.. compound::
+
+ **Jitter:** other interrupts (USB, Serial, SysTick, or other
+ timers) can and will get called before or during the timer
+ interrupt routines, causing pseudo-random 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.
+
+ 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.
+
+.. _timers-modes:
+
+General Timer Modes
+-------------------
+
+``TIMER_DISABLED``
+
+ Exactly what it sounds like: the timer stops counting, interrupts
+ are not called, and no state changes are output.
+
+``TIMER_PWM``
+
+ This is the default mode for pins after initialization. See the
+ :ref:`PWM docs <pwm>` for more information on this 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.
+
+``TIMER_OUTPUTCOMPARE``
+
+ In this mode, the timer counts from 0 to the overflow value
+ repeatedly; every time the counter value reaches one of the
+ channel compare values, the corresponding interrupt is fired.
+
+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()``.
+
+Function Reference
+------------------
+
+For all of these functions, ``Timer1`` can be replaced with
+``Timer2``, ``Timer3``, or ``Timer4``; the channel numbers also range
+from 1 to 4.
+
+``Timer1.pause()``/\ ``Timer1.resume()``
+
+ These functions start and stop the counter without affecting the
+ rest of the configuration. These functions can be used during the
+ setup period to prevent interrupts from firing before they are
+ completely configured. Note that there is some function call
+ overhead with these functions, so they are not a perfect way to
+ align multiple timers to the same count value.
+
+``Timer1.setOverflow(val)``
+
+ Sets the overflow (or "reload") value for the whole timer; when
+ the counter reaches this value it resets to zero. Defaults to
+ 65535 (the largest unsigned 16bit integer); setting it 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.
+
+``Timer1.setPrescaleFactor(val)``
+
+ The prescaler acts as a clock divider to slow down the rate at
+ which the counter increments. 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 you set the prescaler to 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 just about
+ once a second. Use the :ref:`setPeriod <timers-set-period>`
+ function below if you are allergic to math!
+
+.. _timers-set-period:
+
+``Timer1.setPeriod(val)``
+
+ This tricky trick will configure the prescaler and overflow values
+ to generate a timer reload with a period as close to val
+ microseconds as possible. It returns the chosen overflow value,
+ which you can then use to set the channel compare values
+ appropriately: if you just want the interrupts to fire when the
+ clock rolls over and you don't care about the relative "phase",
+ you can always set the channel compare values to 1.
+
+ Remember: a microsecond is 1/1,000,000th of a second, or 1/1,000
+ of a millisecond. The prescaler itself is 16bit, so the longest
+ period that can be configured is 1/(72MHz) * (2^32) = (59.65
+ seconds) or about a minute. You can get around this by creating an
+ interrupt that increments a 32-bit variable, by using the
+ ``millis()`` function, or by interfacing with an external
+ real-time-clock chip.
+
+``Timer1.setCount(val)``/\ ``Timer1.getCount()``
+
+ These functions let you mess with the counter's brains
+ directly. You can probably make it not work if you try! The timer
+ is 16bit, so ``val`` and the return value of ``getCount`` are
+ ``uint16``.
+
+``Timer1.setChannel1Mode(MODE)``
+
+ This sets the given channel (here 1) of the given timer (here 1)
+ to the given mode. See the :ref:`list above <timers-modes>` for
+ possible values; for interrupts you want ``TIMER_OUTPUTCOMPARE``.
+
+``Timer1.setCompare1(val)``
+
+ Sets the compare value for the given channel; when the counter
+ reaches this value the interrupt for this channel will fire if the
+ channel is in output compare mode 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 overhead means that the smallest increment
+ rate is a couple microseconds.
+
+``Timer1.attachCompare1Interrupt(function)``/\ ``Timer1.detachCompare1Interrupt()``
+
+ This is how to attach or disable an interrupt handlers to timer
+ channels; this what will get called when the counter reaches the
+ compare value set with ``setCompareN(val)``. ``function``
+ (sometimes referred to as an ISR: "interrupt service routine")
+ should be of a type that does not accept or return any values
+ (C/C++ programmers: ``void (function*)(void)``). They are just
+ like any other function in your sketch/program and must be
+ initialized at the top of the file and defined below.
+
+ ``function`` should try to do what it has to do as fast 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 ISR, you're probably doing it
+ wrong.
+
+ Stay vigilant here... function pointers are serious business, and
+ once you go down that path you'll find yourself in a `forest of
+ parentheses <http://mitpress.mit.edu/sicp/>`_ before you know it.
+
+Code Examples
+-------------
+
+LED blink
+^^^^^^^^^
+
+\ ::
+
+ #define LED_PIN 13
+ #define LED_RATE 500000 // in microseconds; should give 0.5Hz toggles
+
+ void handler_led(void);
+
+ int toggle = 0;
+
+ void setup()
+ {
+ // Set up the LED to blink
+ pinMode(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) {
+ toggle ^= 1;
+ digitalWrite(LED_PIN, toggle);
+ }
+
+Racing Counters
+^^^^^^^^^^^^^^^
+
+\ ::
+
+ #define BUTTON_PIN 38
+
+ void handler_count1(void);
+ void handler_count2(void);
+
+ int count1 = 0;
+ int count2 = 0;
+
+ void setup()
+ {
+ // Set up BUT for input
+ pinMode(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(BUTTON_PIN)) {
+ Timer4.pause();
+ } else {
+ Timer4.resume();
+ }
+ delay(1);
+ }
+ }
+
+ void handler1(void) {
+ count1++;
+ }
+ void handler2(void) {
+ count2++;
+ }
diff --git a/source/usart.rst b/source/usart.rst
index 30c953a..19b054f 100644
--- a/source/usart.rst
+++ b/source/usart.rst
@@ -4,4 +4,96 @@
USART
=======
-Stub.
+.. contents::
+ :local:
+
+Hardware/Circuit Design
+-----------------------
+
+The Maple has 3 separate USART devices: ``Serial1``, ``Serial2``, and
+``Serial3``. In the most simple use case, the RX and TX pins are used
+to send data at a predetermined baudrate with the line voltage level
+relative to ground.
+
++-----------+--------+-----+
+|Port |Function|Pin |
++===========+========+=====+
+|``Serial1``|TX |D7 |
+| | | |
+| |RX |D8 |
+| | | |
+| |CK |D6 |
++-----------+--------+-----+
+|``Serial2``|TX |D1 |
+| | | |
+| |RX |D0 |
+| | | |
+| |CK |D10 |
+| | | |
+| |CTS |D2 |
+| | | |
+| |RTS |D3 |
++-----------+--------+-----+
+|``Serial3``|TX |D29 |
+| | | |
+| |RX |D30 |
+| | | |
+| |CK |D31 |
+| | | |
+| |CTS |D32 |
+| | | |
+| |RTS |D33 |
++-----------+--------+-----+
+
+.. TODO make above less ugly
+
+Compatible Devices and Specifications
+-------------------------------------
+
+We have successfully used the Maple USART ports with an FT232R-based USB-serial converter at up to 115200 baud; higher speeds should certainly be possible.
+
+Function Reference
+------------------
+
+In the following, you may replace ``SerialN`` with ``Serial1``,
+``Serial2``, or ``Serial3``.
+
+``SerialN.begin(baudrate)``
+
+ ``SerialN.begin`` is usually called in `setup()`_ to configure the
+ baudrate of the given serial port and to set up the header pins
+ appropriately. It can be called at any time to reconfigure a port
+ or to change the baudrate. 9600 baud is the generic speed most
+ widely supported by other devices and terminals.
+
+``SerialN.print(...)``/\ ``SerialN.println(...)``
+
+ Writes data into the port buffer to be transmitted as soon as
+ possible. Accepts strings (``char*``). If a raw integer is
+ passed, the corresponding ASCII character will be transmitted; to
+ print out a number in human readable form add a second parameter
+ with the base system.
+
+ For example, to print out the decimal number '1234' use
+ ``SerialN.print(1234, DEC)``; to print out the binary number
+ '1001', use ``SerialN.print(9, BIN)``.
+
+``SerialN.available()``/\ ``SerialN.read()``
+
+ ``SerialN.read()`` will return the next unread character that has
+ been received over the port. ``SerialN.available()`` returns how
+ many such bytes are available (or zero if none are). If none are
+ available, ``SerialN.read()`` will block/fail, so the usual
+ program structure is to poll with ``SerialN.available`` and only
+ read if a nonzero value is returned.
+
+Recommended Reading
+-------------------
+
+* `Wikipedia article on Universal asynchronous receiver/transmitter (USART) <http://en.wikipedia.org/wiki/Universal_asynchronous_receiver/transmitter>`_
+* `Arduino reference on Serial <http://arduino.cc/en/Reference/Serial>`_
+* STMicro documentation for STM32F103RB microcontroller:
+
+ * `All <http://www.st.com/mcu/devicedocs-STM32F103RB-110.html>`_
+ * `Datasheet <http://www.st.com/stonline/products/literature/ds/13587.pdf>`_ (pdf)
+ * `Reference Manual <http://www.st.com/stonline/products/literature/rm/13902.pdf>`_ (pdf)
diff --git a/source/usb.rst b/source/usb.rst
index 2460df5..1ce91f0 100644
--- a/source/usb.rst
+++ b/source/usb.rst
@@ -1,7 +1,191 @@
+.. highlight:: cpp
+
.. _usb:
=====
USB
=====
-Stub.
+.. note:: Changes and Caveats
+
+ The SerialUSB functionality was modified for the 0.0.6 IDE
+ release. It now includes a 50 millisecond timeout for writes and
+ does not try to detect if the USB host is "really" connected or
+ just enumerated and initialized. This means that if you have a
+ number of SerialUSB writes or prints in your code and you are not
+ monitoring on a computer your program will run much, much slower
+ than if it is being monitored or totally disconnected (battery).
+
+ You can avoid this behavior by :ref:`deciphering the port status
+ <usb-safe-print>` using the DTR and RTS line status; the behavior
+ of these control lines is platform dependent and we no longer
+ interpret them by default.
+
+The Maple STM32 microprocessor includes a dedicated USB peripheral
+which can be configured to act as a general USB slave device with
+transfer rates up to 12Mbps (it unfortunately can't be configured as a
+host or on-the-go device). By default, the peripheral is configured
+for two uses: first, to receive sketch/program uploads from the IDE,
+and second, to emulate a regular serial port for use as a terminal
+(text read/write).
+
+The emulated terminal is relatively slow and inefficient; it is best
+for transferring data at regular serial speeds (kilobaud). Users
+requiring faster data transfer should consider implementing a
+different communications protocol; the Maple could be reprogrammed to
+appear as a mass storage device (thumb drive), human interface device
+(mouse or keyboard), microphone, or any other USB device.
+
+The SerialUSB channel is also used as part of the auto-reset feature
+of the IDE to program the board (on Maple Rev3): a :ref:`magic
+sequence of control line toggles and transmitted data
+<bootloader-rev3>` causes the Maple to reset itself and enter
+bootloader mode. As an unfortunate consequence, the auto-reset will
+not work if the IDE can not access the serial port, either due to a
+conflict with another program (serial monitor) or because the
+interface has been disabled from the Maple side (through
+``SerialUSB.end()``).
+
+Function Reference
+------------------
+
+``SerialUSB.print(...)``/\ ``SerialUSB.println(...)``
+
+ Writes data into the port buffer to be transmitted as soon as
+ possible. Accepts strings (``char*``). If a raw integer is passed
+ the corresponding ASCII character will be transmitted; to print
+ out a number in human readable form add a second parameter with
+ the base system. For example, to print out the decimal number
+ "1234", use ``SerialUSB.print(1234, DEC)``; to print out the
+ binary number "1001", use ``SerialUSB.print(9, BIN)``.
+
+.. _usb-write:
+
+``SerialUSB.write(bytes)``
+
+ ``write`` is a lower-level function that writes bytes directly
+ into the buffer. :ref:`print() <usb-print>` often calls this
+ function dozens of times to write out a single formatted number;
+ user code can optimize raw data speed by calling this function
+ with 64-byte chunks instead.
+
+``SerialUSB.available()``/\ ``SerialUSB.read()``
+
+ ``SerialUSB.read()`` will return the next available character
+ (``byte``) that has been received over the port.
+ ``SerialUSB.available()`` returns how many such bytes are actually
+ available. If there is no data, ``read`` will block/fail, so the
+ usual program structure is to poll with ``available`` and only
+ ``read`` if there are data to read.
+
+``SerialUSB.read(buffer, length)``
+
+ An alternative version of ``SerialUSB.read``; will write the next
+ ``length`` available characters into the array ``buffer``.
+
+``SerialUSB.pending()``
+
+ Returns the number of bytes waiting in the transmit
+ buffer. Usercode can use this to prevent any blocking/waiting when
+ using the direct :ref:`write <usb-write>` functions, or to check
+ if data was actually requested/received by the host.
+
+``SerialUSB.getRTS()``
+
+ Returns the state (1 or 0) of the virtual RTS ("ready to send")
+ line. This can be used to guess if the USB host is actively
+ waiting for data (e.g., if a serial monitor program is running) or
+ just "configured" (i.e., the virtual serial port is configured,
+ but no program is reading data).
+
+``SerialUSB.getDTR()``
+
+ Returns the state (1 or 0) of the virtual DTR ("data terminal
+ ready") line. This can be used to guess if the USB host is
+ actively waiting for data (e.g., if a serial monitor program is
+ running) or just "configured" (i.e., the virtual serial port is
+ configured, but no program is reading data).
+
+.. TODO deprecate crap out of above two functions; write a sane API
+
+``SerialUSB.isConnected()``
+
+ Returns 1 if the USB host is connected and the virtual serial
+ interface is initialized (though not necessarily active).
+ Otherwise, returns 0.
+
+``SerialUSB.end()``/\ ``SerialUSB.begin()``
+
+ The USB peripheral is enabled by default so that the auto-reset
+ feature will work, but it can be disabled/restarted at any time
+ with the ``SerialUSB.end()`` and ``SerialUSB.begin()``
+ functions.
+
+ ``SerialUSB.end()`` is a relatively hard shutdown, similar to
+ unplugging the board; this may crash or confuse any programs
+ running host-side. Note that calling this function will require
+ the Maple to be put into :ref:`perpetual bootloader mode
+ <troubleshooting-perpetual-bootloader>` before another program can
+ be uploaded onto it, unless ``SerialUSB.begin()`` is called before
+ the upload is attempted.
+
+ It's probably wise to wait a few seconds between calls to
+ ``SerialUSB.end()`` and ``SerialUSB.begin()`` (or to
+ ``SerialUSB.begin()`` and ``SerialUSB.print()``) to let the
+ computer reconfigure.
+
+Code Examples
+-------------
+
+.. _usb-safe-print:
+
+Safe Print
+^^^^^^^^^^
+
+This function should run smoothly and not block; the LED should blink
+at roughly the same speed whether being monitored, running from
+battery, or connected but not monitored. You may need to experiment
+with the DTR/RTS logic for your platform and device configuration. ::
+
+ #define LED_PIN 13
+
+ void setup() {
+ /* Set up the LED to blink */
+ pinMode(LED_PIN, OUTPUT);
+ }
+
+ void loop() {
+ // LED will stay off if we are disconnected;
+ // will blink quickly if USB is unplugged (battery etc)
+ if(SerialUSB.isConnected()) {
+ digitalWrite(LED_PIN, 1);
+ }
+ delay(100);
+
+ // If this logic fails to detect if bytes are going to
+ // be read by the USB host, then the println() will fully
+ // many times, causing a very slow LED blink.
+ // If the characters are printed and read, the blink will
+ // only slow a small amount when "really" connected, and fast
+ // when the virtual port is only configured.
+ if(SerialUSB.isConnected() && (SerialUSB.getDTR() || SerialUSB.getRTS())) {
+ for(int i=0; i<10; i++) {
+ SerialUSB.println(123456,BIN);
+ }
+ }
+ digitalWrite(LED_PIN, 0);
+ delay(100);
+ }
+
+Recommended Reading
+-------------------
+
+* `USB in a NutShell <http://www.beyondlogic.org/usbnutshell/usb1.htm>`_ overview from Beyond Logic
+* `Wikipedia article on Universal Serial Bus (USB) <http://en.wikipedia.org/wiki/Universal_Serial_Bus>`_
+* Linux Kernel documentation for `USB ACM <http://www.kernel.org/doc/Documentation/usb/acm.txt>`_ and `USB Serial <http://www.kernel.org/doc/Documentation/usb/usb-serial.txt>`_
+* STMicro documentation for STM32F103RB microcontroller:
+
+ * `All documents <http://www.st.com/mcu/devicedocs-STM32F103RB-110.html>`_
+ * `Datasheet <http://www.st.com/stonline/products/literature/ds/13587.pdf>`_ (pdf)
+ * `Reference Manual <http://www.st.com/stonline/products/literature/rm/13902.pdf>`_ (pdf)
+ * `Programming Manual <http://www.st.com/stonline/products/literature/pm/15491.pdf>`_ (pdf; assembly language and register reference)