aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--Makefile8
-rw-r--r--README8
-rw-r--r--TODO6
-rw-r--r--build-targets.mk8
-rw-r--r--docs/Doxyfile1633
-rw-r--r--docs/Makefile133
-rw-r--r--docs/README83
-rw-r--r--docs/make.bat155
-rw-r--r--docs/source/_static/.gitignore0
-rw-r--r--docs/source/_static/apilist.html5
-rw-r--r--docs/source/_static/img/blinky-to-flash.pngbin0 -> 22657 bytes
-rw-r--r--docs/source/_static/img/blinky.pngbin0 -> 21042 bytes
-rw-r--r--docs/source/_static/img/button-new.pngbin0 -> 234 bytes
-rw-r--r--docs/source/_static/img/button-open.pngbin0 -> 259 bytes
-rw-r--r--docs/source/_static/img/button-save.pngbin0 -> 253 bytes
-rw-r--r--docs/source/_static/img/button-serial-monitor.pngbin0 -> 249 bytes
-rw-r--r--docs/source/_static/img/button-stop.pngbin0 -> 294 bytes
-rw-r--r--docs/source/_static/img/button-upload.pngbin0 -> 291 bytes
-rw-r--r--docs/source/_static/img/button-verify.pngbin0 -> 326 bytes
-rw-r--r--docs/source/_static/img/codeblocks_build.pngbin0 -> 112088 bytes
-rw-r--r--docs/source/_static/img/codeblocks_makefile.pngbin0 -> 75653 bytes
-rw-r--r--docs/source/_static/img/codeblocks_maketargets.pngbin0 -> 56250 bytes
-rw-r--r--docs/source/_static/img/codeblocks_newproject.pngbin0 -> 45930 bytes
-rw-r--r--docs/source/_static/img/ide-blinky.pngbin0 -> 29213 bytes
-rw-r--r--docs/source/_static/img/jtag-wiring.pngbin0 -> 33637 bytes
-rw-r--r--docs/source/_static/img/libmaple-screenshot-small.pngbin0 -> 38023 bytes
-rw-r--r--docs/source/_static/img/osx-network-prefs-unconfigured.pngbin0 -> 81770 bytes
-rw-r--r--docs/source/_static/img/osx-unconfigured-popup.pngbin0 -> 28359 bytes
-rw-r--r--docs/source/_static/img/round_logo_32x32.icobin0 -> 4286 bytes
-rw-r--r--docs/source/_static/img/round_logo_60x60.pngbin0 -> 5552 bytes
-rw-r--r--docs/source/_static/img/serial-monitor.pngbin0 -> 55975 bytes
-rw-r--r--docs/source/_static/img/serial-port-mac.pngbin0 -> 64284 bytes
-rw-r--r--docs/source/_static/img/serial-port-ubuntu.pngbin0 -> 46629 bytes
-rw-r--r--docs/source/_static/img/serial-port-win.pngbin0 -> 15183 bytes
-rw-r--r--docs/source/_static/img/upload-button.pngbin0 -> 9993 bytes
-rw-r--r--docs/source/_static/img/verify-success.pngbin0 -> 26460 bytes
-rw-r--r--docs/source/_static/img/verify_button.pngbin0 -> 1800 bytes
-rw-r--r--docs/source/_templates/.gitignore0
-rw-r--r--docs/source/_templates/layout.html5
-rw-r--r--docs/source/adc.rst81
-rw-r--r--docs/source/arm-gcc.rst70
-rw-r--r--docs/source/bootloader.rst682
-rw-r--r--docs/source/compatibility.rst266
-rw-r--r--docs/source/conf.py273
-rw-r--r--docs/source/epilog.rst8
-rw-r--r--docs/source/errata.rst140
-rw-r--r--docs/source/external-interrupts.rst119
-rw-r--r--docs/source/gpio.rst102
-rw-r--r--docs/source/hardware/maple-mini.rst6
-rw-r--r--docs/source/hardware/maple-native.rst6
-rw-r--r--docs/source/hardware/maple.rst104
-rw-r--r--docs/source/i2c.rst87
-rw-r--r--docs/source/ide.rst136
-rw-r--r--docs/source/index.rst86
-rw-r--r--docs/source/jtag.rst65
-rw-r--r--docs/source/lang/api/abs.rst49
-rw-r--r--docs/source/lang/api/analogread.rst119
-rw-r--r--docs/source/lang/api/analogwrite.rst173
-rw-r--r--docs/source/lang/api/attachinterrupt.rst115
-rw-r--r--docs/source/lang/api/bit.rst44
-rw-r--r--docs/source/lang/api/bitclear.rst44
-rw-r--r--docs/source/lang/api/bitread.rst46
-rw-r--r--docs/source/lang/api/bitset.rst46
-rw-r--r--docs/source/lang/api/bitwrite.rst46
-rw-r--r--docs/source/lang/api/cc-attribution.txt9
-rw-r--r--docs/source/lang/api/constants.rst337
-rw-r--r--docs/source/lang/api/constrain.rst69
-rw-r--r--docs/source/lang/api/cos.rst32
-rw-r--r--docs/source/lang/api/delay.rst72
-rw-r--r--docs/source/lang/api/delaymicroseconds.rst65
-rw-r--r--docs/source/lang/api/detachinterrupt.rst43
-rw-r--r--docs/source/lang/api/digitalread.rst58
-rw-r--r--docs/source/lang/api/digitalwrite.rst68
-rw-r--r--docs/source/lang/api/hardwarespi.rst152
-rw-r--r--docs/source/lang/api/hardwaretimer.rst370
-rw-r--r--docs/source/lang/api/highbyte.rst59
-rw-r--r--docs/source/lang/api/interrupts.rst47
-rw-r--r--docs/source/lang/api/isbuttonpressed.rst17
-rw-r--r--docs/source/lang/api/loop.rst45
-rw-r--r--docs/source/lang/api/lowbyte.rst25
-rw-r--r--docs/source/lang/api/map.rst68
-rw-r--r--docs/source/lang/api/max.rst65
-rw-r--r--docs/source/lang/api/micros.rst46
-rw-r--r--docs/source/lang/api/millis.rst52
-rw-r--r--docs/source/lang/api/min.rst66
-rw-r--r--docs/source/lang/api/nointerrupts.rst47
-rw-r--r--docs/source/lang/api/pinmode.rst79
-rw-r--r--docs/source/lang/api/pow.rst23
-rw-r--r--docs/source/lang/api/pwmwrite.rst55
-rw-r--r--docs/source/lang/api/random.rst73
-rw-r--r--docs/source/lang/api/randomseed.rst60
-rw-r--r--docs/source/lang/api/serial.rst226
-rw-r--r--docs/source/lang/api/serialusb.rst243
-rw-r--r--docs/source/lang/api/setup.rst29
-rw-r--r--docs/source/lang/api/sin.rst32
-rw-r--r--docs/source/lang/api/sq.rst46
-rw-r--r--docs/source/lang/api/tan.rst31
-rw-r--r--docs/source/lang/api/toggleled.rst17
-rw-r--r--docs/source/lang/api/togglepin.rst17
-rw-r--r--docs/source/lang/api/volatile.rst65
-rw-r--r--docs/source/lang/api/waitforbuttonpress.rst17
-rw-r--r--docs/source/lang/cc-attribution.txt9
-rw-r--r--docs/source/lang/cpp/arithmetic.rst127
-rw-r--r--docs/source/lang/cpp/array.rst123
-rw-r--r--docs/source/lang/cpp/assignment.rst60
-rw-r--r--docs/source/lang/cpp/bitshift.rst144
-rw-r--r--docs/source/lang/cpp/bitwisemath.rst186
-rw-r--r--docs/source/lang/cpp/boolean.rst91
-rw-r--r--docs/source/lang/cpp/booleanvariables.rst54
-rw-r--r--docs/source/lang/cpp/break.rst35
-rw-r--r--docs/source/lang/cpp/built-in-types.rst95
-rw-r--r--docs/source/lang/cpp/byte.rst34
-rw-r--r--docs/source/lang/cpp/bytecast.rst50
-rw-r--r--docs/source/lang/cpp/cc-attribution.txt9
-rw-r--r--docs/source/lang/cpp/char.rst50
-rw-r--r--docs/source/lang/cpp/charcast.rst36
-rw-r--r--docs/source/lang/cpp/comments.rst67
-rw-r--r--docs/source/lang/cpp/comparison.rst87
-rw-r--r--docs/source/lang/cpp/compoundarithmetic.rst44
-rw-r--r--docs/source/lang/cpp/compoundbitwise.rst230
-rw-r--r--docs/source/lang/cpp/const.rst52
-rw-r--r--docs/source/lang/cpp/continue.rst32
-rw-r--r--docs/source/lang/cpp/curly-braces.rst109
-rw-r--r--docs/source/lang/cpp/define.rst56
-rw-r--r--docs/source/lang/cpp/double.rst48
-rw-r--r--docs/source/lang/cpp/doublecast.rst27
-rw-r--r--docs/source/lang/cpp/dowhile.rst27
-rw-r--r--docs/source/lang/cpp/enum.rst52
-rw-r--r--docs/source/lang/cpp/float.rst50
-rw-r--r--docs/source/lang/cpp/floatcast.rst28
-rw-r--r--docs/source/lang/cpp/for.rst142
-rw-r--r--docs/source/lang/cpp/goto.rst130
-rw-r--r--docs/source/lang/cpp/if.rst121
-rw-r--r--docs/source/lang/cpp/include.rst72
-rw-r--r--docs/source/lang/cpp/increment.rst37
-rw-r--r--docs/source/lang/cpp/int.rst68
-rw-r--r--docs/source/lang/cpp/intcast.rst29
-rw-r--r--docs/source/lang/cpp/keywords.rst204
-rw-r--r--docs/source/lang/cpp/longcast.rst27
-rw-r--r--docs/source/lang/cpp/longlong.rst56
-rw-r--r--docs/source/lang/cpp/modulo.rst70
-rw-r--r--docs/source/lang/cpp/pointer.rst31
-rw-r--r--docs/source/lang/cpp/return.rst61
-rw-r--r--docs/source/lang/cpp/scope.rst120
-rw-r--r--docs/source/lang/cpp/semicolon.rst25
-rw-r--r--docs/source/lang/cpp/sizeof.rst64
-rw-r--r--docs/source/lang/cpp/sqrt.rst25
-rw-r--r--docs/source/lang/cpp/static.rst57
-rw-r--r--docs/source/lang/cpp/string.rst128
-rw-r--r--docs/source/lang/cpp/switchcase.rst118
-rw-r--r--docs/source/lang/cpp/unsignedchar.rst33
-rw-r--r--docs/source/lang/cpp/unsignedint.rst59
-rw-r--r--docs/source/lang/cpp/unsignedlonglong.rst43
-rw-r--r--docs/source/lang/cpp/variables.rst170
-rw-r--r--docs/source/lang/cpp/void.rst33
-rw-r--r--docs/source/lang/cpp/while.rst38
-rw-r--r--docs/source/lang/unimplemented/notone.rst50
-rw-r--r--docs/source/lang/unimplemented/pulsein.rst82
-rw-r--r--docs/source/lang/unimplemented/shiftout.rst136
-rw-r--r--docs/source/lang/unimplemented/stringclass.rst6
-rw-r--r--docs/source/lang/unimplemented/stringobject.rst89
-rw-r--r--docs/source/lang/unimplemented/tone.rst81
-rw-r--r--docs/source/language-index.rst40
-rw-r--r--docs/source/language.rst444
-rw-r--r--docs/source/libmaple.rst41
-rw-r--r--docs/source/libraries.rst194
-rw-r--r--docs/source/libs/servo.rst108
-rw-r--r--docs/source/maple-ide-install.rst162
-rw-r--r--docs/source/maple-quickstart.rst200
-rw-r--r--docs/source/prolog.rst7
-rw-r--r--docs/source/pwm.rst118
-rw-r--r--docs/source/specs.rst29
-rw-r--r--docs/source/spi.rst30
-rw-r--r--docs/source/timers.rst206
-rw-r--r--docs/source/troubleshooting.rst236
-rw-r--r--docs/source/unix-toolchain.rst423
-rw-r--r--docs/source/usart.rst34
-rw-r--r--docs/source/usb.rst45
-rw-r--r--examples/blinky.cpp12
-rw-r--r--examples/test-session.cpp959
-rw-r--r--libmaple/adc.c2
-rw-r--r--libmaple/adc.h13
-rw-r--r--libmaple/dac.c4
-rw-r--r--libmaple/dac.h4
-rw-r--r--libmaple/dma.c2
-rw-r--r--libmaple/exti.h8
-rw-r--r--libmaple/flash.h3
-rw-r--r--libmaple/fsmc.c4
-rw-r--r--libmaple/fsmc.h4
-rw-r--r--libmaple/gpio.c5
-rw-r--r--libmaple/gpio.h26
-rw-r--r--libmaple/libmaple.h115
-rw-r--r--libmaple/libmaple_types.h2
-rw-r--r--libmaple/rcc.h3
-rw-r--r--libmaple/spi.h1
-rw-r--r--libmaple/systick.c2
-rw-r--r--libmaple/timers.c90
-rw-r--r--libmaple/timers.h335
-rw-r--r--libmaple/usart.c17
-rw-r--r--libmaple/usart.h1
-rw-r--r--libmaple/usb/README84
-rw-r--r--libmaple/usb/descriptors.c48
-rw-r--r--libmaple/usb/descriptors.h25
-rw-r--r--libmaple/usb/usb.c272
-rw-r--r--libmaple/usb/usb.h93
-rw-r--r--libmaple/usb/usb_callbacks.c425
-rw-r--r--libmaple/usb/usb_callbacks.h11
-rw-r--r--libmaple/usb/usb_config.h1
-rw-r--r--libmaple/usb/usb_hardware.c183
-rw-r--r--libmaple/util.c2
-rw-r--r--libmaple/util.h4
-rw-r--r--libraries/LiquidCrystal/LiquidCrystal.cpp324
-rw-r--r--libraries/LiquidCrystal/LiquidCrystal.h105
-rw-r--r--libraries/LiquidCrystal/rules.mk29
-rw-r--r--libraries/Servo/Servo.cpp138
-rw-r--r--libraries/Servo/Servo.h116
-rw-r--r--libraries/Servo/rules.mk35
-rw-r--r--libraries/Wire/README5
-rw-r--r--libraries/Wire/Wire.cpp259
-rw-r--r--libraries/Wire/Wire.h99
-rw-r--r--libraries/Wire/rules.mk29
-rw-r--r--main.cpp.example28
-rw-r--r--notes/coding_standard.txt123
-rw-r--r--notes/native-pin-definitions.txt201
-rw-r--r--notes/pin-mapping.txt101
-rw-r--r--support/ld/maple_mini/flash.ld211
-rw-r--r--support/ld/maple_mini/jtag.ld186
-rw-r--r--support/ld/maple_mini/ram.ld220
-rw-r--r--support/ld/maple_native/flash.ld2
-rw-r--r--support/ld/maple_native/jtag.ld4
-rw-r--r--support/openocd/flash_0.4.0.cfg89
-rw-r--r--support/openocd/run_0.4.0.cfg75
-rwxr-xr-xsupport/scripts/copy-to-ide42
-rwxr-xr-xsupport/stm32loader.py28
-rw-r--r--wirish/HardwareTimer.cpp167
-rw-r--r--wirish/HardwareTimer.h368
-rw-r--r--wirish/bit_constants.h579
-rw-r--r--wirish/bits.h74
-rw-r--r--wirish/boards.h514
-rw-r--r--wirish/comm/HardwareSPI.h23
-rw-r--r--wirish/comm/HardwareSerial.cpp11
-rw-r--r--wirish/comm/HardwareSerial.h15
-rw-r--r--wirish/ext_interrupts.c20
-rw-r--r--wirish/ext_interrupts.h72
-rw-r--r--wirish/io.h213
-rw-r--r--wirish/pwm.c6
-rw-r--r--wirish/pwm.h14
-rw-r--r--wirish/time.c1
-rw-r--r--wirish/time.h42
-rw-r--r--wirish/usb_serial.cpp16
-rw-r--r--wirish/wirish.c5
-rw-r--r--wirish/wirish.h4
-rw-r--r--wirish/wirish_digital.c53
-rw-r--r--wirish/wirish_math.cpp5
-rw-r--r--wirish/wirish_math.h103
256 files changed, 20379 insertions, 1656 deletions
diff --git a/.gitignore b/.gitignore
index fba4237..7e29a09 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,10 @@
build/
+docs/build/
main.cpp
libmaple.layout
tags
TAGS
*~
-*.swp \ No newline at end of file
+*.swp
+docs/doxygen/
+arm
diff --git a/Makefile b/Makefile
index 4fd5ade..9bf0c9d 100644
--- a/Makefile
+++ b/Makefile
@@ -17,6 +17,10 @@ ifeq ($(BOARD), maple_native)
MCU := STM32F103ZE
PRODUCT_ID := 0003
endif
+ifeq ($(BOARD), maple_mini)
+ MCU := STM32F103CB
+ PRODUCT_ID := 0003
+endif
# Useful paths
ifeq ($(LIB_MAPLE_HOME),)
@@ -62,6 +66,10 @@ endif
# Set all submodules here
LIBMAPLE_MODULES := $(SRCROOT)/libmaple
LIBMAPLE_MODULES += $(SRCROOT)/wirish
+# Official libraries:
+LIBMAPLE_MODULES += $(SRCROOT)/libraries/Servo
+LIBMAPLE_MODULES += $(SRCROOT)/libraries/LiquidCrystal
+LIBMAPLE_MODULES += $(SRCROOT)/libraries/Wire
# call each module rules.mk
$(foreach m,$(LIBMAPLE_MODULES),$(eval $(call LIBMAPLE_MODULE_template,$(m))))
diff --git a/README b/README
index 5e88e11..b7dd521 100644
--- a/README
+++ b/README
@@ -70,3 +70,11 @@ maple-library folder (macosx and windows).
Write your program using /main.cpp as the entry point. Then just 'make help'
and follow the directions!
+Instructions to create a library
+------------------------------------------------------------------------------
+If you have a complicated project with its own Makefile and multiple .c files,
+or you're using an IDE that creates its own Makefile, you'll probably want to
+load libmaple from an archive (a build-time library, not a DLL). Use the
+"make library" target, and install build/libmaple.a and the appropriate headers
+in your project's directory. At a minimum, the header set will include
+libmaple.h, util.h, and libmaple_types.h
diff --git a/TODO b/TODO
index 3829be2..af8ef80 100644
--- a/TODO
+++ b/TODO
@@ -2,10 +2,11 @@ Quick TODO --------------------------------------------------------------------
- write language unit test
- more maple-specific example programs
+- maple mini serial bootloader HOWTO
+- maple and mini jtag HOWTO
Peripherals -------------------------------------------------------------------
-- complete timers and interrupt stuff
- I2C wrap up
- SPI wrap up
@@ -16,9 +17,6 @@ EEPROM:
uint8 read(int)
void write(int, uint8)
-Servo:
- modify timer code, "banks" of pins corresponding to a timer
-
Firmata:
edit Firmata.h for capabilities
diff --git a/build-targets.mk b/build-targets.mk
index 448b1ee..0718b15 100644
--- a/build-targets.mk
+++ b/build-targets.mk
@@ -2,6 +2,14 @@
$(BUILD_PATH)/main.o: main.cpp
$(SILENT_CXX) $(CXX) $(CFLAGS) $(CXXFLAGS) $(LIBMAPLE_INCLUDES) $(WIRISH_INCLUDES) -o $@ -c $<
+$(BUILD_PATH)/libmaple.a: $(BUILDDIRS) $(TGT_BIN)
+ - rm -f $@
+ $(AR) crv $(BUILD_PATH)/libmaple.a $(TGT_BIN)
+
+library: $(BUILD_PATH)/libmaple.a
+
+.PHONY: library
+
$(BUILD_PATH)/$(BOARD).elf: $(BUILDDIRS) $(TGT_BIN) $(BUILD_PATH)/main.o
$(SILENT_LD) $(CXX) $(LDFLAGS) -o $@ $(TGT_BIN) $(BUILD_PATH)/main.o
diff --git a/docs/Doxyfile b/docs/Doxyfile
new file mode 100644
index 0000000..3290843
--- /dev/null
+++ b/docs/Doxyfile
@@ -0,0 +1,1633 @@
+# Doxyfile 1.7.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = libmaple
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = custom-build
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = ./doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES = "sideeffect=\par Side Effects:\n"
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = YES
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ../libmaple/ \
+ ../wirish/
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvances is that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = ALWAYS_INLINE= \
+ __cplusplus
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans.ttf
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = NO
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = NO
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = NO
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..eb14c90
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,133 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest doxygen
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml: doxygen
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml: doxygen
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle: doxygen
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json: doxygen
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp: doxygen
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp: doxygen
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/libmaple.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/libmaple.qhc"
+
+devhelp: doxygen
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/libmaple"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/libmaple"
+ @echo "# devhelp"
+
+epub: doxygen
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex: doxygen
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf: doxygen
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ make -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text: doxygen
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man: doxygen
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes: doxygen
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck: doxygen
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest: doxygen
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
+
+doxygen:
+ doxygen
diff --git a/docs/README b/docs/README
new file mode 100644
index 0000000..326d278
--- /dev/null
+++ b/docs/README
@@ -0,0 +1,83 @@
+This directory contains the Sphinx documentation for libmaple, as well
+as a Doxygen configuration file; we turn Doxygen XML output into
+Sphinx documentation. You can generate HTML documentation using the
+Makefile if you have make, or using make.bat from Windows.
+
+Documentation Build Steps
+-------------------------
+
+1. You need a recent-ish version of Doxygen in your PATH:
+
+ http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc
+
+2. Install breathe, which does Doxygen-to-Sphinx conversion:
+
+ Read/write version (for LeafLabs developers):
+
+ $ git clone git@github.com:leaflabs/breathe.git
+
+ Read-only version (for non-LeafLabs developers):
+
+ $ git clone git://github.com/leaflabs/breathe.git
+
+ After that's done, set an environment variable BREATHE_HOME to
+ point to where you downloaded it. Something like this on bash:
+
+ $ export BREATHE_HOME=/path/to/breathe/repo/
+
+ (You'll want to put this in your shell startup script).
+
+3. Install Sphinx.
+
+ From source or .egg:
+
+ http://pypi.python.org/pypi/Sphinx#downloads
+
+ Via easy_install:
+
+ $ sudo easy_install -U Sphinx
+
+4. Before the first time you run Sphinx (and any time the Doxygen
+ comments in the libmaple source code are changed), you'll need to
+ rebuild the Doxygen XML output:
+
+ $ cd libmaple/docs/source
+ $ doxygen
+
+5. Finally, you can build the documentation:
+
+ $ make html
+
+ (Read the Makefile for more targets).
+
+Reading and Modifying the Documentation
+---------------------------------------
+
+The net effect of the above is to produce Doxygen XML output (ignore
+this) in libmaple/docs/doxygen/xml, and HTML documentation (this is
+what you want) in libmaple/docs/build/html.
+
+Just point your web browser at the file
+
+ libmaple/docs/build/html/index.html
+
+it corresponds to the Sphinx file
+
+ libmaple/docs/source/index.rst
+
+All of the documentation itself lives in libmaple/docs/source/. The
+directory source/_static/ is for static content (like style sheets);
+source/_templates/ contains Sphinx templates (or, it would, if we had
+any).
+
+The docs are written in Sphinx's version of reStructuredText (reST);
+it's a Python thing that they use to produce the docs at
+http://python.org. You can read more about Sphinx here:
+
+ http://sphinx.pocoo.org/tutorial.html
+
+You can view the source for any generated page of documentation by
+clicking the "Show Source" link in the sidebar.
+
+The file libmaple/docs/source/conf.py is the Sphinx configuration
+file; you can go read it for more information about our setup.
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 0000000..1833a4b
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,155 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\libmaple.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\libmaple.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
diff --git a/docs/source/_static/.gitignore b/docs/source/_static/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/docs/source/_static/.gitignore
diff --git a/docs/source/_static/apilist.html b/docs/source/_static/apilist.html
new file mode 100644
index 0000000..e9eb8e3
--- /dev/null
+++ b/docs/source/_static/apilist.html
@@ -0,0 +1,5 @@
+{# Filename: .static/apilist.html #}
+{% set parents = parents.pop() %}
+{% if parents %}
+<a href="{{ parents.link|e }}">{{ parents.title }}</a>
+{% endif %} \ No newline at end of file
diff --git a/docs/source/_static/img/blinky-to-flash.png b/docs/source/_static/img/blinky-to-flash.png
new file mode 100644
index 0000000..0320c5b
--- /dev/null
+++ b/docs/source/_static/img/blinky-to-flash.png
Binary files differ
diff --git a/docs/source/_static/img/blinky.png b/docs/source/_static/img/blinky.png
new file mode 100644
index 0000000..bda4cee
--- /dev/null
+++ b/docs/source/_static/img/blinky.png
Binary files differ
diff --git a/docs/source/_static/img/button-new.png b/docs/source/_static/img/button-new.png
new file mode 100644
index 0000000..3fd98be
--- /dev/null
+++ b/docs/source/_static/img/button-new.png
Binary files differ
diff --git a/docs/source/_static/img/button-open.png b/docs/source/_static/img/button-open.png
new file mode 100644
index 0000000..466fc10
--- /dev/null
+++ b/docs/source/_static/img/button-open.png
Binary files differ
diff --git a/docs/source/_static/img/button-save.png b/docs/source/_static/img/button-save.png
new file mode 100644
index 0000000..7eba286
--- /dev/null
+++ b/docs/source/_static/img/button-save.png
Binary files differ
diff --git a/docs/source/_static/img/button-serial-monitor.png b/docs/source/_static/img/button-serial-monitor.png
new file mode 100644
index 0000000..aec9741
--- /dev/null
+++ b/docs/source/_static/img/button-serial-monitor.png
Binary files differ
diff --git a/docs/source/_static/img/button-stop.png b/docs/source/_static/img/button-stop.png
new file mode 100644
index 0000000..4812ae9
--- /dev/null
+++ b/docs/source/_static/img/button-stop.png
Binary files differ
diff --git a/docs/source/_static/img/button-upload.png b/docs/source/_static/img/button-upload.png
new file mode 100644
index 0000000..0f41eeb
--- /dev/null
+++ b/docs/source/_static/img/button-upload.png
Binary files differ
diff --git a/docs/source/_static/img/button-verify.png b/docs/source/_static/img/button-verify.png
new file mode 100644
index 0000000..95abeb8
--- /dev/null
+++ b/docs/source/_static/img/button-verify.png
Binary files differ
diff --git a/docs/source/_static/img/codeblocks_build.png b/docs/source/_static/img/codeblocks_build.png
new file mode 100644
index 0000000..c98bcdc
--- /dev/null
+++ b/docs/source/_static/img/codeblocks_build.png
Binary files differ
diff --git a/docs/source/_static/img/codeblocks_makefile.png b/docs/source/_static/img/codeblocks_makefile.png
new file mode 100644
index 0000000..a0ef21f
--- /dev/null
+++ b/docs/source/_static/img/codeblocks_makefile.png
Binary files differ
diff --git a/docs/source/_static/img/codeblocks_maketargets.png b/docs/source/_static/img/codeblocks_maketargets.png
new file mode 100644
index 0000000..bbb68cb
--- /dev/null
+++ b/docs/source/_static/img/codeblocks_maketargets.png
Binary files differ
diff --git a/docs/source/_static/img/codeblocks_newproject.png b/docs/source/_static/img/codeblocks_newproject.png
new file mode 100644
index 0000000..8d08d1f
--- /dev/null
+++ b/docs/source/_static/img/codeblocks_newproject.png
Binary files differ
diff --git a/docs/source/_static/img/ide-blinky.png b/docs/source/_static/img/ide-blinky.png
new file mode 100644
index 0000000..3cccdb4
--- /dev/null
+++ b/docs/source/_static/img/ide-blinky.png
Binary files differ
diff --git a/docs/source/_static/img/jtag-wiring.png b/docs/source/_static/img/jtag-wiring.png
new file mode 100644
index 0000000..8f31f99
--- /dev/null
+++ b/docs/source/_static/img/jtag-wiring.png
Binary files differ
diff --git a/docs/source/_static/img/libmaple-screenshot-small.png b/docs/source/_static/img/libmaple-screenshot-small.png
new file mode 100644
index 0000000..f2be783
--- /dev/null
+++ b/docs/source/_static/img/libmaple-screenshot-small.png
Binary files differ
diff --git a/docs/source/_static/img/osx-network-prefs-unconfigured.png b/docs/source/_static/img/osx-network-prefs-unconfigured.png
new file mode 100644
index 0000000..70d2fa0
--- /dev/null
+++ b/docs/source/_static/img/osx-network-prefs-unconfigured.png
Binary files differ
diff --git a/docs/source/_static/img/osx-unconfigured-popup.png b/docs/source/_static/img/osx-unconfigured-popup.png
new file mode 100644
index 0000000..a43ad57
--- /dev/null
+++ b/docs/source/_static/img/osx-unconfigured-popup.png
Binary files differ
diff --git a/docs/source/_static/img/round_logo_32x32.ico b/docs/source/_static/img/round_logo_32x32.ico
new file mode 100644
index 0000000..29fb2bf
--- /dev/null
+++ b/docs/source/_static/img/round_logo_32x32.ico
Binary files differ
diff --git a/docs/source/_static/img/round_logo_60x60.png b/docs/source/_static/img/round_logo_60x60.png
new file mode 100644
index 0000000..dacd36a
--- /dev/null
+++ b/docs/source/_static/img/round_logo_60x60.png
Binary files differ
diff --git a/docs/source/_static/img/serial-monitor.png b/docs/source/_static/img/serial-monitor.png
new file mode 100644
index 0000000..6162dab
--- /dev/null
+++ b/docs/source/_static/img/serial-monitor.png
Binary files differ
diff --git a/docs/source/_static/img/serial-port-mac.png b/docs/source/_static/img/serial-port-mac.png
new file mode 100644
index 0000000..b3a1989
--- /dev/null
+++ b/docs/source/_static/img/serial-port-mac.png
Binary files differ
diff --git a/docs/source/_static/img/serial-port-ubuntu.png b/docs/source/_static/img/serial-port-ubuntu.png
new file mode 100644
index 0000000..8038e41
--- /dev/null
+++ b/docs/source/_static/img/serial-port-ubuntu.png
Binary files differ
diff --git a/docs/source/_static/img/serial-port-win.png b/docs/source/_static/img/serial-port-win.png
new file mode 100644
index 0000000..90dc1c4
--- /dev/null
+++ b/docs/source/_static/img/serial-port-win.png
Binary files differ
diff --git a/docs/source/_static/img/upload-button.png b/docs/source/_static/img/upload-button.png
new file mode 100644
index 0000000..20a663f
--- /dev/null
+++ b/docs/source/_static/img/upload-button.png
Binary files differ
diff --git a/docs/source/_static/img/verify-success.png b/docs/source/_static/img/verify-success.png
new file mode 100644
index 0000000..6928674
--- /dev/null
+++ b/docs/source/_static/img/verify-success.png
Binary files differ
diff --git a/docs/source/_static/img/verify_button.png b/docs/source/_static/img/verify_button.png
new file mode 100644
index 0000000..37100db
--- /dev/null
+++ b/docs/source/_static/img/verify_button.png
Binary files differ
diff --git a/docs/source/_templates/.gitignore b/docs/source/_templates/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/docs/source/_templates/.gitignore
diff --git a/docs/source/_templates/layout.html b/docs/source/_templates/layout.html
new file mode 100644
index 0000000..93547f0
--- /dev/null
+++ b/docs/source/_templates/layout.html
@@ -0,0 +1,5 @@
+{% extends "!layout.html" %}
+{% block rootrellink %}
+ <li><a href="http://leaflabs.com/">LeafLabs</a> |</li>
+ {{ super() }}
+{% endblock %}
diff --git a/docs/source/adc.rst b/docs/source/adc.rst
new file mode 100644
index 0000000..6bbbac2
--- /dev/null
+++ b/docs/source/adc.rst
@@ -0,0 +1,81 @@
+.. _adc:
+
+=====
+ ADC
+=====
+
+Analog-Digital Conversion is the process of reading a physical voltage
+as a number. The Maple has a large number of pins which are capable of
+taking 12-bit ADC measurements, which means that voltages from ground
+to +3.3v are read as numbers from 0 to 4095; this corresponds to a
+theoretical sensitivity of just under 1 millivolt. In reality, a
+number of factors introduce noise and bias into this reading and a
+number of techniques must be used to get good precision and accuracy.
+
+.. compound::
+
+ The header pins with ADC functionality (marked as "AIN" on the
+ silkscreen) are:
+
+ D0, D1, D2, D3, D10, D11, D12, D13, D15, D16, D17, D18, D19, D20, D27, D28
+
+ Note that pins 3, 27, and 28 are not marked AIN on the silkscreen
+ for Maple revisions through Rev 5, however, they **do work** as
+ analog input pins.
+
+.. contents:: Contents
+ :local:
+
+.. _adc-noise-bias:
+
+Noise and Bias
+--------------
+
+The biggest issues with analog-digital conversion are noise and bias.
+With the Maple, we have tried to isolate the ADC pins and traces from
+strong noise sources but there are always trade--offs between noise,
+additional functionality, cost, and package size.
+
+The 6 ADC pins in a bank (D15--D20) generally have the least
+noise and should be used for fine measurements. If the input voltage
+changes relatively slowly, a number of samples can be taken in
+succession and averaged together, or the same voltage can even be
+sampled by multiple ADC pins at the same time.
+
+An important factor when taking a voltage reading is the reference
+voltages that the sample is being compared against. In the case of the
+Maple, the high reference is |vcc| and the low reference is ground.
+This means that noise or fluctuations on either |vcc| or ground will
+affect the measurement. It also means that the voltage you are trying
+to sample must be between ground and 3.3V. In the case of a variable
+reading, it is best if the voltage varies over the entire range of
+0--3.3V; otherwise, only a fraction of the sensitivity is being
+leveraged. Resistor dividers and constant voltage diodes are basic
+tools which can help bring a given voltage signal into the appropriate
+range; opamps and other powered components can also be used.
+
+.. _adc-function-reference:
+
+Function Reference
+------------------
+
+.. doxygenfunction:: analogRead
+
+.. doxygenfunction:: pinMode
+
+.. doxygenenum:: WiringPinMode
+
+.. _adc-recommended-reading:
+
+Recommended Reading
+-------------------
+
+* `Wikipedia article on Analog-to-digital converter <http://en.wikipedia.org/wiki/Analog-to-digital_converter>`_
+* `Arduino Analog Input Tutorial <http://arduino.cc/en/Tutorial/AnalogInputPins>`_
+* 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 ADC Modes (pdf) <http://www.st.com/stonline/products/literature/an/16840.pdf>`_
+ * `Application Note on ADC Oversampling (pdf) <http://www.st.com/stonline/products/literature/an/14183.pdf>`_
diff --git a/docs/source/arm-gcc.rst b/docs/source/arm-gcc.rst
new file mode 100644
index 0000000..ef745f5
--- /dev/null
+++ b/docs/source/arm-gcc.rst
@@ -0,0 +1,70 @@
+
+.. _arm-gcc:
+
+GCC for Maple
+=============
+
+This document provides notes on the current usage of
+``arm-none-eabi-gcc``, the `CodeSourcery <http://codesourcery.com>`_
+version of the GNU `GCC <http://gcc.gnu.org/>`_ compilers used to
+compile programs for the Maple. It is not intended as a reference
+manual for GCC; such manuals are available `elsewhere
+<http://gcc.gnu.org/>`_.
+
+Obtaining ``arm-none-eabi-gcc``
+-------------------------------
+
+Recent versions of ``arm-none-eabi-gcc`` and associated tools are
+included with the :ref:`Maple IDE <ide>`.
+
+Users who wish to use ``arm-none-eabi-gcc`` in concert with a standard
+Unix toolchain are referred to our :ref:`unix-toolchain` reference,
+which describes how to set up such an environment.
+
+LeafLabs mirrors some of the more recent versions of the compiler
+under http://static.leaflabs.com/pub/codesourcery/\ , including
+versions for OS X, win32, and 32-bit Linux.
+
+Compiler Flags Used by libmaple
+-------------------------------
+
+This section documents the flags passed to ``arm-none-eabi-gcc`` by
+the :ref:`Maple IDE <ide>` and the default Makefile provided with
+:ref:`libmaple <unix-toolchain>`. The information in this section is
+subject to change without notice.
+
+.. highlight:: sh
+
+The following flags are among those passed to the C compiler::
+
+ -Os -g -mcpu=cortex-m3 -mthumb -march=armv7-m -nostdlib
+ -ffunction-sections -fdata-sections -Wl,--gc-sections
+
+The following flags are among those passed to the C++ compiler::
+
+ -fno-rtti -fno-exceptions -Wall
+
+The following flags are among those passed to the assembler::
+
+ -mcpu=cortex-m3 -march=armv7-m -mthumb
+
+.. highlight:: cpp
+
+.. _arm-gcc-avr-gcc:
+
+Switching from AVR-GCC
+----------------------
+
+This section, which is expected to grow over time, describes
+techniques for porting code which uses AVR-GCC features (AVR-GCC is
+the compiler used by many Atmel AVR-based microcontroller boards,
+including Arduino) for use on the Maple.
+
+.. _arm-gcc-attribute-flash:
+
+- Replacing ``PROGMEM``: You can direct the linker script provided
+ with libmaple to store a variable in flash by using
+ ``__attribute__((section (".USER_FLASH")))``, like so::
+
+ uint32 arr[] __attribute__((section (".USER_FLASH"))) = {...};
+
diff --git a/docs/source/bootloader.rst b/docs/source/bootloader.rst
new file mode 100644
index 0000000..57833ed
--- /dev/null
+++ b/docs/source/bootloader.rst
@@ -0,0 +1,682 @@
+.. highlight:: sh
+
+=====================
+ Maple Bootloader(s)
+=====================
+
+.. TODO: add a section on flashing your own bootloader
+
+The firmware which allows the Maple to be reprogrammed via a USB
+connection. Every Maple board comes programmed with this by default,
+and it is not overwritten by regular programs (it lives lower in the
+Flash memory and only runs when the chip is reset).
+
+**Check out the latest source code version:** ::
+
+ git clone git://github.com/leaflabs/maple-bootloader.git
+
+**Visit the github development project**: http://github.com/leaflabs/maple-bootloader
+
+.. contents:: Contents
+ :local:
+
+Bootloader Schemes Explained
+----------------------------
+
+Maple Rev 3 and Rev 5 (Rev 5 is the version currently shipping)
+represents a drastic remake of the core library as well as the upload
+process. Thes changes to the bootloader, were implemented to resolve
+platform-specific issues on Windows. Before delving into how the Rev
+1 bootloader worked and how the Rev 5 bootloader works now, we'll
+discuss the features common to each and touch a bit on the Arduino
+setup.
+
+This is a fairly involved explanation, with a lot of details that are
+likely only interesting to a few. If you just want to get the rough
+idea, skim this article. If you want to start hacking on the
+bootloader, get in touch with us to get even more info on how this all
+works. And finally, you can always `check out the code at github
+<http://github.com/leaflabs/libmaple>`_!
+
+Arduino
+-------
+
+Arduino is based off of AVR series microcontrollers, most of which
+lack USB support. Thus, boards like the Duemilanove add USB capability
+via an FTDI USB-to-Serial converter chip. This chip interfaces with
+the AVR over an RS-232 serial interface. When you plug an Arduino into
+a computer, only an FTDI driver is needed. Since the FTDI chip is
+separate from the AVR, you can reset the Arduino without closing this
+USB connection with the FTDI chip.
+
+To program an Arduino, the host machine sends a command over the USB
+pipe (reset DTR) which in turn resets the AVR. The AVR will boot into
+a bootloader, which waits for a second for any upload commands over
+serial. The host machine can either send those commands, or do
+nothing. If it does nothing, the AVR will quickly jump to user code
+and off you go. The whole process is quick, the bootloader doesn’t
+live for very long, and will exit almost immediately if no upload
+commands are received.
+
+Maple Rev 1
+-----------
+
+Maple is based off the STM32 (ARM cortex M3) series chips, which do
+have embedded USB support. Thus, Maple doesn’t need the extra FTDI
+chip. Firmware is uploaded via the standard DFU protocol (also used by
+iPhone and openMoko). Since DFU is a standard, there is no need for
+custom software running on the host to upload the firmware. Any DFU
+compliant program will work. The maple ide is based around
+:command:`dfu-util`, openMoko’s DFU utility. Using DFU came at a cost,
+however. The USB port must additionally implement a separate serial
+port at the same time (we use the CDC ACM class for serial
+functionality).
+
+Maple Rev 1 attempted to run both DFU and CDC ACM devices
+simultaneously on the USB peripheral. On Linux, this worked great. The
+OS would service the DFU driver during uploads, and the CDC ACM for
+serial port transactions. There was no reset necessary for uploads. No
+waiting. The bootloader was always running the background, ready to
+receive commands.
+
+The problem was that *only* Linux did this. Windows refused to attach
+more than one driver to a single USB device without repackaging the
+DFU and CDC ACM into a single IAD Compound Device. It's not terribly
+important what this means, except for two things.
+
+1. Four drivers were necessary to make everything work.
+2. IAD is not supported by OS X.
+
+Mac, on the other hand, only supported Compound USB, a different trick
+that is not supported by Windows. While a perpetual background
+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/Rev5 - DFU
+---------------------
+
+Maple Rev 3 takes a completely different tack, more along the lines of
+Arduino. In Rev 3, the device resets into bootloader mode, which
+stays alive for a few moments to receive commands, and then jumps to
+user code. The bootloader is implemented as a DFU device -- just a DFU
+device, no serial port. This requires one driver for Windows
+(:file:`drivers/mapleDrv/dfu` in the Windows IDE directory). As part
+of the :ref:`libmaple <libmaple>` library, user code is automatically
+supplied with serial support via some behind the scenes work that
+happens automatically when you compile (``setupUSB()`` is appended to
+``setup()``). This user mode code only implements a CDC ACM class USB
+device, giving you functions like ``Usb.print()``. Separating these
+two modes fixed the driver issue, required no complicated compound USB
+device nonsense, and works well across platforms, requiring only two
+drivers (serial and DFU) on Windows.
+
+However, it is no longer possible to upload code at will, since there
+is no bootloader quietly listening in the background. Instead you have
+to reset the board, then initiate a DFU transaction. This reset is
+performed automatically by the IDE by sending a command over the USB
+serial port. You can generate this reset on your own using a Python
+script or some other scheme. All you need do is:
+
+1. Pulse DTR (high and then low, so that you've created a negative
+ edge)
+2. Write "1EAF" in ASCII over the serial pipe. This will cause Maple
+ to reset. Only the first 4 bytes after a negative edge of DTR are
+ checked for this command, so it's important you actually create a
+ negative edge, rather than just ensuring DTR is low.
+
+After the reset, the host OS takes a few moments (.5-2 seconds) to
+re-enumerate the device as DFU. This delay is unpredictable, and its
+the reason the bootloader on Maple Rev3 stays alive for so
+long. Sometimes the bootloader was exiting before the OS had even
+enumerated the device! Once in bootloader mode, however,
+:command:`dfu-util` uploads your sketch into either flash or RAM (DFU
+alternate setting 0 or 1, respectively) and resets the board again.
+This time, however, no DFU transaction is initiated, and the
+bootloader gives way to user code, closing down the DFU pipe and
+bringing up the USB serial.
+
+.. .. _bootloader-rev6:
+
+.. Maple Rev6 - The Serial Bootloader (Tentative)
+.. ----------------------------------------------
+
+.. .. note:: This section documents an in-progress version of the Maple
+.. bootloader. **No Maples yet sold use this bootloader protocol**.
+.. It has not been yet been publicly released, and its interface is
+.. not stable.
+
+.. The bootloader in Rev3/Rev5 works well on Linux, acceptably on Mac,
+.. but was unsatisfactory on Windows. Unlike the other operating systems,
+.. Windows needed to be manually pointed to both the driver to use for
+.. programming (DFU, via `libusb <http://www.libusb.org/>`_) and the
+.. driver to use for serial communication (usbser.sys, built in to
+.. Windows). Since Maple operates in only one of these modes at a time,
+.. driver installation was unnecessarily complicated. It was necessary to
+.. bring Maple into the correct mode before installing each of the
+.. drivers. Furthermore, because libusb is not bundled with Windows, and
+.. its driver is not signed, Windows 7 users have been forced to
+.. laboriously disable driver signing checks. Finally, Windows hates the
+.. constant switching of the device between Serial and DFU modes (during
+.. programming), and often prompts users to install drivers that are
+.. already installed. We have therefore decided to abandon DFU.
+
+.. In our new bootloader scheme, Maple is simply a serial device.
+.. Windows comes bundled with usbser.sys, so no driver signing is
+.. required. The IDE installation process is greatly simplified, there
+.. is no more switching back and forth between "modes", and we can build
+.. in new functionality outside the DFU spec.
+
+.. The first incarnation of this serial-only bootloader leaves libmaple
+.. and user code untouched. However, during programming, instead of
+.. calling :command:`dfu-util` to upload code we will now call a newly
+.. written utility script similar to `avr-dude
+.. <http://savannah.nongnu.org/projects/avrdude/>`_. The high level
+.. operation of the bootloader will remain the same - come on at startup,
+.. wait for an upload operation or timeout, and jump to user code.
+
+.. The second version of this bootloader will eliminate this dependence
+.. on resetting and timing out by having the bootloader run in the
+.. background. It will additionally own the serial port. In this scheme,
+.. sending data over the COM port while DTR is pulled low results in that
+.. packet being captured by the bootloader and interpreted as a
+.. bootloader command. When the user uploads a new program, the
+.. bootloader will overwrite the old one, reset the various peripheral
+.. registers, and jump to user code. All of this will occur without
+.. resetting the chip and thus causing Maple to connect and disconnect
+.. from your computer (which seems to cause many problems).
+
+.. The final version of this bootloader scheme will involve a separate
+.. microcontroller, whose responsibilities are to drive the USB port,
+.. program the main processor, and offer some amount of debugging
+.. capability. This will allow user sketches to run on the bare metal of
+.. the main processor, without any bootloader hiding underneath. This
+.. approach is similar to the approaches taken by mbed and the Arduino
+.. Uno.
+
+.. Regardless of which generation of the new serial bootloader you are
+.. working with, the command interface is the same. The low level
+.. communication protocol is inspired by STK-500, the protocol used to
+.. program many AVR-based development boards. The protocol is a
+.. packetized query-response scheme. The host PC initiates every
+.. transaction, and for every query sent to the bootloader, a single
+.. response will be returned (or the system times out). Data is
+.. transmitted over 115.2kbps, 8 data bits, 1 stop bit, no parity
+.. bit. Every query or response follows the same packet format that looks
+.. like this:
+
+.. .. _bootloader-packet-structure:
+
+.. Packet Structure
+.. ^^^^^^^^^^^^^^^^
+
+.. A bootloader packet is composed of a sequence of fields, as follows.
+
+.. .. list-table::
+.. :header-rows: 1
+
+.. * - Field
+.. - Length (bytes)
+.. - Value
+.. - Description
+
+.. * - START
+.. - 1
+.. - 0x1B
+.. - Magic constant, indicates bootloader packet
+
+.. * - SEQUENCE_NUM
+.. - 1
+.. - 0--0xFF
+.. - Queries and responses must have the same sequence number; rolls
+.. over to 0 after 0xFF
+
+.. * - MESSAGE_SIZE
+.. - 2
+.. - 0--0xFFFF
+.. - Size of message body, currently limited to a 1024B=1KB maximum
+
+.. * - TOKEN
+.. - 1
+.. - 0x7F
+.. - Differs from STK500 value of 0x0E
+
+.. * - MESSAGE_BODY
+.. - Variable, determined by MESSAGE_SIZE field
+.. - Command query or response
+.. - See :ref:`next section <bootloader-commands>`
+
+.. * - CHECKSUM
+.. - 4
+.. - XOR of all other 32-bit words in packet
+.. - See :ref:`below <bootloader-checksum>`
+
+.. .. _bootloader-checksum:
+
+.. .. highlight:: cpp
+
+.. .. note:: When computing the checksum, the words in a packet are
+.. interpreted big-endian (as if the packet were a sequence of 32-bit,
+.. big-endian unsigned integers). If the end of the MESSAGE_BODY is
+.. not aligned with a four-byte boundary, then the checksum will treat
+.. it as if it was padded with zero bytes to a four-byte boundary.
+
+.. As a concrete example, an entire GET_INFO query (see :ref:`below
+.. <bootloader-get-info>`), including the packet structure, is
+.. comprised of the byte sequence ::
+
+.. {0x1B, 0x7F, 0x00, 0x01, 0x7F, 0x00, 0x64, 0x7F, 0x00, 0x01}
+
+.. The SEQUENCE_NUM of this query is 0x7F.
+
+.. .. highlight:: sh
+
+.. .. _bootloader-commands:
+
+.. Commands
+.. ^^^^^^^^
+
+.. The packet structure overhead is for reliability. The actual queries
+.. and responses are transacted inside of the message body. Following
+.. the STK-500 protocol, each query or response begins with the single
+.. byte command field. For each query, the resultant response must begin
+.. with the same CMD byte. For each type of command, the structure of
+.. queries and responses is of fixed size.
+
+.. Also following STK-500, fields longer than 1 byte are transmitted MSB
+.. first (big-endian). However, READ and WRITE commands operate byte-wise
+.. (not word-wise); it is up to the host PC to ensure that alignment and
+.. ordering issues are handled appropriately.
+
+.. .. _bootloader-get-info:
+
+.. GET_INFO
+.. """"""""
+
+.. Used to query device characteristics.
+
+.. GET_INFO Query:
+
+.. .. list-table::
+.. :header-rows: 1
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - GET_INFO
+.. - 1
+.. - Value 0
+
+.. GET_INFO Response:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 4 2 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - GET_INFO
+.. - 1
+.. - Value 0
+
+.. * - Endianness
+.. - 1
+.. - 0 indicates little-endian, 1 indicates big-endian.
+.. (Currently returns 0; this field allows for future
+.. expansion).
+
+.. * - Available Ram
+.. - 4
+.. - In bytes
+
+.. * - Available Flash
+.. - 4
+.. - In bytes
+
+.. * - Flash Page Size
+.. - 2
+.. - In bytes
+
+.. * - Starting Address (FLASH)
+.. - 4
+.. - Usually 0x08005000
+
+.. * - Starting Address (RAM)
+.. - 4
+.. - Usually 0x200000C0
+
+.. * - Bootloader Version
+.. - 4
+.. - Current version 0x00060000 (MAJ,MIN)
+
+.. .. _bootloader-erase-page:
+
+.. ERASE_PAGE
+.. """"""""""
+
+.. Used to erase flash pages.
+
+.. ERASE_PAGE query:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 4 2 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - ERASE_PAGE
+.. - 1
+.. - Value 1
+
+.. * - ADDRESS
+.. - 4
+.. - Will erase whichever page contains ADDRESS
+
+.. ERASE_PAGE response:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 3 2 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - ERASE_PAGE
+.. - 1
+.. - Value 1
+
+.. * - SUCCESS
+.. - 1
+.. - Either 0 (failure) or 1 (success)
+
+.. WRITE_BYTES
+.. """""""""""
+
+.. Used to write to RAM or flash.
+
+.. WRITE_BYTES query:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 4 4 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - WRITE_BYTES
+.. - 1
+.. - Value 2
+
+.. * - Starting Address
+.. - 4
+.. - Can address arbitrary RAM, or :ref:`cleared
+.. <bootloader-erase-page>` flash pages.
+
+.. * - DATA
+.. - MESSAGE_SIZE - 5
+.. - See :ref:`Packet Structure <bootloader-packet-structure>`
+
+.. WRITE_BYTES response:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 2 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - WRITE_BYTES
+.. - 1
+.. - Value 2
+
+.. * - SUCCESS
+.. - 1
+.. - Either 0 (failure) or 1 (success). Will fail if writes were
+.. made to uncleared pages. Does not clean up failed writes
+.. (memory will be left in an undefined state).
+
+.. READ_BYTES
+.. """"""""""
+
+.. Used to read from RAM or flash.
+
+.. READ_BYTES query:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 2 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - READ_BYTES
+.. - 1
+.. - Value 3
+
+.. * - ADDRESS
+.. - 4
+.. - Start of block to read. Must be a multiple of 4.
+
+.. * - LENGTH
+.. - 2
+.. - Maximum number of bytes to read (currently, this may be at most
+.. 1024 = 1KB). Must be a multiple of 4.
+
+.. READ_BYTES response:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 2 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - READ_BYTES
+.. - 1
+.. - Value 3
+
+.. * - DATA
+.. - MESSAGE_SIZE - 1
+.. - Contains read bytes. The actual number of bytes read may be
+.. less than the LENGTH field of the corresponding READ_BYTES
+.. query. If this section is of length 0, this should be
+.. interpreted as a read failure. See
+.. :ref:`bootloader-packet-structure`.
+
+.. JUMP_TO_USER
+.. """"""""""""
+
+.. Causes the bootloader to jump to user code's starting address.
+
+.. JUMP_TO_USER query:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 1 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - JUMP_TO_USER
+.. - 1
+.. - Value 4
+
+.. * - Location
+.. - 1
+.. - 0 means jump to flash starting address, 1 means jump to RAM
+.. starting address. See the :ref:`bootloader-get-info` command
+.. for more information.
+
+.. JUMP_TO_USER response:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 1 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - JUMP_TO_USER
+.. - 1
+.. - Value 4
+
+.. * - SUCCESS
+.. - 1
+.. - Either 0 (failure) or 1 (success). If successful, after the
+.. response is sent, the bootloader ends this session and jumps to
+.. the user code in flash or RAM as specified in the query's
+.. Location field.
+
+
+.. SOFT_RESET
+.. """"""""""
+
+.. Engages a full software reset.
+
+.. SOFT_RESET query:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 1 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - SOFT_RESET
+.. - 1
+.. - Value 5
+
+.. SOFT_RESET response:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 1 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - SOFT_RESET
+.. - 1
+.. - Value 5
+
+.. * - SUCCESS
+.. - 1
+.. - Either 0 or 1 (FAILED and OK, respectively). Will end this
+.. bootloader session and reset the processor.
+
+.. _bootloader-reflashing:
+
+Flashing A Custom Bootloader
+----------------------------
+
+The STM32 microprocessor on the Maple comes with a built-in hardware
+bootloader that can be used to flash a new (software) bootloader onto
+the chip. This section describes how to go about this, using a Maple
+Rev 3 or higher (if you have a Maple Rev 1; you don't have a BUT
+button, and won't be able to follow these directions. A workaround is
+detailed in `this forum posting
+<http://forums.leaflabs.com/topic.php?id=32#post-126>`_).
+
+.. warning:: This section is directed at users wishing to write a
+ custom bootloader for the Maple, or update their bootloader to a
+ more recent version. It's generally not necessary to do so, and it
+ is possible to make a mistake and e.g. render your Maple unable to
+ communicate with the IDE. Know what you're doing, and proceed with
+ caution.
+
+.. highlight:: sh
+
+Setup
+^^^^^
+
+In order to follow these instructions, you will need:
+
+- A binary of the bootloader you want to upload
+- Hardware for communicating between the Maple and your computer over
+ serial.
+- `Python <http://python.org>`_ version 2.5 or higher, with the
+ `PySerial <http://pyserial.sourceforge.net/>`_ library installed.
+
+**Step 1: Obtain a bootloader binary**. The first thing you'll need to
+do is to compile your bootloader binary. Note that an ASCII
+representation of the binary, such as the Intel .hex format, will not
+suffice. For example, you can run (on a :ref:`suitably configured
+system <unix-toolchain>`) the following to obtain a binary of the
+bootloader currently used on the Maple::
+
+ $ git checkout git://github.com/leaflabs/maple-bootloader.git
+ $ cd maple-bootloader
+ $ make
+ $ ls -lh build/maple-boot.bin # this is the compiled bootloader binary
+
+**Step 2: Connect Maple Serial1 to your computer**.
+There are a variety of ways of doing this. We use Sparkfun's `FTDI
+breakout boards <http://www.sparkfun.com/products/718>`_, but you
+could use another Maple, an Arduino, etc. -- anything that allows your
+computer to communicate with the Maple you want to reprogram over a
+serial interface.
+
+If you do use an FTDI breakout board, first make sure your Maple is
+disconnected from an external power source, be it battery, USB, or
+barrel jack. Then, connect the FTDI board's TX pin to ``Serial1``\ 's
+RX pin (pin 8), FTDI RX to ``Serial1`` TX (pin 7), FTDI ground to
+Maple's GND, and its 3.3V pin to Maple's Vin (use the Maple's
+silkscreen for help locating these pins). At this point, you're ready
+to plug the FTDI board into your computer (via USB).
+
+The ``Serial1`` pins are documented :ref:`here <lang-serial>`.
+
+**Step 3: Put your Maple into serial bootloader mode**. Do this by
+pressing the RESET button, then *while RESET is held down*, pressing
+and holding the BUT button. Next, *making sure to keep BUT held
+down*, release the RESET button and wait for a few seconds before
+releasing BUT.
+
+**Step 4: Obtain stm32loader.py**. The
+script ``stm32loader.py`` is provided with libmaple. If you have set
+up the :ref:`Unix toolchain <unix-toolchain>`, it is available in
+libmaple/support/stm32loader.py. Otherwise, you can download it
+directly from `github
+<https://github.com/leaflabs/libmaple/raw/master/support/stm32loader.py>`_
+(click the link, then save the file somewhere on your system).
+
+Flashing the new Bootloader
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+We'll use ``new-boot.bin``, ``ser-port``, and ``stm32loader.py`` to
+respectively refer to the absolute paths to the bootloader binary
+(from Step 1), the serial port device file or COMM port (from Steps 2
+and 3), and the stm32loader.py script.
+
+.. highlight:: sh
+
+You can run ::
+
+ $ python stm32loader.py -h
+
+to obtain usage information. The incantation for uploading a
+bootloader binary ``new-bootloader.bin`` is ::
+
+ $ python stm32loader.py -p ser-port -evw new-boot.bin
+
+If all goes well, you'll see a bunch of output, then "Verification
+OK". If something goes wrong, the `forum`_ is probably your best bet
+for obtaining help, with IRC (irc.freenode.net, #leafblowers) being
+another option. If all else fails, you can always `contact us
+directly`_!
diff --git a/docs/source/compatibility.rst b/docs/source/compatibility.rst
new file mode 100644
index 0000000..848a3d3
--- /dev/null
+++ b/docs/source/compatibility.rst
@@ -0,0 +1,266 @@
+.. highlight:: cpp
+
+.. _compatibility:
+
+=============================
+ Maple-Arduino Compatibility
+=============================
+
+.. contents:: Contents
+ :local:
+
+Overview
+--------
+
+The biggest difference between the Maple and most Arduino boards is
+that the Maple uses a 32-bit ARM Cortex-M3 architecture chip while the
+Arduinos have 8-bit Atmel AVR chips. The different instruction set
+means that machine code (executable binary programs) is incompatible
+between the two, and a different compiler (actually just a different
+version of `gcc <http://gcc.gnu.org/>`_) is required.
+
+The compiler for the regular Arduino IDE is the popular
+:command:`avr-gcc` package; the compiler for the Maple version of the
+IDE is CodeSourcery's edition of gcc for the ARM EABI target
+(:command:`arm-non-eabi-gcc`). A (preliminary) reference on
+:ref:`using arm-none-eabi-gcc <arm-gcc>` is available.
+
+The bitwidth of the processor means that the Maple can process 32-bit
+operations (like adding two 32-bit integers) in a single instruction,
+while an Arduino processor would have to split up large operations
+into several smaller ones. In a lot of cases 8-bit operations are
+plenty (integers 0-255, single characters of text, etc.), but if
+you're dealing with higher resolution data, the speed up could be
+significant. A trade-off is that code could be larger as well; program
+instructions and memory locations can be up to 32-bits each, which in
+the worst case would quadruple program size. In reality, the removal
+of extra instructions and fancy packing together of simple
+instructions means that programs aren't much larger (or are even
+smaller).
+
+Header Numbering and Incompatibilities
+--------------------------------------
+
+The numbering of headers is different; on the Maple each GPIO has a
+unique number: D0, D1, D2, all the way up to D37 (actually, there are
+:ref:`a few more <jtag>`...). On the Arduino, the analog pins are
+numbered separately (A0-A5) from the digital pins (D0\ -D13).
+
+The incompatible hardware differences are:
+
+* **I2C port**: on most Arduinos, the |i2c| port is Analog Input 4
+ (SDA) and Analog Input 5 (SCL); on the Maple, |i2c| port 1 is D5
+ (SCL) and D9 (SDA), and |i2c| port 2 is D29 (SCL) and D30 (SDA).
+
+ It should be possible to skywire, sacrificing signal quality (due to
+ increased capacitance). Alternatively, |i2c| can be bit-banged
+ reasonably well in software. This peripheral could potentially be
+ rerouted internally, but we haven't looked into it.
+
+* :ref:`PWM <pwm>` **on D10**: all the other standard Arduino PWM
+ headers have PWM functionality on the Maple (D2,D3,D6,D9,D11), but
+ not D10. We did our best! It may be possible to reroute this
+ peripheral internally using low level configuration, but we haven't
+ looked in to it.
+
+* **No External Voltage Reference**: The Arduino has an Aref pin which
+ allows the use of an external ADC voltage reference; the Maple has
+ an extra GPIO pin (14) with PWM capability in this spot, and does
+ not allow an external voltage reference to be configured.
+
+* **EEPROM**: the Maple does not have any internal EEPROM. This
+ functionality can be emulated with regular persistent flash memory,
+ or with an external EEPROM chip.
+
+* **ISP Programming**: the Maple does not use an ISP/ICSP bus for
+ debugging; it uses :ref:`JTAG <jtag>`.
+
+
+Software Language/Library Changes
+---------------------------------
+
+With :ref:`a few exceptions <language-missing-features>`, the entire
+Wiring/Arduino language is supported. However, there are some subtle
+differences, most of which are improvements:
+
+* **32-bit integers**: many standard functions either expect or return
+ full 32-bit (4 byte) integer values instead of the regular 16-bit (2
+ byte) Arduino values.
+
+* **64-bit doubles**: The :ref:`double <lang-double>` type is a full
+ double-precision floating point type on the Maple; it is a
+ single-precision floating point value on the Arduino.
+
+* :ref:`pinMode() <lang-pinmode>` **types**: any :ref:`GPIO <gpio>`
+ (including analog pins) can be configured into one of the following
+ modes with a single call to ```pinMode()``: ``OUTPUT``,
+ ``OUTPUT_OPEN_DRAIN``, ``INPUT_FLOATING``, ``INPUT_PULLUP``,
+ ``INPUT_PULLDOWN``. Additionally, the PWM and Analog Input pins can
+ be configured as ``INPUT_ANALOG`` and ``PWM`` respectively. See the
+ :ref:`GPIO documentation <gpio>` for more information.
+
+* :ref:`Serial port <lang-serial>` **syntax**: like the `Arduino Mega
+ <http://arduino.cc/en/Main/ArduinoBoardMega>`_, the Maple has
+ multiple :ref:`USART ports <lang-serial>`. By default, ``Serial``
+ is not mapped to any of them, use ``Serial1`` through ``Serial3``
+ instead.
+
+* **16-bit** :ref:`PWM <pwm>`: Arduino boards support 8-bit PWM, which
+ means that calls to :ref:`analogWrite() <lang-analogwrite>` take
+ values between 0 (always off) and 255 (always on). The Maple
+ supports 16-bit PWM, so the corresponding values should be between 0
+ (always off) and 65535 (always on).
+
+* **12-bit** :ref:`ADC <adc>`: Arduino boards support 10-bit ADC, which
+ means that calls to :ref:`analogRead() <lang-analogread>` will
+ return values between 0 and 1023. The Maple supports 12-bit ADC, so
+ the same call will instead return values between 0 and 4095.
+
+Shield and Device Compatibility
+-------------------------------
+
+.. list-table::
+ :header-rows: 1
+
+ * - Shield/Device
+ - Compatible?
+ - Notes
+
+ * - Ethernet shield
+ - Yes!
+ - Tested; no library yet
+
+ * - WiFi Shield
+ - Yes!
+ - Tested; preliminary library support
+
+ * - MIDI shield
+ - Yes!
+ - Tested; no library yet
+
+ * - XBee shield
+ - Unknown
+ -
+
+ * - Bluetooth shield
+ - Unknown
+ - Some Bluetooth <-> UART boards have been tested and are known
+ to work.
+
+ * - Cellular shield
+ - Unknown
+ -
+
+Library Porting Status
+----------------------
+
+The state of currently ported Arduino libraries is the
+:ref:`libraries`.
+
+.. TODO Update as libraries are ported.
+
+.. list-table::
+ :header-rows: 1
+
+
+ * - Library
+ - Ported?
+ - Notes
+
+ * - Wire
+ - Preliminary
+ - In progress; see :ref:`library reference <libraries-wire>`.
+
+ * - LiquidCrystal
+ - **Yes**
+ - :ref:`Included since IDE 0.0.7 <libraries-liquid-crystal>`
+
+ * - Ethernet
+ - Not yet
+ - Planned
+
+ * - EEPROM
+ - (Unsupported) third-party emulation
+ - The Maple doesn't have EEPROM; it uses flash instead. There is
+ an `EEPROM emulation library
+ <http://akb77.com/g/mcu/maple-eeprom-emulation-library/>`_ by
+ `x893 <http://akb77.com/g/>`_, but we haven't tested it.
+
+ * - Firmata
+ - Not yet
+ - Planned
+
+ * - Matrix
+ - Not yet
+ - Planned
+
+ * - Servo
+ - **Yes**
+ - :ref:`Included since IDE 0.0.9 <libraries-servo>`
+
+ * - SoftwareSerial
+ - Not yet
+ - Planned
+
+ * - Sprite
+ - Not yet
+ - Planned
+
+ * - Stepper
+ - Not yet
+ - Planned
+
+Sketch and Library Porting HOWTO
+--------------------------------
+
+In addition to the suggestions in this section, you may find many of
+the individual :ref:`language reference <language>` pages useful. As
+appropriate, these have "Arduino Compatibility" sections; one good
+example is the :ref:`analogWrite() <lang-analogwrite-compatibility>`
+function.
+
+- Check the hardware and header differences above, and see if your
+ project or shield needs to be modified (eg, add 3.3V level
+ converters or reroute PWM to header D10).
+
+- Check for ported library functionality. We intend to port all of the
+ core and popular libraries (like Wire, Ethernet, and the LCD screen
+ driver), but this task is not yet finished. (Patches are welcome!)
+
+- Check for peripheral conflicts; changing the configuration of timers
+ and bus speeds for a feature on one header may impact all the
+ features on that hardware "port". For example, changing the timer
+ prescaler to do long PWM pulses could impact |i2c| communications on
+ nearby headers.
+
+- Rewrite any low-level code. This could potentially be very
+ difficult, but hopefully you've used the Arduino libraries to
+ abstract away the registers and other hardware-specific
+ details. Your sketch probably doesn't have any low-level code; a
+ library which wraps a particular peripheral very well may. Some
+ help is available in the :ref:`arm-gcc` reference.
+
+- Redeclare variable sizes if necessary: generics like ``int`` will
+ probably work unless you depend on side-effects like rollover.
+
+- Check every ``pinMode()``: the Maple has more modes for GPIO
+ pins. For example, make sure to set analog pins to ``INPUT_ANALOG``
+ before reading and PWM pins to ``PWM`` before writing. The full set
+ of pin modes is documented in the :ref:`lang-pinmode` reference.
+
+- Modify PWM writes: ``pinMode()`` must be set to ``PWM``, the
+ frequency of the PWM pulse configured, and the duty cycle written
+ with up to 16-bit resolution.
+
+- Modify ADC reads: :ref:`lang-analogread` takes the full pin number
+ (not 0-5) and returns a full 12-bit reading. The ADC pin must have
+ its ``pinMode()`` set to ``INPUT_ANALOG``.
+
+- Possibly convert all Serial-over-USB communications to use
+ :ref:`lang-serialusb` instead of a USART :ref:`serial port
+ <lang-serial>`. The Maple has a dedicated USB port which is not
+ connected to the USART TX/RX pins in any way.
+
+- Check timing: Maple clock cycles are just 13.9 nanoseconds, though
+ the peripheral bus speeds (which limit GPIO output) are clocked
+ slower.
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644
index 0000000..1ad4e57
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,273 @@
+# -*- coding: utf-8 -*-
+#
+# libmaple documentation build configuration file, created by
+# sphinx-quickstart on Thu Oct 7 06:42:30 2010.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# We rely on Michael Jones's breathe as a Doxygen-to-Sphinx bridge.
+# See libmaple/docs/README for information on obtaining it and letting
+# Sphinx know where it is.
+sys.path.append(os.environ['BREATHE_HOME'])
+
+# -- General configuration ----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest',
+ 'sphinx.ext.intersphinx', 'sphinx.ext.todo',
+ 'sphinx.ext.coverage', 'breathe']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates', '_static']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Maple'
+copyright = u'2010, LeafLabs, LLC'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.0'
+# The full version, including alpha/beta/rc tags.
+release = '0.0.9'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['epilog.rst', 'prolog.rst']
+
+# Included at the end of every source file that is read.
+with open('epilog.rst', 'r') as ep:
+ rst_epilog = ep.read()
+
+# Included at the beginning of every source file that is read.
+with open('prolog.rst', 'r') as pr:
+ rst_prolog = pr.read()
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# Warn about all references where the target cannot be found.
+nitpicky = True
+
+# -- Options for HTML output --------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+html_theme_options = {
+ ## Sidebar placement options
+ #'stickysidebar' : 'true',
+ 'rightsidebar' : 'true',
+ #'collapsiblesidebar' : 'true',
+
+ ## Color
+ 'sidebarbgcolor' : '#C8C8C8',
+ 'sidebarlinkcolor' : 'green',
+ 'sidebartextcolor' : 'black',
+ #'sidebarbtncolor' : 'black',
+ 'footerbgcolor' : 'green',
+ 'relbarbgcolor' : 'green',
+ 'headlinkcolor' : '#000000',
+ 'linkcolor' : 'green',
+ 'visitedlinkcolor' : 'green',
+
+ ## Font
+ 'headfont' : 'Georgia',
+ 'bodyfont' : 'Lucidia'
+}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = ['_static']
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+html_title = project + ' v' + release + ' Documentation'
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+html_short_title = 'Index'
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = '_static/img/round_logo_60x60.png'
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+html_favicon = '_static/img/round_logo_32x32.ico'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+# re-add commented line when custom template for api finished
+html_sidebars = {
+ '**': ['globaltoc.html', 'searchbox.html'],
+ #'lang/api**':['searchbox.html', 'apilist.html'],
+}
+
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+html_use_index = False
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'mapledoc'
+
+
+# -- Options for LaTeX output -------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target file, title, author, documentclass [howto/manual])
+latex_documents = [
+ ('index', 'maple.tex', u'Maple Documentation',
+ u'LeafLabs, LLC', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output -------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'maple', u'Maple Documentation',
+ [u'LeafLabs, LLC'], 1)
+]
+
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {'http://docs.python.org/': None}
+
+
+# -- Options for breathe integration ------------------------------------------
+
+breathe_projects = {'libmaple' : os.path.join(os.environ['LIB_MAPLE_HOME'],
+ 'docs', 'doxygen', 'xml')}
+
+breathe_default_project = 'libmaple'
diff --git a/docs/source/epilog.rst b/docs/source/epilog.rst
new file mode 100644
index 0000000..e64103c
--- /dev/null
+++ b/docs/source/epilog.rst
@@ -0,0 +1,8 @@
+.. This file automatically gets included at the end of every file, so
+.. it's useful for common references, etc.
+
+.. Common URL references
+
+.. _forum: http://forums.leaflabs.com
+.. _contact: http://leaflabs.com/contact/
+.. _contact us directly: http://leaflabs.com/contact/
diff --git a/docs/source/errata.rst b/docs/source/errata.rst
new file mode 100644
index 0000000..8feb6ea
--- /dev/null
+++ b/docs/source/errata.rst
@@ -0,0 +1,140 @@
+.. _errata:
+
+========
+ Errata
+========
+
+This page is a collection of known issues and warnings for each
+revision of the Maple board. The failure modes aren't design errors,
+but are easy ways to break or damage your board permanently. For a
+list of differences between the Maple and Arduinos, see the
+:ref:`compatibility reference <compatibility>`.
+
+The errata are grouped by Maple version ("Rev"). Rev 5 is currently
+on sale. If you are unsure which version you own, the :ref:`Maple
+hardware page <maple-hardware-identify-rev>` has pictures and
+descriptions of each version.
+
+.. contents:: Contents
+ :local:
+
+Maple Rev 5
+-----------
+
+Known issues:
+
+* **Pin 3 AIN missing**: Pin 3 is capable of analog input, but the
+ corresponding "AIN" is missing from its silkscreen.
+
+* **GPIO 39-43 not configured**: this is really more of a software
+ "TODO" item. Some of the JTAG header pins are numbered 39-43. These
+ STM32 pins are indeed fully functional :ref:`GPIO <gpio>` when the a
+ :ref:`JTAG <jtag>` device is not connected, but we have not enabled
+ them in software and thus they can not be accessed with the regular
+ :ref:`lang-pinmode` or :ref:`lang-digitalwrite` functions.
+
+Potential failure modes:
+
+* **TTL voltage on non-tolerant pins**: not all header pins are 5V
+ compatible; connecting certain serial devices in the wrong way could
+ over voltage the pins. The :ref:`Pin-Mapping Mega Table
+ <pin-mapping-mega-table>` details which pins are 5V-tolerant.
+
+Maple Rev 3
+-----------
+
+Known issues:
+
+* **Bad/Sticky Buttons**: a number of Rev 3 boards sold in May-June 2010
+ have questionable RESET and BUT buttons.
+
+ What seems to have happened is that the flux remover we used to
+ clean the boards before shipping eroded the plastic internals, which
+ resulted in intermittent functionality. All buttons on all shipped
+ boards did function in testing, but some may have been unreliable in
+ regular use.
+
+ If you have this problem, we will be happy to ship you new buttons
+ if you think you can re-solder them yourself, or you can ship us
+ your board and we will swap out that part.
+
+ For reference, the button part number is KMR211GLFS and the flux
+ remover we used is "Precision Electronics Cleaner" from RadioShack,
+ which is "Safe on most plastics" and contains Dipropylene glycol
+ monomethyl ether, hydrotreated heavy naphtha, dipropylene glycol
+ methyl ether acetate (really?), and carbon dioxide.
+
+* **Resistors on pins 0 and 1**: these header pins, which are RX/TX on
+ USART2 (:ref:`Serial2 <lang-serial>`), have resistors in-line
+ between the STM32 and the headers. These resistors increase the
+ impedance of the lines for ADC reads and affect the open drain GPIO
+ functionality of the pins.
+
+ These resistors were accidentally copied over from older Arduino USB
+ designs, where they appear to protect the USB-Serial converter from
+ TTL voltage on the headers.
+
+* **GPIO 39-43 not configured**: this is really more of a software
+ "TODO" item. Some of the JTAG header pins are numbered 39-43. These
+ STM32 pins are indeed fully functional :ref:`GPIO <gpio>` when the a
+ :ref:`JTAG <jtag>` device is not connected, but we have not enabled
+ them in software and thus they can not be accessed with the regular
+ :ref:`lang-pinmode` or :ref:`lang-digitalwrite` functions.
+
+* **Silkscreen Errors**: the silkscreen on the bottom indicated PWM
+ functionality on pin 25 and listen the external header GND pin as
+ number 38 (actually 38 is connected to the BUT button). We manually
+ sharpied over both of these mistakes.
+
+* **PWM Marketing Mistake**: We originally sold the Maple advertising
+ 22 channels of 16-bit hardware PWM; actually the Maple only has 15.
+
+Potential failure modes:
+
+* **TTL voltage on non-tolerant pins**: not all header pins are 5V
+ compatible; connecting certain serial devices in the wrong way could
+ over voltage the pins. The :ref:`Pin-Mapping Mega Table
+ <pin-mapping-mega-table>` details which pins are 5V-tolerant.
+
+Maple Rev 1
+-----------
+
+Known issues:
+
+* **ADC noise**: generally very high, in particular when the USB port
+ is being used for communications (including keep-alive pings when
+ connected to a computer).
+
+ This issue was resolved in Rev 3 with a 4-layer design and a
+ geometrically isolated ADC V\ :sub:`ref` plane.
+
+* **Resistors on pins 0 and 1**: these header pins, which are RX/TX on
+ USART2 (:ref:`Serial2 <lang-serial>`), have resistors in-line
+ between the STM32 and the headers. These resistors increase the
+ impedance of the lines for ADC reads and affect the open drain GPIO
+ functionality of the pins.
+
+ These resistors were accidentally copied over from older Arduino USB
+ designs, where they appear to protect the USB-Serial converter from
+ TTL voltage on the headers.
+
+* **Silkscreen Differences**: the pin numbering scheme on Rev 1 is
+ different from Rev 3, and thus Rev 3 software is difficult to use
+ with Rev 1 boards. Notably, the analog input bank is labeled A0-A4
+ on Rev 1 but 15-20 on Rev 3, and the extra header bank does not have
+ a pinout table on the bottom.
+
+* **No BUT Button**: the BUT button, useful for serial bootloading,
+ was only added in Rev 3. As a workaround, you can directly short the
+ appropriate MCU pin to Vcc; see `this forum posting
+ <http://forums.leaflabs.com/topic.php?id=32#post-126>`_.
+
+* **PWM Marketing Mistake**: We originally sold the Maple advertising
+ 22 channels of 16-bit hardware PWM; actually the Maple only has 15.
+
+Potential failure modes:
+
+* **TTL voltage on non-tolerant pins**: not all header pins are 5v
+ compatible; connecting certain serial devices in the wrong way could
+ over voltage the pins. The :ref:`Pin-Mapping Mega Table
+ <pin-mapping-mega-table>` details which pins are 5V-tolerant.
diff --git a/docs/source/external-interrupts.rst b/docs/source/external-interrupts.rst
new file mode 100644
index 0000000..b2cbbb1
--- /dev/null
+++ b/docs/source/external-interrupts.rst
@@ -0,0 +1,119 @@
+.. highlight:: cpp
+
+.. _external-interrupts:
+
+External Interrupts
+===================
+
+External interrupts can be used to trigger routines to run in response
+to changes in voltage on a pin. Each GPIO pin on the Maple can be used
+to detect transitions such as when the voltage goes from low to high,
+or from high to low. This technique can be used to avoid unnecessary
+polling of the state of a pin.
+
+.. _contents: Contents
+ :local:
+
+
+Overview
+--------
+
+External interrupts are often used to detect when events happen
+outside of the microcontroller. These can be used to tell the Maple
+when events happen, such as when a sensor has data ready to be read,
+or when a button has been pushed. When such an event happens, an
+interrupt is raised and the Maple can react to it with a preset
+*interrupt handler*.
+
+Every GPIO pin on the Maple can be used as an external interrupt,
+subject to certain constraints; there can be a maximum of 16 different
+external interrupts set up at a time on the Maple. This is because the
+external interrupt lines on the STM32 are multiplexed between GPIO
+ports. In effect, this means that every pin on the Maple maps to a
+certain EXTI line, and within that EXTI line, only one of the pins
+that maps to it can be used as an external interrupt at a time.
+
+The following table shows which pins can be used on which lines.
+
+.. list-table::
+ :widths: 1 1
+ :header-rows: 1
+
+ * - EXTI Line
+ - Maple pins
+ * - EXTI0
+ - 2, 15, 27
+ * - EXTI1
+ - 3, 16, 28
+ * - EXTI2
+ - 1, 17, 25
+ * - EXTI3
+ - 0, 18
+ * - EXTI4
+ - 10, 19
+ * - EXTI5
+ - 4, 13, 20
+ * - EXTI6
+ - 5, 12, 35
+ * - EXTI7
+ - 9, 11, 36
+ * - EXTI8
+ - 6, 14, 37
+ * - EXTI9
+ - 7, 25, 28
+ * - EXTI10
+ - 8, 26, 29
+ * - EXTI11
+ - 30
+ * - EXTI12
+ - 31
+ * - EXTI13
+ - 21, 32
+ * - EXTI14
+ - 22, 33
+ * - EXTI15
+ - 23, 34
+
+.. note::
+
+ You should set the :ref:`pin mode <lang-pinmode>` of your
+ desired pin to an input mode (e.g ``INPUT`` or ``INPUT_FLOATING``,
+ ``INPUT_PULLUP``, ``INPUT_PULLDOWN``).
+
+
+Function Reference
+------------------
+
+- :ref:`attachInterrupt() <lang-attachinterrupt>`
+- :ref:`detachInterrupt() <lang-detachinterrupt>`
+
+Code example
+------------
+
+Blink the LED on every transition::
+
+ int pin = 13;
+ volatile int state = LOW;
+
+ void setup() {
+ pinMode(pin, OUTPUT);
+ pinMode(0, INPUT_FLOATING);
+ attachInterrupt(0, blink, CHANGE);
+ }
+
+ void loop() {
+ digitalWrite(pin, state);
+ }
+
+ void blink() {
+ state = !state;
+ }
+
+
+Recommended Reading
+-------------------
+
+* STMicro documentation for STM32F103RB microcontroller:
+
+ * `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/docs/source/gpio.rst b/docs/source/gpio.rst
new file mode 100644
index 0000000..4017862
--- /dev/null
+++ b/docs/source/gpio.rst
@@ -0,0 +1,102 @@
+.. _gpio:
+
+GPIO
+====
+
+The Maple features 38 ready-to-use general purpose input/output (GPIO)
+pins for digital input/output, numbered D0 through D37. These numbers
+correspond to the numeric values next to each header on the Maple
+silkscreen.
+
+Many of these pins may additionally be used for special features or
+peripheral functions. This page documents those capabilities, by pin.
+
+The current and voltage limitations have not been copied over from the
+STM32 datasheet (see the :ref:`Recommended Reading
+<gpio-recommended-reading>` for a link). In particular, a number of
+GPIO pins are 5V tolerant (which means that applying 5 volts to a pin
+and reading it as input or allowing it to drain to ground will not
+damage that pin), while some are not.
+
+.. contents:: Contents
+ :local:
+
+.. _pin-mapping-mega-table:
+
+Pin Mapping Mega Table
+----------------------
+
+This table shows the available functionality on every GPIO pin, by
+peripheral type. The "STM32" column refers to the port and number that
+the header is connected to on the microcontroller. The "5V?" column
+documents whether or not the pin is 5 volt tolerant (see 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"
+ "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
+----------
+
+.. doxygenenum:: WiringPinMode
+
+Function Reference
+------------------
+
+.. doxygenfunction:: pinMode
+
+.. doxygenfunction:: digitalRead
+
+.. doxygenfunction:: digitalWrite
+
+.. doxygenfunction:: analogRead
+
+.. _gpio-recommended-reading:
+
+Recommended Reading
+-------------------
+
+STMicro documentation for STM32F103RB microcontroller:
+
+ * `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/docs/source/hardware/maple-mini.rst b/docs/source/hardware/maple-mini.rst
new file mode 100644
index 0000000..a8a4186
--- /dev/null
+++ b/docs/source/hardware/maple-mini.rst
@@ -0,0 +1,6 @@
+.. _hardware-maple-mini:
+
+Maple Mini
+==========
+
+Stub.
diff --git a/docs/source/hardware/maple-native.rst b/docs/source/hardware/maple-native.rst
new file mode 100644
index 0000000..79115fc
--- /dev/null
+++ b/docs/source/hardware/maple-native.rst
@@ -0,0 +1,6 @@
+.. _hardware-maple-native:
+
+Maple Native
+============
+
+Stub.
diff --git a/docs/source/hardware/maple.rst b/docs/source/hardware/maple.rst
new file mode 100644
index 0000000..8350cc5
--- /dev/null
+++ b/docs/source/hardware/maple.rst
@@ -0,0 +1,104 @@
+.. highlight:: sh
+
+.. _hardware-maple:
+
+Maple
+=====
+
+.. contents:: Contents
+ :local:
+
+.. _maple-hardware-identify-rev:
+
+Identifying your Rev
+--------------------
+
+We went through three versions ("Revs") of the Maple hardware: Rev 1,
+Rev 3, and Rev 5 [#frev2_4]_; Rev 5, the final design, is currently on
+sale. The following sections will help you to help you identify your
+Rev. Known issues are listed in the :ref:`errata <errata>`.
+
+Rev 1
+^^^^^
+
+A small number of Maple Rev 1 boards went on sale in late 2009. They
+have a light red silkscreen and a single pixelated leaf as a logo.
+
+.. figure:: /_static/img/maple_rev1.png
+ :align: center
+ :alt: Maple Rev 1
+
+.. rubric:: Footnotes
+
+.. [#frev2_4] Revs 2 and 4 were prototypes that didn't pass internal
+ testing.
+
+Rev 3
+^^^^^
+
+This batch of boards went on sale beginning in May 2010. They have a
+darker red silkscreen and the "infinity leaf" logo. The Maple Rev 3
+was the first version which includes the built-in button, labeled BUT.
+It also includes a built-in LiPo battery charger.
+
+.. figure:: /_static/img/maple_rev3.png
+ :align: center
+ :alt: Maple Rev 3
+
+Rev 5
+^^^^^
+
+These boards went on sale in November 2010. They have white buttons,
+and "r5" in small print near the "LeafLabs Maple" text next to the
+"infinity leaf" logo. The Maple Rev 5 repositioned the double header
+on the right hand side to better fit 0.1 inch pitch breadboard. This
+necessitated the removal of pins 21 and 22 from the double header;
+they are still available, but don't have any headers installed on
+them.
+
+.. figure:: /_static/img/maple_rev5.png
+ :align: center
+ :alt: Maple Rev 5
+
+Powering the Maple
+------------------
+
+The Maple's power source is determined by the header to the left of
+the "LeafLabs" label on the silkscreen. All versions of the Maple can
+be powered from the barrel jack connector, USB, or a LiPo battery. We
+ship the Maple with a jumper on the USB selector. In order to power
+it off of an alternative source, unplug the Maple, then move the
+jumper to the desired selector before reconnecting power.
+
+You can also power the Maple via the pin labeled "Vin" on the lower
+header. However, don't do this while simultaneously powering the
+Maple from another source, or you could damage the board.
+
+Using the Built-in Battery Charger
+----------------------------------
+
+Maples Rev 3 and Rev 5 also have a built-in LiPo battery charger. In
+order to use it, put a jumper across the CHRG header on the power
+selection header and across the USB, or EXT selectors, depending on
+whether you're charging the battery via USB cable or barrel jack
+connector. The LED labeled CHRG will light up while the battery is
+being charged. When the battery is finished charging, the LED labeled
+DONE will also light up.
+
+Hardware Design Files
+---------------------
+
+The hardware schematics and board layout files are available in the
+`Maple github repository <https://github.com/leaflabs/maple>`_. The
+design files for Rev 1, Rev 3, and Rev 5 are respectively in the
+``maple-r1``, ``maple-r3``, and ``maple-r5`` subdirectories. A
+schematic for a JTAG adapter suitable for use with Maple is available
+in the ``jtagadapter`` directory.
+
+From the github repository main page, you can download the entire
+repository by clicking the "Download" button. If you are familiar
+with `git <http://git-scm.com/>`_, you can also clone the repository
+at the command line with ::
+
+ $ git clone git://github.com/leaflabs/maple.git
+
diff --git a/docs/source/i2c.rst b/docs/source/i2c.rst
new file mode 100644
index 0000000..b4a996b
--- /dev/null
+++ b/docs/source/i2c.rst
@@ -0,0 +1,87 @@
+.. _i2c:
+
+=====
+|i2c|
+=====
+
+.. 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:
+
+ * `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/docs/source/ide.rst b/docs/source/ide.rst
new file mode 100644
index 0000000..b3ef653
--- /dev/null
+++ b/docs/source/ide.rst
@@ -0,0 +1,136 @@
+.. _ide:
+
+Maple IDE
+=========
+
+This page documents the basic functionality of the Maple IDE.
+Specifically, it describes the operation of the buttons on the main
+toolbar. It is expected to become more comprehensive over time.
+
+The :ref:`Maple Quickstart <maple-quickstart>` is another good source of
+information on the IDE; it is especially useful for setting up a
+computer for the first time.
+
+.. figure:: /_static/img/ide-blinky.png
+ :align: center
+ :alt: Maple IDE
+
+.. _ide-verify:
+
+Verify
+------
+
+.. image:: /_static/img/button-verify.png
+ :align: left
+
+Click Verify to compile the current sketch.
+
+.. _ide-stop:
+
+Stop
+----
+
+.. image:: /_static/img/button-stop.png
+ :align: left
+
+Click Stop to cancel a compilation.
+
+.. _ide-new:
+
+New
+---
+
+.. image:: /_static/img/button-new.png
+ :align: left
+
+Click New to begin a fresh sketch.
+
+.. _ide-open:
+
+Open
+----
+
+.. image:: /_static/img/button-open.png
+ :align: left
+
+Click Open to open a new sketch. By default, this will look in you
+*sketchbook*, which is a directory on your system which contains all
+of your sketches. The default directory of your sketchbook varies by
+operating system; you can change it in the IDE preferences.
+
+.. _ide-save:
+
+Save
+----
+
+.. image:: /_static/img/button-save.png
+ :align: left
+
+Click Save to save the currently opened sketch.
+
+.. _ide-upload:
+
+Upload
+------
+
+.. image:: /_static/img/button-upload.png
+ :align: left
+
+Click Upload to send the compiled sketch to your Maple to run. Before
+you click Upload, you must have a memory location and serial port
+selected. The memory location, either Flash or RAM, determines
+whether the compiled sketch binary will be stored on the Maple. You
+can choose this using the Tools > Board menu. The serial port
+corresponds to the Serial-over-USB connection the Maple has
+established with your computer. This looks like "COM1", "COM2",
+etc. on Windows, "/dev/tty.usbmodemXXX" on Mac (where "XXX" is some
+sequence of letters and numbers), or "/dev/ttyACMXXX" on Linux (again,
+where "XXX" is some sequence of letters and numbers). You can choose
+a serial port using the Tools > Serial Port menu.
+
+If you click Upload without having made these choices; The IDE
+*should* prompt you to do so. However, if you're trying to upload and
+are unsuccessful, make sure you've made choices for both board and
+serial port.
+
+For more help, the upload process is documented in more detail (with
+screenshots) in the :ref:`quickstart <maple-quickstart-upload>`.
+
+If all else fails, try putting your Maple in :ref:`perpetual
+bootloader mode <troubleshooting-perpetual-bootloader>` before
+uploading.
+
+In any case, you can always find us on the `forum`_ or `contact us
+directly`_.
+
+.. _ide-serial-monitor:
+
+Serial Monitor
+--------------
+
+.. image:: /_static/img/button-serial-monitor.png
+ :align: left
+
+Click Serial Monitor to open up a communications channel between your
+PC and the Maple's :ref:`Serial-over-USB <lang-serialusb>`
+(``SerialUSB``) virtual serial port.
+
+If the serial monitor is open, any information sent to the computer
+(e.g. using :ref:`SerialUSB.println() <lang-serialusb-println>` will
+be displayed in the large text area. You can send data to the Maple
+(to be read with e.g. :ref:`SerialUSB.read() <lang-serialusb-read>`)
+by typing into the small text box and either hitting the Enter key or
+pressing the Send button.
+
+Here is an example serial monitor session with the InteractiveTest
+sketch (which you can load in the IDE by choosing menu item File >
+Examples > Maple > InteractiveTest):
+
+.. image:: /_static/img/serial-monitor.png
+
+This is the result of typing "?" in the text box and clicking Send.
+
+.. note:: You cannot upload a sketch while the serial monitor is open.
+ If you click :ref:`Upload <ide-upload>` while the serial monitor is
+ open, the IDE will close it for you before proceeding with the
+ upload.
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644
index 0000000..5c1718f
--- /dev/null
+++ b/docs/source/index.rst
@@ -0,0 +1,86 @@
+.. _index:
+
+Maple Documentation Contents
+============================
+
+Welcome! This is the Maple documentation index. If you just bought a
+Maple, you probably want to head to the :ref:`quickstart
+<maple-quickstart>`. If you're having problems, check out the
+:ref:`troubleshooting <troubleshooting>` and :ref:`known problems
+<errata>` pages.
+
+Have fun!
+
+.. _index-usage:
+
+**Usage Guides:**
+
+.. toctree::
+ :maxdepth: 1
+
+ Quickstart <maple-quickstart>
+ IDE Installation <maple-ide-install>
+ IDE Usage <ide>
+ Command-Line Toolchain <unix-toolchain>
+
+.. _index-maple-programming:
+
+**Maple Programming:**
+
+.. toctree::
+ :maxdepth: 1
+
+ Language <language>
+ Libraries <libraries>
+ Arduino Compatibility <compatibility>
+ libmaple <libmaple>
+ External Interrupts <external-interrupts>
+ Bootloader <bootloader>
+ Troubleshooting <troubleshooting>
+ Known Problems <errata>
+
+.. _index-hardware:
+
+**Hardware Peripherals:**
+
+.. toctree::
+ :maxdepth: 1
+
+ adc
+ gpio
+ i2c
+ jtag
+ pwm
+ spi
+ timers
+ usb
+ usart
+
+.. _index-schematics:
+
+**Board Hardware Documentation:**
+
+.. toctree::
+ :maxdepth: 1
+
+ hardware/maple.rst
+
+.. TODO write/include these upon Mini and Native release
+
+.. toctree::
+ :hidden:
+
+ hardware/maple-mini.rst
+ hardware/maple-native.rst
+
+.. _index-reference:
+
+**Reference:**
+
+.. toctree::
+ :maxdepth: 1
+
+ Technical Specifications <specs>
+ Complete Language Index <language-index>
+
+
diff --git a/docs/source/jtag.rst b/docs/source/jtag.rst
new file mode 100644
index 0000000..e3c8111
--- /dev/null
+++ b/docs/source/jtag.rst
@@ -0,0 +1,65 @@
+.. _jtag:
+
+======
+ JTAG
+======
+
+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 fairly advanced users to use
+this feature.
+
+.. contents:: Contents
+ :local:
+
+Wiring Diagram
+--------------
+
+.. figure:: /_static/img/jtag-wiring.png
+ :align: center
+ :alt: JTAG wiring diagram
+ :width: 7.4in
+
+ JTAG wiring diagram (`large version
+ <http://leaflabs.com/wp-content/uploads/2010/11/maple-jtagadapter.png>`_)
+ to connect a standard 20-pin ARM JTAG device to the 8-pin JTAG port
+ on the Maple.
+
+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.
+
+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 November 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:
+
+ * `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)
+* There's a `thread on JTAG
+ <http://forums.leaflabs.com/topic.php?id=536>`_ in our `forum`_
+ which you may find useful.
diff --git a/docs/source/lang/api/abs.rst b/docs/source/lang/api/abs.rst
new file mode 100644
index 0000000..0cc6c23
--- /dev/null
+++ b/docs/source/lang/api/abs.rst
@@ -0,0 +1,49 @@
+.. highlight:: cpp
+
+.. _lang-abs:
+
+
+abs()
+======
+
+(Macro) computes the absolute value of a number.
+
+Syntax
+------
+
+::
+
+ abs(x)
+
+Parameters
+----------
+
+**x**: the number.
+
+Returns
+-------
+
+**x**: if **x** is greater than or equal to 0.
+
+**-x**: if **x** is less than 0.
+
+Warning
+-------
+
+Because of the way ``abs()`` is implemented, avoid using other
+functions or causing side effects inside the parentheses, as it may
+lead to incorrect results::
+
+ abs(a++); // avoid this - yields incorrect results
+
+ abs(a); // use this instead -
+ a++; // keep other operations outside abs()
+
+
+Arduino Compatibility
+---------------------
+
+Maple's implementation of ``abs()`` is compatible with Arduino.
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/analogread.rst b/docs/source/lang/api/analogread.rst
new file mode 100644
index 0000000..35c6fbc
--- /dev/null
+++ b/docs/source/lang/api/analogread.rst
@@ -0,0 +1,119 @@
+.. highlight:: cpp
+
+.. _lang-analogread:
+
+.. _lang-api-analogread:
+
+analogRead()
+============
+
+Used to perform ADC conversion.
+
+.. contents:: Contents
+ :local:
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: analogRead
+
+Discussion
+----------
+
+Reads the value from the specified analog pin. The Maple board
+contains a 16-channel, 12-bit analog to digital converter. This means
+that it will map input voltages between 0 and 3.3 volts into integer
+values between 0 and 4095. This yields a resolution between readings
+of 3.3V / 4096 units, or 0.8 millivolts. However, a number of factors
+interfere with getting full accuracy and precision. For more
+information, see :ref:`adc`.
+
+Before calling analogRead() on a pin, that pin must first be
+configured for analog input, using :ref:`lang-pinMode` (you only
+have to do this once, so it's usually done in :ref:`lang-setup`\ ).
+
+Parameter Discussion
+--------------------
+
+The pin parameter is the number of the analog input pin to read from.
+Header pins on the Maple with ADC functionality (marked as "AIN" on
+the silkscreen) are:
+
+ 0, 1, 2, 3, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 27, 28
+
+Note that pins 3, 27, and 28 are not marked AIN on the silkscreen
+for Maple revisions through Rev 5, however, they **do work** as
+analog input pins.
+
+Note
+----
+
+If the analog input pin is not connected to anything, the value
+returned by analogRead() will fluctuate based on a number of factors
+(e.g. the values of the other analog inputs, how close your hand is to
+the board, etc.) in a seemingly random way.
+
+
+Example
+-------
+
+ ::
+
+
+ int analogPin = 3; // potentiometer wiper (middle terminal) connected
+ // to analog pin 3. outside leads to ground and +3.3V
+ int val = 0; // variable to store the value read
+
+ void setup() {
+ pinMode(analogPin, INPUT_ANALOG); // set up pin for analog input
+ SerialUSB.begin(); // set up usb virtual COM port
+ }
+
+ void loop() {
+ val = analogRead(analogPin); // read the input pin
+ SerialUSB.println(val); // print the value, for debugging with
+ // a serial monitor
+ }
+
+
+Arduino Compatibility
+---------------------
+
+The Arduino board contains a 6 channel (8 channels on the Mini and
+Nano, 16 on the Mega), 10-bit analog to digital converter with an
+input voltage range of 0V--5V. This means that it will map input
+voltages between 0 and 5 volts (which is **larger** than Maple's range
+of 0V-3.3V) into integer values between 0 and 1023 (which is
+**smaller** than the Maple's range of 0--4095).
+
+This yields a theoretical resolution between readings of: 5 volts /
+1024 units or .0049 volts (4.9 mV) per unit on Arduino boards, which
+is larger, and thus less precise, than Maple's 0.0008 volts (0.8 mV).
+
+If your program expects Arduino-style 10-bit ADC, you can :ref:`right
+shift <lang-bitshift>` the value of a Maple readout by 2, like so::
+
+ // right shift means that the result will be between 0 and 1023;
+ // be aware that you're losing a lot of precision if you do this
+ int adc_reading = analogRead(pin) >> 2;
+
+On the Arduino, the input range and resolution can be changed using
+their implementation of `analogReference()
+<http://arduino.cc/en/Reference/AnalogReference>`_\ . Because of the
+way its hardware (as of Rev 5) was designed, it's not possible to
+implement analogReference on the Maple, so this function doesn't
+exist. If your inputs lie in a different voltage range than 0V--3.3V,
+you'll need to bring them into that range before using analogRead.
+Some basic tools to accomplish this are `resistor dividers
+<http://en.wikipedia.org/wiki/Voltage_divider>`_ and `Zener diodes
+<http://en.wikipedia.org/wiki/Voltage_source#Zener_voltage_source>`_\
+. However, opamps and other powered components can also be used if
+greater precision is required.
+
+See also
+--------
+
+- :ref:`ADC note <adc>`
+- `(Arduino) Tutorial: Analog Input Pins <http://arduino.cc/en/Tutorial/AnalogInputPins>`_
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/analogwrite.rst b/docs/source/lang/api/analogwrite.rst
new file mode 100644
index 0000000..9147b96
--- /dev/null
+++ b/docs/source/lang/api/analogwrite.rst
@@ -0,0 +1,173 @@
+.. highlight:: cpp
+
+.. _lang-analogwrite:
+
+.. _lang-api-analogwrite:
+
+
+analogWrite()
+=============
+
+.. note::
+
+ On the Maple, calling analogWrite() is the same as calling
+ :ref:`lang-pwmwrite`\ ; we recommend using that function directly
+ instead.
+
+ 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:`lang-analogread`\ , which is
+ potentially confusing.
+
+ The alias of analogWrite() to pwmWrite() is provided for the sake
+ of compatibility with Arduino only.
+
+.. contents:: Contents
+ :local:
+
+.. _lang-analogwrite-compatibility:
+
+Arduino Compatibility
+---------------------
+
+There are a few important differences between Arduino's `analogWrite()
+<http://arduino.cc/en/Reference/AnalogWrite>`_ and Maple's
+:ref:`lang-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 <lang-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 <lang-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:`lang-pinmode`\ , with argument ``PWM``.
+This should just be one extra line of code in your
+:ref:`lang-setup` function. Example::
+
+ void setup() {
+ // set up pin 9 for PWM
+ pinMode(9, PWM);
+ }
+
+This also means that you can't later call :ref:`lang-digitalread`
+or :ref:`lang-digitalwrite` on that pin (unless some time in
+between, you use pinMode() to reconfigure that pin for ``INPUT`` or
+``OUTPUT``; see the :ref:`lang-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, 14, 24, 27, and 28 or fifteen pins in total. That's *more*
+PWM-capable pins as any Arduino board, but there are differences in
+*which* pins support PWM.
+
+* 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.
+
+* **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, then any other 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 definitely requires Arduino's PWM frequency, then
+the steps are:
+
+1. Figure out which :ref:`timer <lang-hardwaretimer>` 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. The important examples are :ref:`timer interrupts
+<lang-hardwaretimer-attachinterrupt>` and :ref:`PWM
+<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
diff --git a/docs/source/lang/api/attachinterrupt.rst b/docs/source/lang/api/attachinterrupt.rst
new file mode 100644
index 0000000..7c5a6c7
--- /dev/null
+++ b/docs/source/lang/api/attachinterrupt.rst
@@ -0,0 +1,115 @@
+.. highlight:: cpp
+
+.. _lang-attachinterrupt:
+
+attachInterrupt()
+=================
+
+Used to specify a function to call when an external interrupt (like an
+GPIO changing from LOW to HIGH, a button getting pressed, etc.)
+occurs.
+
+.. contents:: Contents
+ :local:
+
+Library Documentation
+---------------------
+
+.. FIXME once breathe knows how to get the correct attachInterupt
+.. (right now it's copying from HardwareTimer), replace with a
+.. doxygenfunction directive
+
+.. cpp:function:: void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode)
+
+ Registers an interrupt handler on a pin.
+
+ The interrupt will be triggered on a given transition on the pin,
+ as specified by the mode parameter. The handler runs in interrupt
+ context. The new handler will replace whatever handler is
+ currently registered for the pin, if any.
+
+ *Parameters*
+
+ - ``pin`` - Maple pin number
+
+ - ``handler`` - Function to run upon external interrupt trigger.
+ The handler should take no arguments, and have void return type.
+
+ - ``mode`` - Type of transition to trigger on, e.g. falling,
+ rising, etc.
+
+.. doxygenenum:: ExtIntTriggerMode
+
+.. doxygentypedef:: voidFuncPtr
+
+Discussion
+----------
+
+Because the function will run in interrupt context, inside of it,
+:ref:`lang-delay` won't work, and the value returned by
+:ref:`lang-millis` will not increment. Serial data received while
+in the function may be lost. You should declare as ``volatile`` any
+global variables that you modify within the attached function.
+
+There are a few constraints you should be aware of if you're using
+more than one interrupt at a time; the :ref:`external-interrupts` page
+has the details.
+
+Using Interrupts
+----------------
+
+Interrupts are useful for making things happen automatically in
+microcontroller programs, and can help solve timing problems. A
+good task for using an interrupt might be reading a rotary encoder,
+or monitoring user input.
+
+If you wanted to insure that a program always caught the pulses
+from a rotary encoder, never missing a pulse, it would make it very
+tricky to write a program to do anything else, because the program
+would need to constantly poll the sensor lines for the encoder, in
+order to catch pulses when they occurred. Other sensors have a
+similar interface dynamic too, such as trying to read a sound
+sensor that is trying to catch a click, or an infrared slot sensor
+(photo-interrupter) trying to catch a coin drop. In all of these
+situations, using an interrupt can free the microcontroller to get
+some other work done while not missing the doorbell.
+
+Example
+-------
+
+::
+
+ int maple_led_pin = 13;
+ volatile int state = LOW; // must declare volatile, since it's
+ // modified within the blink handler
+
+ void setup() {
+ pinMode(maple_led_pin, OUTPUT);
+ attachInterrupt(0, blink, CHANGE);
+ }
+
+ void loop() {
+ digitalWrite(maple_led_pin, state);
+ }
+
+ void blink() {
+ state = !state;
+ }
+
+Arduino Compatibility
+---------------------
+
+Most Arduino boards have two external interrupts: numbers 0 (on
+digital pin 2) and 1 (on digital pin 3). The Arduino Mega has an
+additional four: numbers 2 (pin 21), 3 (pin 20), 4 (pin 19), and 5
+(pin 18). On the Maple, you don't have to remember which interrupt
+number goes with which pin -- just tell ``attachInterrupt()`` the pin
+you want.
+
+See also
+--------
+
+- :ref:`detachInterrupt <lang-detachinterrupt>`
+- :ref:`external-interrupts`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/bit.rst b/docs/source/lang/api/bit.rst
new file mode 100644
index 0000000..dd5c050
--- /dev/null
+++ b/docs/source/lang/api/bit.rst
@@ -0,0 +1,44 @@
+.. _lang-bit:
+
+bit()
+=====
+
+(Macro) Computes the value of an (unsigned) integer with the specified
+bit set (``bit(0)`` is 1, ``bit(1)`` is 2, ``bit(2)`` is 4, then 8,
+16, 32, etc.).
+
+Syntax
+------
+
+``bit(n)``
+
+
+Parameters
+----------
+
+* **n** the bit to set.
+
+
+Value
+-----
+
+The value of an integer with the given bit set.
+
+
+Arduino Compatibility
+---------------------
+
+The Maple implementation of bit is compatible with Arduino.
+
+
+See also
+--------
+
+
+- :ref:`lang-bitread`
+- :ref:`lang-bitwrite`
+- :ref:`lang-bitset`
+- :ref:`lang-bitclear`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/bitclear.rst b/docs/source/lang/api/bitclear.rst
new file mode 100644
index 0000000..941f912
--- /dev/null
+++ b/docs/source/lang/api/bitclear.rst
@@ -0,0 +1,44 @@
+.. _lang-bitclear:
+
+bitClear()
+==========
+
+(Macro) Clears (writes a 0 to) a bit of a numeric variable.
+
+Syntax
+------
+
+``bitClear(x, n)``
+
+
+Parameters
+----------
+
+* **x** the numeric variable whose bit to clear
+
+* **n** which bit to clear, starting at 0 for the least-significant
+ (rightmost) bit
+
+
+Returns
+-------
+
+None.
+
+
+Arduino Compatibility
+---------------------
+
+This implementation is compatible with that of Arduino.
+
+
+See also
+--------
+
+- :ref:`bit <lang-bit>`\ ()
+- :ref:`bitRead <lang-bitread>`\ ()
+- :ref:`bitWrite <lang-bitwrite>`\ ()
+- :ref:`bitSet <lang-bitset>`\ ()
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/bitread.rst b/docs/source/lang/api/bitread.rst
new file mode 100644
index 0000000..46b4478
--- /dev/null
+++ b/docs/source/lang/api/bitread.rst
@@ -0,0 +1,46 @@
+.. _lang-bitread:
+
+bitRead()
+=========
+
+(Macro) Gets the value of a bit in a number.
+
+
+Syntax
+------
+
+``bitRead(x, n)``
+
+
+Parameters
+----------
+
+* **x** the number from which to read the bit.
+
+* **n** which bit to read, starting at 0 for the least-significant
+ (rightmost) bit
+
+
+Value
+-----
+
+The value of the bit (0 or 1).
+
+
+Arduino Compatibility
+---------------------
+
+The Maple implementation of ``bitRead`` is compatible with Arduino.
+
+
+See also
+--------
+
+
+- :ref:`lang-bit`
+- :ref:`lang-bitwrite`
+- :ref:`lang-bitset`
+- :ref:`lang-bitclear`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/bitset.rst b/docs/source/lang/api/bitset.rst
new file mode 100644
index 0000000..ccd76de
--- /dev/null
+++ b/docs/source/lang/api/bitset.rst
@@ -0,0 +1,46 @@
+.. _lang-bitset:
+
+bitSet()
+========
+
+(Macro) Sets (writes a 1 to) a bit of a numeric variable.
+
+
+Syntax
+------
+
+``bitSet(x, n)``
+
+
+Parameters
+----------
+
+* **x** the numeric variable whose bit to set
+
+* **n** which bit to set, starting at 0 for the least-significant
+ (rightmost) bit
+
+
+Value
+-----
+
+None.
+
+
+Arduino Compatibility
+---------------------
+
+The Maple implementation of bitSet is compatible with Arduino.
+
+
+See Also
+--------
+
+- :ref:`lang-bit`
+- :ref:`lang-bitread`
+- :ref:`lang-bitwrite`
+- :ref:`lang-bitclear`
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/bitwrite.rst b/docs/source/lang/api/bitwrite.rst
new file mode 100644
index 0000000..b3feff2
--- /dev/null
+++ b/docs/source/lang/api/bitwrite.rst
@@ -0,0 +1,46 @@
+.. highlight:: cpp
+
+.. _lang-bitwrite:
+
+bitWrite()
+==========
+
+(Macro) Writes a bit of a numeric variable.
+
+Syntax
+------
+
+::
+
+ bitWrite(x, n, b)
+
+Parameters
+----------
+
+**x**: the numeric variable whose bit to write.
+
+**n**: which bit of the number to write, starting at 0 for the
+least-significant (rightmost) bit.
+
+**b**: the value to write to the bit (0 or 1).
+
+Returns
+-------
+
+Nothing.
+
+Arduino Compatibility
+---------------------
+
+Maple's version of ``bitWrite()`` is compatible with Arduino.
+
+See also
+--------
+
+- :ref:`bit() <lang-bit>`
+- :ref:`bitRead() <lang-bitRead>`
+- :ref:`bitSet() <lang-bitSet>`
+- :ref:`bitClear() <lang-bitClear>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/cc-attribution.txt b/docs/source/lang/api/cc-attribution.txt
new file mode 100644
index 0000000..e100140
--- /dev/null
+++ b/docs/source/lang/api/cc-attribution.txt
@@ -0,0 +1,9 @@
+.. Included in all this directory's files in order to satisfy the
+.. Arduino CC Attribution-ShareAlike 3.0 License
+
+.. admonition:: License and Attribution
+
+ This documentation page was adapted from the `Arduino Reference
+ Documentation <http://arduino.cc/en/Reference/HomePage>`_\ , which
+ is released under a `Creative Commons Attribution-ShareAlike 3.0
+ License <http://creativecommons.org/licenses/by-sa/3.0/>`_.
diff --git a/docs/source/lang/api/constants.rst b/docs/source/lang/api/constants.rst
new file mode 100644
index 0000000..72738b8
--- /dev/null
+++ b/docs/source/lang/api/constants.rst
@@ -0,0 +1,337 @@
+.. _lang-constants:
+
+Constants
+=========
+
+Constants are like predefined variables, whose values can't
+change. They are used to make the programs easier to read and modify.
+This page describes the most commonly used constants.
+
+.. contents:: Contents
+ :local:
+
+.. _lang-constants-bool:
+
+Boolean Constants
+-----------------
+
+There are two constants used to represent truth and falsity: ``true``,
+and ``false``.
+
+.. _lang-constants-false:
+
+false
+^^^^^
+
+``false`` is the false ``bool`` value. An integer which is 0 evaluates
+to ``false`` as a boolean.
+
+.. _lang-constants-true:
+
+true
+^^^^
+
+``true`` is the true ``bool`` value. As an integer, ``true`` is often
+said to be 1. This is correct in the sense that ``true`` evaluates to
+1 as an integer. However, any integer which is *non-zero* is ``true``
+as a :ref:`bool <lang-booleanvariables>`. So -1, 2 and -200 are all
+"true", in the sense that these numbers are treated the same as
+``true`` in a boolean context.
+
+Note that the ``true`` and ``false`` constants are typed in lowercase;
+unlike e.g. ``HIGH``, ``LOW``, ``INPUT``, and ``OUTPUT`` (which are
+described below).
+
+
+Pin Levels: HIGH and LOW
+------------------------
+
+When reading or writing to a digital pin there are only two possible
+values a pin can be set to: ``HIGH`` and ``LOW``.
+
+.. _lang-constants-high:
+
+HIGH
+^^^^
+
+The meaning of ``HIGH`` (in reference to a pin) is somewhat different
+depending on whether the pin is set to ``INPUT`` or ``OUTPUT``. When a
+pin is configured as an ``INPUT`` (using :ref:`pinMode()
+<lang-pinmode>`), and read with :ref:`digitalRead()
+<lang-digitalread>`, the microcontroller will report ``HIGH`` if a
+voltage of 3 volts or more is present at the pin.
+
+.. TODO? Following seems false; check it out sometime, leave out for now:
+
+.. A pin may also be configured as an ``INPUT`` with ``pinMode()``, and
+.. subsequently made ``HIGH`` with :ref:`digitalWrite()
+.. <lang-digitalwrite>`, this will set the internal pullup resistors,
+.. which will *steer* the input pin to a HIGH reading unless it is pulled
+.. LOW by external circuitry.
+
+When a pin is configured to ``OUTPUT`` with pinMode, and set to
+``HIGH`` with :ref:`digitalWrite() <lang-digitalwrite>`, the pin is at
+3.3 volts. In this state it can *source* current, e.g. light an LED
+that is connected through a series resistor to ground, or to another
+pin configured as an output and set to ``LOW``.
+
+.. _lang-constants-low:
+
+LOW
+^^^
+
+The meaning of ``LOW`` also has a different meaning depending on
+whether a pin is set to ``INPUT`` or ``OUTPUT``. When a pin is
+configured as an ``INPUT`` with :ref:`pinMode() <lang-pinmode>`, and
+read with :ref:`digitalRead() <lang-digitalread>`, the microcontroller
+will report ``LOW`` if a voltage of 2 volts or less is present at the
+pin.
+
+When a pin is configured to ``OUTPUT`` with ``pinMode()``, and set to
+``LOW`` with :ref:`digitalWrite() <lang-digitalwrite>`, the
+microcontroller will attempt to keep that pin's voltage at 0V. In this
+state it can *sink* current, e.g. light an LED that is connected
+through a series resistor to +3.3V, or to another pin configured as an
+output, and set to ``HIGH``.
+
+Pin Modes
+---------
+
+Digital pins can be used in a variety of modes. The basic modes,
+``INPUT`` and ``OUTPUT``, have been introduced above. Changing a pin
+from ``INPUT`` TO ``OUTPUT`` with :ref:`pinMode() <lang-pinmode>`
+drastically changes the electrical behavior of the pin.
+
+This section describes the basic digital pin modes (``INPUT`` and
+``OUTPUT``) only. For a detailed description of all possible pin
+modes, see the :ref:`pinMode() <lang-pinmode>` reference page.
+
+.. _lang-constants-input:
+
+INPUT
+^^^^^
+
+Maple (STM32) pins configured as ``INPUT`` are said to be in a
+high-impedance state. One way of explaining this is that pins
+configured as ``INPUT`` make extremely small demands on the circuit
+that they are sampling. This makes them useful for reading a sensor,
+but not powering an LED.
+
+.. _lang-constants-output:
+
+OUTPUT
+^^^^^^
+
+Pins configured as ``OUTPUT`` with :ref:`pinMode() <lang-pinmode>` are
+said to be in a low-impedance state. This means that they can provide
+a substantial amount of current to other circuits. STM32 pins can
+source (provide positive current) or sink (provide negative current)
+up to 50 mA (milliamps) of current to other devices/circuits. This
+makes them useful for powering LEDs, but useless for reading sensors.
+
+Pins configured as outputs can also be damaged or destroyed if short
+circuited to either ground or 3.3V power rails. The amount of current
+provided by an STM32 pin is also not enough to power most relays or
+motors, and some interface circuitry will be required.
+
+.. _lang-constants-integers:
+
+Integer Constants
+-----------------
+
+Integer constants (or more properly speaking, integer *literals*) are
+numbers used directly in a sketch, like ``123``. By default, an
+integer literal is treated as a (signed) :ref:`int <lang-int>`, but
+you can change this with the U and L modifiers (see :ref:`below
+<lang-constants-integers-u-l>`). You can specify negative numbers by
+putting a minus sign in front, like ``-123``.
+
+Normally, integer literals are treated as base 10 (decimal) integers,
+but special notation (formatters) may be used to enter numbers in
+other bases. These are summarized in the following table:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Base
+ - Example
+ - Formatter
+ - Comment
+
+ * - 10 (decimal)
+ - ``123``
+ - None
+ -
+
+ * - 2 (binary)
+ - ``0b1111011``
+ - Leading "0b"
+ - GCC extension; not standard C++
+
+ * - 8 (octal)
+ - ``0173``
+ - Leading "0"
+ - Characters 0-7 valid
+
+ * - 16 (hexadecimal)
+ - ``0x7B``
+ - Leading "0x"
+ - Characters 0-9, A-F (or a-f) valid
+
+Binary constants (like ``B1111011``) for values between 0 and 255 are
+supported for compatibility with Arduino only. Their use in new
+programs is discouraged.
+
+.. _lang-constants-integers-dec:
+
+**Decimal** is base 10. This is the common number system we learn in
+school. Integer literals without other prefixes are assumed to be in
+decimal format.
+
+For example, the decimal literal ``101`` is one hundred and one: 1×10\
+:sup:`2` + 0×10\ :sup:`1` + 1×10\ :sup:`0` = 101.
+
+.. _lang-constants-integers-bin:
+
+**Binary** is base two. Only characters 0 and 1 are valid. Binary
+literals are indicated by the prefix ``0b`` (this is a :ref:`GCC
+<arm-gcc>` extension; it's not standard C++).
+
+For example, the binary literal ``0b101`` is five: 1×2\ :sup:`2` +
+0×2\ :sup:`1` + 1×2\ :sup:`0` = 5.
+
+.. _lang-constants-integers-oct:
+
+**Octal** is base eight. Only characters 0 through 7 are valid. Octal
+literals are indicated by the prefix ``0``.
+
+For example, the octal literal ``0101`` is sixty five: 1×8\ :sup:`2` +
+0×8\ :sup:`1` + 1×8\ :sup:`0` = 65.
+
+.. warning:: Bugs sometimes result by (unintentionally) including a
+ leading "0" before an integer literal, which makes the compiler
+ interpret it in octal.
+
+.. _lang-constants-integers-hex:
+
+**Hexadecimal** (or "hex") is base sixteen. Valid characters are 0
+through 9 and letters A through F; A has the value 10, B is 11, up to
+F, which is 15. Hex values are indicated by the prefix ``0x``. A-F
+may be typed in upper or lower case (a-f).
+
+For example, the hexadecimal literal ``0x101`` is two hundred fifty
+seven: 1×16\ :sup:`2` + 0×16\ :sup:`1` + 1×16\ :sup:`0` = 257.
+
+The hexadecimal literal ``0xCF2`` is three thousand, three hundred
+fourteen: 12×16\ :sup:`2` + 15×16\ :sup:`1` + 2×16\ :sup:`0` = 3314.
+
+(Remember that in hex, ``A`` means 10, and counting up, ``B``\ =11, so
+``C``\ =12 and ``F``\ =15).
+
+.. _lang-constants-integers-u-l:
+
+U and L Suffixes
+^^^^^^^^^^^^^^^^
+
+By default, an integer constant is treated as an :ref:`int
+<lang-int>`, with the attendant :ref:`limitations in values
+<lang-int-overflow>`. To specify an integer constant with another data
+type, follow it with:
+
+- a ``u`` or ``U`` to interpret the constant as an unsigned value.
+ For example, ``33U`` is an :ref:`unsigned int <lang-unsignedint>`.
+
+- an ``l`` or ``L`` to interpret the constant as a long value. For
+ example, ``100000L`` is a :ref:`long <lang-long>`. On the Maple,
+ ``long`` is just a synonym for ``int``.
+
+- a ``ul`` or ``UL`` to do both. For example, ``32767UL`` is an
+ :ref:`unsigned long <lang-unsignedlong>`. On the Maple, ``unsigned
+ long`` is just a synonym for ``unsigned int``.
+
+- an ``ll`` or ``LL`` to interpret the constant as a :ref:`long long
+ <lang-longlong>` value.
+
+- a ``ull`` or ``ULL`` to interpret the constant as an :ref:`unsigned
+ long long <lang-unsignedlonglong>`.
+
+.. _lang-constants-fp:
+
+Floating-Point Constants
+------------------------
+
+Similar to integer literals, floating point constants (properly:
+floating-point *literals*) are used to make code more readable.
+Floating point literals are swapped at compile time for the value to
+which the expression evaluates.
+
+A floating point literal is any number which includes a decimal point.
+For instance, ``3.0`` is a floating-point literal for the number 3.
+By default, a floating-point literal is a :ref:`double <lang-double>`.
+In order for the literal to be interpreted as a :ref:`float
+<lang-float>`, you can write ``f`` directly after it. For example,
+``3.0f`` is a floating-point literal with type ``float``.
+
+Floating point constants can also be expressed in a variety of
+scientific notation. ``E`` and ``e`` are both accepted as valid
+exponent indicators. Some examples are given in the following table:
+
+
+.. list-table::
+ :header-rows: 1
+
+ * - Floating-point literal
+ - Evaluates to
+ - Alternate expression
+
+ * - ``10.0``
+ - 10
+ -
+
+ * - ``2.34E5``
+ - 2.34×10\ :sup:`5`
+ - ``234000.0``
+
+ * - ``67e-12``
+ - 67.0×10\ :sup:`-12`
+ - ``0.000000000067``
+
+.. _lang-constants-board:
+
+Board-Specific Constants
+------------------------
+
+This section documents constants whose value might change across
+different LeafLabs boards. You can use these constants to help ensure
+that your code will be portable across different boards.
+
+.. TODO replace "upcoming" when Mini, Native come out
+
+.. _lang-constants-led:
+
+- ``BOARD_LED_PIN``: the number of the pin which connects to the
+ built-in LED. On the Maple, this is pin 13, but it's not guaranteed
+ to be the same in upcoming boards like the Maple Mini.
+
+.. _lang-constants-but:
+
+- ``BOARD_BUTTON_PIN``: the number of the pin which connects to the
+ built-in button (labeled "BUT"). On the Maple, this is pin 38, but
+ it's not guaranteed to be the same in other boards.
+
+See Also
+--------
+
+- :ref:`pinMode() <lang-pinmode>`
+- :ref:`Boolean Variables <lang-booleanvariables>`
+- :ref:`#define <lang-define>`
+- :ref:`int <lang-int>`
+- :ref:`unsigned int <lang-unsignedint>`
+- :ref:`long <lang-long>`
+- :ref:`unsigned long <lang-unsignedlong>`
+- :ref:`long long <lang-longlong>`
+- :ref:`unsigned long long <lang-unsignedlonglong>`
+- :ref:`float <lang-float>`
+- :ref:`double <lang-double>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/constrain.rst b/docs/source/lang/api/constrain.rst
new file mode 100644
index 0000000..d19b61c
--- /dev/null
+++ b/docs/source/lang/api/constrain.rst
@@ -0,0 +1,69 @@
+.. highlight:: cpp
+
+.. _lang-constrain:
+
+constrain()
+===========
+
+(Macro) Constrains a number to be within a range.
+
+Syntax
+------
+
+::
+
+ constrain(x, a, b)
+
+
+Parameters
+----------
+
+**x**: the number to constrain
+
+**a**: the lower end of the range
+
+**b**: the upper end of the range
+
+Returns
+-------
+
+**x**: if **x** is between **a** and **b**
+
+**a**: if **x** is less than **a**
+
+**b**: if **x** is greater than **b**
+
+Example
+-------
+
+::
+
+ // limits range of sensor values to between 10 and 150:
+ sensVal = constrain(sensVal, 10, 150);
+
+
+Warning
+-------
+
+Because of the way ``constrain()`` is implemented, avoid using other
+functions or causing side effects inside the parentheses, as it may
+lead to incorrect results::
+
+ constrain(x,a++,b); // avoid this - yields incorrect results
+
+ constrain(x,a,b); // use this instead-
+ a++; // keep other math outside constrain()
+
+Arduino Compatibility
+---------------------
+
+Maple's implementation of ``constrain()`` is compatible with Arduino.
+
+See also
+--------
+
+- :ref:`min() <lang-min>`
+- :ref:`max() <lang-max>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/cos.rst b/docs/source/lang/api/cos.rst
new file mode 100644
index 0000000..3fbb0af
--- /dev/null
+++ b/docs/source/lang/api/cos.rst
@@ -0,0 +1,32 @@
+.. _lang-cos:
+
+cos()
+=====
+
+Calculates the cosine of an angle.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: cos
+
+Arduino Compatibility
+---------------------
+
+The Maple ``cos()`` implementation is compatible with Arduino.
+
+Note that the Maple implementation comes from `newlib
+<http://sourceware.org/newlib/>`_\ , while Arduino's is that of
+`avr-libc <http://avr-libc.nongnu.org/>`_\ .
+
+See also
+--------
+
+
+- :ref:`sin() <lang-sin>`
+- :ref:`tan() <lang-tan>`
+- :ref:`float <lang-float>`
+- :ref:`double <lang-double>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/delay.rst b/docs/source/lang/api/delay.rst
new file mode 100644
index 0000000..90ca268
--- /dev/null
+++ b/docs/source/lang/api/delay.rst
@@ -0,0 +1,72 @@
+.. highlight:: cpp
+
+.. _lang-delay:
+
+delay()
+=======
+
+Pauses the program for at least a given number of milliseconds. (There
+are 1000 milliseconds in a second.)
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: delay
+
+
+Discussion
+----------
+
+While it is easy to create a blinking LED with the ``delay()``
+function, and many sketches use short delays for such tasks as switch
+debouncing, the use of ``delay()`` in a sketch has significant
+drawbacks. No other reading of sensors, mathematical calculations, or
+pin manipulation can go on during the delay function, so in effect, it
+brings most other activity to a halt. For alternative approaches to
+controlling timing see the :ref:`millis() <lang-millis>` function
+and the "Blink Without Delay" sketch cited :ref:`below
+<lang-delay-seealso>`\ . More knowledgeable programmers usually
+avoid the use of ``delay()`` for timing of events longer than tens of
+milliseconds, unless the sketch is very simple.
+
+Certain things *do* go on while the ``delay()`` function is
+controlling the STM32 chip, however, because the delay function does
+not disable interrupts. Serial communication that appears at the RX
+pin is recorded, PWM (see :ref:`pwmWrite() <lang-pwmwrite>`\ ) values
+and pin states are maintained, and :ref:`interrupts
+<lang-attachinterrupt>` will work as they should.
+
+
+Example
+-------
+
+::
+
+ int ledPin = 13; // LED connected to pin 13
+
+ void setup() {
+ pinMode(ledPin, OUTPUT); // sets the digital pin as output
+ }
+
+ void loop() {
+ digitalWrite(ledPin, HIGH); // sets the LED on
+ delay(1000); // waits for a second
+ digitalWrite(ledPin, LOW); // sets the LED off
+ delay(1000); // waits for a second
+ }
+
+.. _lang-delay-seealso:
+
+See also
+--------
+
+
+- :ref:`millis() <lang-millis>`
+- :ref:`micros() <lang-micros>`
+- :ref:`delayMicroseconds() <lang-delayMicroseconds>`
+- (Arduino) `Blink Without Delay
+ <http://arduino.cc/en/Tutorial/BlinkWithoutDelay>`_ example (works
+ unmodified on Maple)
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/delaymicroseconds.rst b/docs/source/lang/api/delaymicroseconds.rst
new file mode 100644
index 0000000..24a8286
--- /dev/null
+++ b/docs/source/lang/api/delaymicroseconds.rst
@@ -0,0 +1,65 @@
+.. highlight:: cpp
+
+.. _lang-delaymicroseconds:
+
+delayMicroseconds()
+===================
+
+Pauses the program for the amount of time (in microseconds)
+specified as parameter. There are a thousand microseconds in a
+millisecond, and a million microseconds in a second.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: delayMicroseconds
+
+
+Example
+-------
+
+The following example configures pin number 8 to work as an output
+pin, and sends a train of pulses with a period of roughly 100
+microseconds::
+
+ int outPin = 8;
+
+ void setup() {
+ pinMode(outPin, OUTPUT); // sets the digital pin as output
+ }
+
+ void loop() {
+ digitalWrite(outPin, HIGH); // sets the pin on
+ delayMicroseconds(50); // pauses for 50 microseconds
+ digitalWrite(outPin, LOW); // sets the pin off
+ delayMicroseconds(50); // pauses for 50 microseconds
+ }
+
+
+Caveats and Known Issues
+------------------------
+
+The longest time ``delayMicroseconds()`` can delay is bounded by its
+argument type and the STM32 clock rate to be (2^32 - 1) / 12
+microseconds, or less than 6 minutes. For longer pauses, use of
+:ref:`lang-delay` is possible.
+
+Arduino Compatibility
+---------------------
+
+While we have made every effort we could to ensure that the timing of
+delayMicroseconds is as accurate as possible, we cannot guarantee it
+will behave as the Arduino implementation down to the microsecond,
+especially for smaller values of ``us``.
+
+See Also
+--------
+
+- :ref:`millis <lang-millis>`
+- :ref:`micros <lang-micros>`
+- :ref:`delay <lang-delay>`
+
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/detachinterrupt.rst b/docs/source/lang/api/detachinterrupt.rst
new file mode 100644
index 0000000..41642a7
--- /dev/null
+++ b/docs/source/lang/api/detachinterrupt.rst
@@ -0,0 +1,43 @@
+.. _lang-detachinterrupt:
+
+detachInterrupt()
+=================
+
+Used to disable an interrupt specified with
+:ref:`lang-attachinterrupt`\ .
+
+Library Documentation
+---------------------
+
+.. FIXME once breathe knows how to get the correct detachInterupt
+.. (right now it's copying from HardwareTimer), replace with a
+.. doxygenfunction directive
+
+.. cpp:function:: void detachInterrupt(uint8 pin)
+
+ Disable any registered external interrupt on the given pin.
+
+ *Parameters*
+
+ - ``pin`` Maple pin number
+
+Arduino Compatibility
+---------------------
+
+There is one important difference between the Maple version of
+detachInterrupt and the Arduino version. On the Maple, the argument
+to ``detachInterrupt()`` is the *pin* on which the interrupt is
+attached, while on the Arduino, the argument is the *interrupt
+number*, which is different from the pin the interrupt is enabled on.
+
+If you're calling this function, you've already called
+:ref:`lang-attachinterrupt` to set up your interrupt handler, so
+just call ``detachInterrupt()`` with the same pin argument you gave to
+``attachInterrupt()``.
+
+See Also
+--------
+
+- :ref:`attachInterrupt() <lang-attachInterrupt>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/digitalread.rst b/docs/source/lang/api/digitalread.rst
new file mode 100644
index 0000000..3502587
--- /dev/null
+++ b/docs/source/lang/api/digitalread.rst
@@ -0,0 +1,58 @@
+.. highlight:: cpp
+
+.. _lang-digitalread:
+
+digitalRead()
+=============
+
+Reads the value from a specified digital pin, either :ref:`HIGH
+<lang-constants-high>` or :ref:`LOW <lang-constants-low>`.
+
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: digitalRead
+
+
+Example
+-------
+
+The following example turns the LED on when the button is pressed::
+
+ int ledPin = 13; // LED connected to Maple pin 13
+ int buttonPin = 38; // BUT connected to Maple pin 38
+
+ void setup() {
+ pinMode(ledPin, OUTPUT);
+ pinMode(buttonPin, INPUT);
+ }
+
+ void loop() {
+ int val = digitalRead(buttonPin); // reads the input pin
+ digitalWrite(ledPin, val);
+ }
+
+Note
+----
+
+If the pin isn't connected to anything, ``digitalRead()`` can return
+either HIGH or LOW (and this can change in a way that seems random).
+
+Arduino Compatibility
+---------------------
+
+The Maple version of ``digitalRead()`` is compatible with Arduino.
+
+
+See Also
+--------
+
+- :ref:`pinMode <lang-pinMode>`
+- :ref:`digitalWrite <lang-digitalWrite>`
+
+
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/digitalwrite.rst b/docs/source/lang/api/digitalwrite.rst
new file mode 100644
index 0000000..6124d5f
--- /dev/null
+++ b/docs/source/lang/api/digitalwrite.rst
@@ -0,0 +1,68 @@
+.. highlight:: cpp
+
+.. _lang-digitalwrite:
+
+digitalWrite()
+==============
+
+Write a :ref:`HIGH <lang-constants-high>` or a :ref:`LOW
+<lang-constants-low>` value to a pin configured as :ref:`OUTPUT
+<lang-constants-output>`.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: digitalWrite
+
+Discussion
+----------
+
+If the pin has been configured as an ``OUTPUT`` with :ref:`pinMode()
+<lang-pinmode>` its voltage will be set to the corresponding value:
+3.3V for ``HIGH``, and 0V (ground) for ``LOW``.
+
+.. TODO make the following paragraphs true, but refer the reader to
+.. INPUT_PULLUP and INPUT_PULLDOWN:
+
+If the pin is configured as an ``INPUT``, writing a ``HIGH`` value
+with ``digitalWrite()`` will enable an internal pullup resistor.
+Writing ``LOW`` will disable the pullup. The pullup resistor is enough
+to light an LED dimly, so if LEDs appear to work, but very dimly, this
+is a likely cause. The remedy is to set the pin to an output with the
+:ref:`pinMode() <lang-pinmode>` function.
+
+.. note:: Pin 13 is harder to use as an input than the other pins
+ because it has an LED and resistor soldered to it in series. If you
+ enable its internal pull-up resistor, it will likely hang at around
+ 1.1V instead of the expected 3.3V because the onboard LED and
+ series resistor pull the voltage level down. If you must use pin 13
+ as a digital input, use an external pull-down resistor.
+
+Example
+-------
+
+The following example sets pin 13 to ``HIGH``, makes a one-second-long
+delay, sets the pin back to ``LOW``, and delays again, causing a
+blinking pattern::
+
+
+ int ledPin = 13; // LED connected to digital pin 13
+
+ void setup() {
+ pinMode(ledPin, OUTPUT); // sets the digital pin as output
+ }
+
+ void loop() {
+ digitalWrite(ledPin, HIGH); // sets the LED on
+ delay(1000); // waits for a second
+ digitalWrite(ledPin, LOW); // sets the LED off
+ delay(1000); // waits for a second
+ }
+
+See Also
+--------
+
+- :ref:`pinMode <lang-pinmode>`
+- :ref:`digitalRead <lang-digitalread>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/hardwarespi.rst b/docs/source/lang/api/hardwarespi.rst
new file mode 100644
index 0000000..c71b2c3
--- /dev/null
+++ b/docs/source/lang/api/hardwarespi.rst
@@ -0,0 +1,152 @@
+.. highlight:: cpp
+
+.. _lang-hardwarespi:
+
+HardwareSPI
+===========
+
+This class is used for creating objects to manage the Maple's built-in
+SPI ports. The Maple has two SPI ports. The relevant pins
+corresponding to each port's logic signals are documented in the
+following table (and on the Maple silkscreen):
+
+.. _lang-hardwarespi-pinout:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Port number
+ - NSS
+ - MOSI
+ - MISO
+ - SCK
+
+ * - 1
+ - 10
+ - 11
+ - 12
+ - 13
+
+ * - 2
+ - 31
+ - 32
+ - 33
+ - 34
+
+If you use a SPI port, you cannot simultaneously use its associated
+pins for other purposes.
+
+Library Documentation
+---------------------
+
+HardwareSPI Class Reference
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You can use the SPI interface by including a declaration ``HardwareSPI
+Spi(number);`` at the start of the sketch or program. The ``number``
+must be either 1 or 2 and specifies which port to use. Once this is
+done, you can call any of the methods documented here using
+``Spi.method(arguments)``; for example, ``Spi.send(0x13)`` would send
+the value ``0x13`` into the port buffer to be transmitted as soon as
+possible.
+
+.. cpp:class:: HardwareSPI
+
+ Class for interacting with SPI.
+
+.. cpp:function:: HardwareSPI::HardwareSPI(uint32 spi_num)
+
+ Construct an object for managing a SPI peripheral. ``spi_num``
+ must be 1 or 2; see the :ref:`table above
+ <lang-hardwarespi-pinout>` for pinout information.
+
+.. cpp:function:: void HardwareSPI::begin(SPIFrequency freq, uint32 endianness, uint32 mode)
+
+ Configure the baudrate of the given SPI port and set up the header
+ pins appropriately.
+
+ Parameters:
+
+ - ``freq``: one of the ``SPIFrequency`` values, given :ref:`below
+ <lang-hardwarespi-spifrequency>`.
+
+ - ``endianness``: either ``LSBFIRST`` (little-endian) or
+ ``MSBFIRST`` (big-endian).
+
+ - ``mode``: one of 0, 1, 2, or 3, and specifies which SPI mode is
+ used. The mode number determines a combination of polarity and
+ phase according to the following table:
+
+ .. list-table::
+ :header-rows: 1
+
+ * - Mode
+ - Polarity
+ - Phase
+
+ * - 0
+ - 0
+ - 0
+
+ * - 1
+ - 0
+ - 1
+
+ * - 2
+ - 1
+ - 0
+
+ * - 3
+ - 1
+ - 1
+
+ For more information on polarity and phase, see the
+ :ref:`external references, below <lang-hardwarespi-seealso>`.
+
+.. cpp:function:: void HardwareSPI::begin()
+
+ A convenience ``begin()``, equivalent to ``begin(SPI_1_125MHZ,
+ MSBFIRST, 0)``.
+
+.. cpp:function:: uint8 HardwareSpi::send(uint8 *data, uint32 length)
+
+ Writes ``data`` into the port buffer to be transmitted as soon as
+ possible, where ``length`` is the number of bytes to send from
+ ``data``. Returns the last byte shifted back from slave.
+
+.. cpp:function:: uint8 HardwareSpi::send(uint8 data)
+
+ Writes the single byte ``data`` into the port buffer to be
+ transmitted as soon as possible. Returns the data byte shifted
+ back from the slave.
+
+.. cpp:function:: uint8 HardwareSpi::recv()
+
+ Reads a byte from the peripheral. Returns the next byte in the
+ buffer.
+
+SPI Speeds
+^^^^^^^^^^
+
+.. _lang-hardwarespi-spifrequency:
+
+The possible SPI speeds are configured using the ``SPIFrequency`` enum:
+
+.. doxygenenum:: SPIFrequency
+
+.. _lang-hardwarespi-seealso:
+
+See Also
+--------
+
+* `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:
+
+ * `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/docs/source/lang/api/hardwaretimer.rst b/docs/source/lang/api/hardwaretimer.rst
new file mode 100644
index 0000000..3e5424c
--- /dev/null
+++ b/docs/source/lang/api/hardwaretimer.rst
@@ -0,0 +1,370 @@
+.. highlight:: cpp
+
+.. _lang-hardwaretimer:
+
+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>`.
+
+Library Documentation
+---------------------
+
+HardwareTimer Class Reference
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+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)``.
+
+.. cpp:class:: HardwareTimer
+
+ Class for interacting with a timer. There are four predefined
+ instances available on the Maple: ``Timer1``, ``Timer2``,
+ ``Timer3``, and ``Timer4``.
+
+.. _lang-hardwaretimer-attachinterrupt:
+
+.. cpp:function:: void HardwareTimer::attachInterrupt(int channel, voidFuncPtr handler)
+
+ 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.
+
+ ``handler`` should be a function which takes no arguments and has
+ :ref:`void <lang-void>` value; i.e. it should have signature ::
+
+ 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 the full :ref:`pin mapping table
+ <pin-mapping-mega-table>` 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()
+
+ Equivalent to :ref:`getCompare <lang-hardwaretimer-getcompare>`\
+ ``(4, mode)``.
+
+.. _lang-hardwaretimer-setcompare:
+
+.. cpp:function:: void HardwareTimer::setCompare(int channel, uint16 compare)
+
+ 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).
+
+ 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>`.
+
+ 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.
+
+.. cpp:function:: void HardwareTimer::setCompare1(uint16 compare)
+
+ Equivalent to :ref:`setCompare <lang-hardwaretimer-setcompare>`\
+ ``(1, compare)``.
+
+.. cpp:function:: void HardwareTimer::setCompare2(uint16 compare)
+
+ Equivalent to :ref:`setCompare <lang-hardwaretimer-setcompare>`\
+ ``(2, compare)``.
+
+.. cpp:function:: void HardwareTimer::setCompare3(uint16 compare)
+
+ Equivalent to :ref:`setCompare <lang-hardwaretimer-setcompare>`\
+ ``(3, compare)``.
+
+.. cpp:function:: void HardwareTimer::setCompare4(uint16 compare)
+
+ Equivalent to :ref:`setCompare <lang-hardwaretimer-setcompare>`\
+ ``(4, compare)``.
+
+.. cpp:function:: uint16 HardwareTimer::getCount()
+
+ 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>`.
+
+.. _lang-hardwaretimer-setcount:
+
+.. cpp:function:: void HardwareTimer::setCount(uint16 val)
+
+ Set the timer's current count to ``val``.
+
+ 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.
+
+ If ``val`` exceeds the timer's :ref:`overflow value
+ <lang-hardwaretimer-getoverflow>`, it is truncated to the overflow
+ value.
+
+
+.. _lang-hardwaretimer-detachinterrupt:
+
+.. cpp:function:: void HardwareTimer::detachInterrupt(int channel)
+
+ Remove the interrupt handler attached to the given ``channel``, if
+ any. The handler will no longer be called by this timer.
+
+.. cpp:function:: void HardwareTimer::detachCompare1Interrupt()
+
+ Equivalent to :ref:`detachInterrupt
+ <lang-hardwaretimer-detachinterrupt>`\ ``(1)``.
+
+.. cpp:function:: void HardwareTimer::detachCompare2Interrupt()
+
+ Equivalent to :ref:`detachInterrupt
+ <lang-hardwaretimer-detachinterrupt>`\ ``(2)``.
+
+.. cpp:function:: void HardwareTimer::detachCompare3Interrupt()
+
+ Equivalent to :ref:`detachInterrupt
+ <lang-hardwaretimer-detachinterrupt>`\ ``(3)``.
+
+.. cpp:function:: void HardwareTimer::detachCompare4Interrupt()
+
+ Equivalent to :ref:`detachInterrupt
+ <lang-hardwaretimer-detachinterrupt>`\ ``(4)``.
+
+.. _lang-hardwaretimer-generateupdate:
+
+.. cpp:function:: void HardwareTimer::generateUpdate()
+
+ Re-initializes the counter (to 0 in upcounting mode, which is the
+ default), and generates an update of the prescale and overflow
+ registers.
+
+.. _lang-hardwaretimer-getoverflow:
+
+.. cpp:function:: uint16 HardwareTimer::getOverflow()
+
+ Gets the timer's overflow value. See :ref:`setOverflow()
+ <lang-hardwaretimer-setoverflow>`.
+
+.. _lang-hardwaretimer-setoverflow:
+
+.. cpp:function:: void HardwareTimer::setOverflow(uint16 val)
+
+ Sets the timer overflow (or "reload") value to ``val``.
+
+ 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).
+
+ 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-pause:
+
+.. cpp:function:: void HardwareTimer::pause()
+
+ Stop the timer's 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 :ref:`resume()
+ <lang-hardwaretimer-resume>` is not a robust way to align multiple
+ timers to the same count value.
+
+.. _lang-hardwaretimer-setperiod:
+
+.. cpp:function:: uint16 HardwareTimer::setPeriod(uint32 microseconds)
+
+ 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.
+
+ 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.
+
+.. _lang-hardwaretimer-getprescalefactor:
+
+.. cpp:function:: uint16 HardwareTimer::getPrescaleFactor()
+
+ Returns the timer's prescale factor. See
+ :ref:`setPrescaleFactor() <lang-hardwaretimer-setprescalefactor>`.
+
+.. _lang-hardwaretimer-setprescalefactor:
+
+.. cpp:function:: void HardwareTimer::setPrescaleFactor(uint16 factor)
+
+ Set the timer's prescale factor to ``factor``.
+
+ 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 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.
+
+ The :ref:`setPeriod() <lang-hardwaretimer-setperiod>` method may
+ also be used as a convenient alternative.
+
+.. _lang-hardwaretimer-resume:
+
+.. cpp:function:: void HardwareTimer::resume()
+
+ Resume a paused timer, without affecting its configuration.
+
+ The timer will resume counting and firing interrupts as
+ appropriate.
+
+ 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.
+
+.. cpp:function:: timer_dev_num HardwareTimer::getTimerNum()
+
+ Returns the :ref:`timer device number
+ <lang-hardwaretimer-timer-dev-num>` associated with the timer. For
+ example, ``Timer1.getTimerNum()`` would return ``TIMER1``.
+
+ 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.
+
+.. _lang-hardwaretimer-modes:
+
+Timer Modes
+^^^^^^^^^^^
+.. doxygenenum:: TimerMode
+
+.. _lang-hardwaretimer-timer-dev-num:
+
+Timer Device Numbers
+^^^^^^^^^^^^^^^^^^^^
+
+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.
+
+.. doxygenenum:: timer_dev_num
+
+.. _lang-hardwaretimer-convenience:
+
+.. _lang-hardwaretimer-gettimer:
+
+Other Functions
+^^^^^^^^^^^^^^^
+.. doxygenfunction:: getTimer
diff --git a/docs/source/lang/api/highbyte.rst b/docs/source/lang/api/highbyte.rst
new file mode 100644
index 0000000..50a1fa6
--- /dev/null
+++ b/docs/source/lang/api/highbyte.rst
@@ -0,0 +1,59 @@
+.. highlight:: cpp
+
+.. _lang-highbyte:
+
+highByte()
+==========
+
+(Macro) Extracts the second lowest byte of an integral data type.
+
+.. warning:: This macro is provided for compatibility with Arduino
+ only. It returns the second-least significant byte in an integral
+ value. It makes sense to call this the "high" byte on a 16-bit
+ ``int`` microcontroller like the Atmel chips on Arduinos, but it
+ makes no sense at all on a 32-bit microcontroller like the STM32s
+ in the Maple line.
+
+ In short: we provide this so that existing Arduino code works as
+ expected, but **strongly discourage its use** in new programs.
+
+Syntax
+------
+
+::
+
+ highByte(x)
+
+Parameters
+----------
+
+**x**: a value of any integral type.
+
+Returns
+-------
+
+Second lowest byte in **x**.
+
+Example
+-------
+
+::
+
+ int x = 0xDEADBEEF;
+ SerialUSB.println(x, HEX); // prints "BE"
+
+Arduino Compatibility
+---------------------
+
+The Maple version of ``highByte()`` is compatible with Arduino.
+
+See Also
+--------
+
+- :ref:`lowByte() <lang-lowbyte>`
+
+
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/interrupts.rst b/docs/source/lang/api/interrupts.rst
new file mode 100644
index 0000000..58fd2cc
--- /dev/null
+++ b/docs/source/lang/api/interrupts.rst
@@ -0,0 +1,47 @@
+.. highlight:: cpp
+
+.. _lang-interrupts:
+
+interrupts()
+============
+
+Re-enables interrupts (after they've been disabled by
+:ref:`noInterrupts() <lang-nointerrupts>`). Interrupts allow certain
+important tasks to happen in the background, and certain interrupts
+are enabled by default.
+
+Some functions will not work while interrupts are disabled, and both
+incoming and outgoing communication may be ignored. Interrupts can
+slightly disrupt the timing of code, however, and may be disabled for
+particularly critical sections of code.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: interrupts
+
+Example
+-------
+
+::
+
+ void setup() {}
+
+ void loop() {
+ noInterrupts();
+ // critical, time-sensitive code here
+ interrupts();
+ // other code here
+ }
+
+See Also
+--------
+
+- :ref:`noInterrupts() <lang-nointerrupts>`
+- :ref:`attachInterrupt() <lang-attachinterrupt>`
+- :ref:`detachInterrupt() <lang-detachinterrupt>`
+- :ref:`Timers reference <timers>`
+- :ref:`Timer API <lang-hardwaretimer>`
+- :ref:`External interrupts <external-interrupts>`
+
+.. include:: /lang/cc-attribution.txt
diff --git a/docs/source/lang/api/isbuttonpressed.rst b/docs/source/lang/api/isbuttonpressed.rst
new file mode 100644
index 0000000..dbff0c9
--- /dev/null
+++ b/docs/source/lang/api/isbuttonpressed.rst
@@ -0,0 +1,17 @@
+.. _lang-isbuttonpressed:
+
+isButtonPressed()
+=================
+
+Check whether the board's built-in button (labeled BUT on the
+silkscreen) is pressed.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: isButtonPressed
+
+See Also
+--------
+
+- :ref:`lang-waitforbuttonpress`
diff --git a/docs/source/lang/api/loop.rst b/docs/source/lang/api/loop.rst
new file mode 100644
index 0000000..d8f6183
--- /dev/null
+++ b/docs/source/lang/api/loop.rst
@@ -0,0 +1,45 @@
+.. highlight:: cpp
+
+.. _lang-loop:
+
+loop()
+======
+
+After creating a :ref:`setup() <lang-setup>` function, which
+initializes your sketch, the ``loop()`` function gets called
+repeatedly, allowing your program to change and respond. Use it to
+actively control your Maple board.
+
+Example
+-------
+
+::
+
+
+ int buttonPin = 38;
+
+ // setup initializes serial and the button pin
+ void setup() {
+ SerialUSB.begin();
+ pinMode(buttonPin, INPUT);
+ }
+
+ // loop() checks the button pin each time it executes,
+ // and will print 'H' if it is pressed, 'L' otherwise
+ void loop() {
+ if (digitalRead(buttonPin) == HIGH) {
+ SerialUSB.println('H');
+ } else {
+ SerialUSB.println('L');
+ }
+
+ delay(1000);
+ }
+
+See Also
+--------
+
+- :ref:`setup() <lang-setup>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/lowbyte.rst b/docs/source/lang/api/lowbyte.rst
new file mode 100644
index 0000000..58e622f
--- /dev/null
+++ b/docs/source/lang/api/lowbyte.rst
@@ -0,0 +1,25 @@
+.. _lang-lowbyte:
+
+lowByte()
+=========
+
+Extracts the low-order (rightmost) byte of a variable (e.g. a
+word).
+
+Syntax
+------
+
+lowByte(x)
+
+Parameters
+----------
+
+**x**: a value of any type. However, if a non-integral type is used,
+the results will be strange.
+
+Returns
+-------
+
+The low byte's value (this will be between 0 and 255).
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/map.rst b/docs/source/lang/api/map.rst
new file mode 100644
index 0000000..79122b3
--- /dev/null
+++ b/docs/source/lang/api/map.rst
@@ -0,0 +1,68 @@
+.. highlight:: cpp
+
+.. _lang-map:
+
+map()
+=====
+
+Re-maps a number from one range to another.
+
+.. contents:: Contents
+ :local:
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: map
+
+Discussion
+----------
+
+``map()`` does not constrain values to within the range, because
+out-of-range values are sometimes intended and useful. The
+:ref:`constrain() <lang-constrain>` macro may be used either before or
+after this function, if limits to the ranges are desired.
+
+Note that the "lower bounds" of either range may be larger or smaller
+than the "upper bounds" so that ``map()`` may be used to reverse a
+range of numbers; for example::
+
+ y = map(x, 1, 50, 50, 1);
+
+The function also handles negative numbers well, so that this
+example ::
+
+ y = map(x, 1, 50, 50, -100);
+
+is also valid.
+
+The ``map()`` function uses integer math (its arguments and return
+values all have type :ref:`long <lang-long>`), so it will not generate
+fractions, when the math might indicate that it should do so.
+Fractional remainders are truncated, and are not rounded or averaged.
+
+Example
+-------
+
+::
+
+ /* Map an ADC reading (12 bits) to 16-bit PWM (0 to 65,535) */
+
+ void setup() {
+ pinMode(0, INPUT_ANALOG);
+ pinMode(9, PWM);
+ }
+
+ void loop() {
+ int val = analogRead(0);
+ val = map(val, 0, 4095, 0, 65535);
+ analogWrite(9, val);
+ }
+
+
+See Also
+--------
+
+- :ref:`constrain() <lang-constrain>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/max.rst b/docs/source/lang/api/max.rst
new file mode 100644
index 0000000..d38eebe
--- /dev/null
+++ b/docs/source/lang/api/max.rst
@@ -0,0 +1,65 @@
+.. highlight:: cpp
+
+.. _lang-max:
+
+max()
+=====
+
+(Macro) Calculates the maximum of two numbers.
+
+Syntax
+------
+
+::
+
+ max(x, y)
+
+Parameters
+----------
+
+**x**: the first number; may be any number or numeric expression.
+
+**y**: the second number; may be any number or numeric expression.
+
+
+Returns
+-------
+
+The larger of the two parameter values.
+
+Example
+-------
+
+::
+
+ sensVal = max(senVal, 20); // assigns sensVal to the larger of sensVal or 20
+ // (effectively ensuring that it is at least 20)
+
+.. note:: Perhaps counter-intuitively, max() is often used to
+ constrain the lower end of a variable's range, while :ref:`min()
+ <lang-min>` is used to constrain the upper end of the range.
+
+Warning
+-------
+
+Because of the way ``max()`` is implemented, avoid using other
+functions inside the parentheses. It may lead to incorrect results::
+
+ max(a--, 0); // avoid this - yields incorrect results
+
+ a--; // use this instead -
+ max(a, 0); // keep other operations outside max()
+
+Arduino Compatibility
+---------------------
+
+The Maple version of ``max()`` is compatible with Arduino.
+
+See Also
+--------
+
+- :ref:`min() <lang-min>`
+- :ref:`constrain() <lang-constrain>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/micros.rst b/docs/source/lang/api/micros.rst
new file mode 100644
index 0000000..f12976b
--- /dev/null
+++ b/docs/source/lang/api/micros.rst
@@ -0,0 +1,46 @@
+.. highlight:: cpp
+
+.. _lang-micros:
+
+micros()
+========
+
+Returns the number of microseconds since the Maple board began running
+the current program. This number will overflow (go back to zero),
+after approximately 70 minutes.
+
+.. note:: There are 1,000 microseconds in a millisecond, and 1,000,000
+ microseconds in a second.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: micros
+
+Example
+-------
+
+::
+
+ unsigned int time;
+
+ void setup() {
+ }
+
+ void loop() {
+ SerialUSB.print("Time: ");
+ time = micros();
+ // prints time since program started
+ SerialUSB.println(time);
+ // wait a second so as not to send massive amounts of data
+ delay(1000);
+ }
+
+See Also
+--------
+
+- :ref:`millis() <lang-millis>`
+- :ref:`delay() <lang-delay>`
+- :ref:`delayMicroseconds() <lang-delaymicroseconds>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/millis.rst b/docs/source/lang/api/millis.rst
new file mode 100644
index 0000000..0288c56
--- /dev/null
+++ b/docs/source/lang/api/millis.rst
@@ -0,0 +1,52 @@
+.. highlight:: cpp
+
+.. _lang-millis:
+
+millis()
+========
+
+Returns the number of milliseconds since the Maple board began running
+the current program. This number will overflow (go back to zero) after
+approximately 50 days.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: millis
+
+Example
+-------
+
+The following time prints the value returned by ``millis()`` roughly
+once per second::
+
+ unsigned int time;
+
+ void setup() {
+ }
+
+ void loop() {
+ SerialUSB.print("Time: ");
+ time = millis();
+ // prints time since program started
+ Serial.println(time);
+
+ // wait a second so as not to send massive amounts of data
+ delay(1000);
+ }
+
+Tip
+---
+
+Since the return value for ``millis()`` is an :ref:`unsigned long
+<lang-unsignedlong>`, overflow errors may occur if you try to do math
+with other data types, such as :ref:`chars <lang-char>`.
+
+See Also
+--------
+
+- :ref:`micros <lang-micros>`
+- :ref:`delay <lang-delay>`
+- :ref:`delayMicroseconds <lang-delaymicroseconds>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/min.rst b/docs/source/lang/api/min.rst
new file mode 100644
index 0000000..1245f6f
--- /dev/null
+++ b/docs/source/lang/api/min.rst
@@ -0,0 +1,66 @@
+.. highlight:: cpp
+
+.. _lang-min:
+
+min()
+=====
+
+(Macro) Calculates the minimum of two numbers.
+
+Syntax
+------
+
+::
+
+ min(x,y)
+
+Parameters
+----------
+
+**x**: the first number; may be any number or numeric expression.
+
+**y**: the second number; may be any number or numeric expression.
+
+Returns
+-------
+
+The smaller of the two numbers.
+
+Example
+-------
+
+::
+
+ sensVal = min(sensVal, 100); // assigns sensVal to the smaller of sensVal or 100
+ // ensuring that it never gets above 100.
+
+
+.. note:: Perhaps counter-intuitively, max() is often used to
+ constrain the lower end of a variable's range, while min() is used
+ to constrain the upper end of the range.
+
+
+Warning
+-------
+
+Because of the way ``min()`` is implemented, avoid using other
+functions inside the parentheses. It may lead to incorrect results::
+
+ min(a++, 100); // avoid this - yields incorrect results
+
+ a++; // use this instead -
+ min(a, 100); // keep other operations outside min()
+
+Arduino Compatibility
+---------------------
+
+The Maple version of ``min()`` is compatible with Arduino.
+
+See Also
+--------
+
+- :ref:`max() <lang-max>`
+- :ref:`constrain() <lang-constrain>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/nointerrupts.rst b/docs/source/lang/api/nointerrupts.rst
new file mode 100644
index 0000000..68f0498
--- /dev/null
+++ b/docs/source/lang/api/nointerrupts.rst
@@ -0,0 +1,47 @@
+.. highlight:: cpp
+
+.. _lang-nointerrupts:
+
+noInterrupts()
+==============
+
+Description
+-----------
+
+Disables interrupts. Interrupts allow certain important tasks to
+happen in the background and are enabled by default. Some functions
+will not work while interrupts are disabled, and incoming
+communication may be ignored. Interrupts can slightly disrupt the
+timing of code, however, and may be disabled for particularly critical
+sections of code.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: noInterrupts
+
+Example
+-------
+
+::
+
+ void setup() {}
+
+ void loop() {
+ noInterrupts();
+ // critical, time-sensitive code here
+ interrupts();
+ // other code here
+ }
+
+See Also
+--------
+
+- :ref:`interrupts() <lang-interrupts>`
+- :ref:`attachInterrupt() <lang-attachinterrupt>`
+- :ref:`detachInterrupt() <lang-detachinterrupt>`
+- :ref:`Timers reference <timers>`
+- :ref:`Timer API <lang-hardwaretimer>`
+- :ref:`External interrupts <external-interrupts>`
+
+.. include:: /lang/cc-attribution.txt
diff --git a/docs/source/lang/api/pinmode.rst b/docs/source/lang/api/pinmode.rst
new file mode 100644
index 0000000..03cbcfa
--- /dev/null
+++ b/docs/source/lang/api/pinmode.rst
@@ -0,0 +1,79 @@
+.. highlight:: cpp
+
+.. _lang-pinmode:
+
+pinMode()
+=========
+
+.. contents:: Contents
+ :local:
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: pinMode
+
+.. _lang-pinmode-wiringpinmode:
+
+.. doxygenenum:: WiringPinMode
+
+Discussion
+----------
+
+``pinMode()`` is usually called within :ref:`lang-setup` in order to
+configure a pin for a certain usage (although it may be called
+anywhere).
+
+Example
+-------
+
+::
+
+ int ledPin = 13; // LED connected to digital pin 13
+
+ void setup() {
+ pinMode(ledPin, OUTPUT); // sets the digital pin as output
+ }
+
+ void loop() {
+ digitalWrite(ledPin, HIGH); // sets the LED on
+ delay(1000); // waits for a second
+ digitalWrite(ledPin, LOW); // sets the LED off
+ delay(1000); // waits for a second
+ }
+
+Arduino Compatibility
+---------------------
+
+.. TODO check out Arduino vs. Maple static discilpline cutoffs to
+.. ensure accuracy of following:
+
+The libmaple implementation of ``pinMode()`` supports the ``INPUT``
+and ``OUTPUT`` modes with semantics identical to that of the Arduino
+function (however, be advised that the Maple, as a 3.3V device, will
+only drive 3.3V to an ``OUTPUT`` pin that has been set ``HIGH``).
+
+``INPUT_ANALOG`` and ``PWM`` modes were added because the Maple does
+not distinguish between analog and digital pins the same way the
+Arduino does. Unlike the Arduino, you **must call** ``pinMode()`` to
+set up a pin for these purposes before a call to, e.g.,
+:ref:`lang-analogRead`. In practice, this should only add a few lines
+to your :ref:`lang-setup` function.
+
+.. TODO verify following before putting it in:
+
+.. ``OUTPUT_OPEN_DRAIN``, ``INPUT_PULLUP``, ``INPUT_PULLDOWN``, and
+.. ``PWM_OPEN_DRAIN`` modes represent functionality not currently
+.. available on Arduino boards.
+
+See also
+--------
+
+- :ref:`lang-constants`
+- :ref:`lang-digitalwrite`
+- :ref:`lang-digitalread`
+- Maple :ref:`GPIO <gpio>` reference page
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/pow.rst b/docs/source/lang/api/pow.rst
new file mode 100644
index 0000000..4280400
--- /dev/null
+++ b/docs/source/lang/api/pow.rst
@@ -0,0 +1,23 @@
+.. _lang-pow:
+
+pow()
+=====
+
+Calculates the value of a number raised to a power.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: pow
+
+.. TODO LATER some examples
+
+See Also
+--------
+
+- :ref:`sqrt() <lang-sqrt>`
+- :ref:`float <lang-float>`
+- :ref:`double <lang-double>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/pwmwrite.rst b/docs/source/lang/api/pwmwrite.rst
new file mode 100644
index 0000000..9d50077
--- /dev/null
+++ b/docs/source/lang/api/pwmwrite.rst
@@ -0,0 +1,55 @@
+.. highlight:: cpp
+
+.. _lang-pwmwrite:
+
+pwmWrite()
+==========
+
+Writes a :ref:`PWM wave <pwm>` to a pin. You can use this to make an
+LED get brighter or dimmer, control a servomotor, etc. After a call to
+pwmWrite(), the pin will output a steady square wave with the given
+duty cycle. You can change the duty cycle later by calling pwmWrite()
+again with the same pin and a different duty.
+
+On the Maple, the pins which support PWM are: 0, 1, 2, 3, 5, 6, 7, 8,
+9, 11, 12, 14, 24, 27, and 28.
+
+The Arduino function :ref:`analogWrite() <lang-analogwrite>` is an
+alias for ``pwmWrite()``, but it is badly named, and its use is
+discouraged.
+
+.. contents:: Contents
+ :local:
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: pwmWrite
+
+Example
+-------
+
+Sets the output to the LED proportional to the value read from the
+potentiometer::
+
+ int analogPin = 3; // potentiometer connected to analog pin 3
+
+ void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT); // sets the LED pin as output
+
+ pinMode(analogPin, INPUT_ANALOG); // sets the potentiometer pin as
+ // analog input
+ }
+
+ void loop() {
+ int val = analogRead(analogPin); // read the input pin
+
+ pwmWrite(BOARD_LED_PIN, val * 16); // analogRead values go from 0
+ // to 4095, pwmWrite values
+ // from 0 to 65535, so scale roughly
+ }
+
+See Also
+--------
+
+- :ref:`Maple PWM tutorial <pwm>`
diff --git a/docs/source/lang/api/random.rst b/docs/source/lang/api/random.rst
new file mode 100644
index 0000000..dd8871d
--- /dev/null
+++ b/docs/source/lang/api/random.rst
@@ -0,0 +1,73 @@
+.. highlight:: cpp
+
+.. _lang-random:
+
+random()
+========
+
+The ``random()`` function generates pseudo-random numbers.
+
+Library Documentation
+---------------------
+
+.. FIXME keep tracking Sphinx/Breathe's ability to reference
+.. overloaded functions so we can use doxygenfunction instead of
+.. manually documenting.
+
+.. cpp:function:: random(long max)
+
+ Same as a call to ``random(0, max)``.
+
+.. cpp:function:: random(long min, long max)
+
+ Generate a pseudo-random number with given lower and upper bounds.
+
+ *Parameters*
+
+ - ``min`` - Lower bound on the returned value, inclusive
+ - ``max`` - Upper bound on the returned value, exclusive
+
+ *Returns*: A pseudo-random number in the range [min, max).
+
+Discussion
+----------
+
+If it is important for a sequence of values generated by
+:ref:`random() <lang-random>` to differ, on subsequent executions of a
+sketch, use :ref:`randomSeed() <lang-randomseed>` to initialize the
+random number generator with a fairly random input, such as
+:ref:`analogRead() <lang-analogread>` on an unconnected pin.
+
+Conversely, it can occasionally be useful to use pseudorandom
+sequences that repeat exactly. This can be accomplished by calling
+``randomSeed()`` with a fixed number, before starting the random
+sequence.
+
+Example
+-------
+
+The following sketch initializes the random seed based on an :ref:`ADC
+<adc>` reading of pin 0. If this pin is unconnected, the Sketch
+should print different values to the :ref:`serial monitor
+<ide-serial-monitor>` each time it is run::
+
+ long randNumber;
+
+ void setup() {
+ pinMode(0, INPUT_ANALOG);
+ randomSeed(analogRead(0));
+ }
+
+ void loop() {
+ randNumber = random(300);
+ SerialUSB.println(randNumber);
+
+ delay(50);
+ }
+
+See Also
+--------
+
+- :ref:`randomSeed() <lang-randomseed>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/randomseed.rst b/docs/source/lang/api/randomseed.rst
new file mode 100644
index 0000000..d0a15b7
--- /dev/null
+++ b/docs/source/lang/api/randomseed.rst
@@ -0,0 +1,60 @@
+.. highlight:: cpp
+
+.. _lang-randomseed:
+
+randomSeed()
+============
+
+``randomSeed()`` initializes the `pseudorandom number generator
+<http://en.wikipedia.org/wiki/Pseudorandom_number_generator>`_,
+causing it to start at an arbitrary point in its random sequence.
+This sequence, while very long, and random, is always the same.
+
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: randomSeed
+
+Discussion
+----------
+
+If it is important for a sequence of values generated by
+:ref:`random() <lang-random>` to differ, on subsequent executions of a
+sketch, use ``randomSeed()`` to initialize the random number generator
+with a fairly random input, such as :ref:`analogRead()
+<lang-analogread>` on an unconnected pin.
+
+Conversely, it can occasionally be useful to use pseudorandom
+sequences that repeat exactly. This can be accomplished by calling
+``randomSeed()`` with a fixed number, before starting the random
+sequence.
+
+Example
+-------
+
+The following sketch initializes the random seed based on an :ref:`ADC
+<adc>` reading of pin 0. If this pin is unconnected, the Sketch
+should print different values to the :ref:`serial monitor
+<ide-serial-monitor>` each time it is run::
+
+ long randNumber;
+
+ void setup() {
+ pinMode(0, INPUT_ANALOG);
+ randomSeed(analogRead(0));
+ }
+
+ void loop() {
+ randNumber = random(300);
+ SerialUSB.println(randNumber);
+
+ delay(50);
+ }
+
+See Also
+--------
+
+- :ref:`random() <lang-random>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/serial.rst b/docs/source/lang/api/serial.rst
new file mode 100644
index 0000000..ca89b31
--- /dev/null
+++ b/docs/source/lang/api/serial.rst
@@ -0,0 +1,226 @@
+.. _lang-serial:
+
+Serial Ports (``Serial1``, ``Serial2``, ``Serial3``)
+====================================================
+
+Used for communication between the Maple board and a computer or other
+devices.
+
+.. contents:: Contents
+ :local:
+
+Introduction
+------------
+
+The Maple has three serial ports (also known as a UARTs or USARTs):
+``Serial1``, ``Serial2``, and ``Serial3``. They communicate using the
+pins summarized in the following table:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Serial port
+ - TX, RX, CK
+ - CTS, RTS (if present)
+
+ * - ``Serial1``
+ - 7, 8, 6
+ -
+
+ * - ``Serial2``
+ - 1, 0, 10
+ - 2, 3
+
+ * - ``Serial3``
+ - 29, 30, 31
+ - 32, 33
+
+Thus, if you use a particular serial port, you cannot also use its
+communication pins for other purposes at the same time.
+
+If you want to communicate with the Maple using the provided USB port,
+use :ref:`SerialUSB <lang-serialusb>` instead.
+
+To use them to communicate with an external TTL serial device, connect
+the TX pin to your device's RX pin, the RX to your device's TX pin,
+and the ground of your Maple to your device's ground.
+
+.. warning:: Don't connect these pins directly to an RS232 serial
+ port; they operate at +/- 12V and can damage your board.
+
+
+Library Documentation
+---------------------
+
+All of the ``Serial[1,2,3]`` objects are instances of the
+``HardwareSerial`` class, which is documented in this section. (This
+means that you can use any of these functions on any of ``Serial1``,
+``Serial2``, and ``Serial3``).
+
+.. cpp:class:: HardwareSerial
+
+ Serial port class. Predefined instances are ``Serial1``,
+ ``Serial2``, and ``Serial3``.
+
+.. cpp:function:: HardwareSerial::begin(unsigned int baud)
+
+ Set up a ``HardwareSerial`` object for communications. This method
+ must be called before attempting to use the ``HardwareSerial``
+ object (typically, you call this in your :ref:`setup()
+ <lang-setup>` function).
+
+.. cpp:function:: HardwareSerial::end()
+
+ Disables the USART associated with this object, allowing any
+ associated communication pins to be used for other purposes.
+
+.. cpp:function:: unsigned int HardwareSerial::available()
+
+ Returns the number of bytes available for reading.
+
+.. cpp:function:: unsigned char HardwareSerial::read()
+
+ Returns the next available, unread character. If there are no
+ available characters (you can check this with :cpp:func:`available
+ <HardwareSerial::available>`), the call will block until one
+ becomes available.
+
+.. cpp:function:: HardwareSerial::flush()
+
+ Removes the contents of the Serial's associated USART RX FIFO.
+ That is, clears any buffered characters, so that the next character
+ read is guaranteed to be new.
+
+.. cpp:function:: HardwareSerial::print(unsigned char b)
+
+ Print the given byte over the USART.
+
+.. cpp:function:: HardwareSerial::print(char c)
+
+ Print the given character over the USART. 7-bit clean characters
+ are typically interpreted as ASCII text.
+
+.. cpp:function:: HardwareSerial::print(const char *str)
+
+ Print the given null-terminated string over the USART.
+
+.. cpp:function:: HardwareSerial::print(int n)
+
+ Print the argument's digits over the USART, in decimal format.
+ Negative values will be prefixed with a ``'-'`` character.
+
+.. cpp:function:: HardwareSerial::print(unsigned int n)
+
+ Print the argument's digits over the USART, in decimal format.
+
+.. cpp:function:: HardwareSerial::print(long n)
+
+ Print the argument's digits over the USART, in decimal format.
+ Negative values will be prefixed with a ``'-'`` character.
+
+.. cpp:function:: HardwareSerial::print(unsigned long n)
+
+ Print the argument's digits over the USART, in decimal format.
+
+.. cpp:function:: HardwareSerial::print(long n, int base)
+
+ Print the digits of ``n`` over the USART, in base ``base`` (which
+ may be between 2 and 16). The ``base`` value 2 corresponds to
+ binary, 8 to octal, 10 to decimal, and 16 to hexadecimal. Negative
+ values will be prefixed with a ``'-'`` character.
+
+.. cpp:function:: HardwareSerial::print(double n)
+
+ Print ``n``, accurate to 2 digits after the decimal point.
+
+.. _lang-serial-println:
+
+.. cpp:function:: HardwareSerial::println(char c)
+
+ Like ``print(c)``, followed by ``"\r\n"``.
+
+.. cpp:function:: HardwareSerial::println(const char *c)
+
+ Like ``print(c)``, followed by ``"\r\n"``.
+
+.. cpp:function:: HardwareSerial::println(unsigned char b)
+
+ Like ``print(b)``, followed by ``"\r\n"``.
+
+.. cpp:function:: HardwareSerial::println(int n)
+
+ Like ``print(n)``, followed by ``"\r\n"``.
+
+.. cpp:function:: HardwareSerial::println(unsigned int n)
+
+ Like ``print(n)``, followed by ``"\r\n"``.
+
+.. cpp:function:: HardwareSerial::println(long n)
+
+ Like ``print(n)``, followed by ``"\r\n"``.
+
+.. cpp:function:: HardwareSerial::println(unsigned long n)
+
+ Like ``print(n)``, followed by ``"\r\n"``.
+
+.. cpp:function:: HardwareSerial::println(long n, int base)
+
+ Like ``print(n, b)``, followed by ``"\r\n"``.
+
+.. cpp:function:: HardwareSerial::println(double n)
+
+ Like ``print(n)``, followed by ``"\r\n"``.
+
+.. cpp:function:: HardwareSerial::println()
+
+ Prints ``"\r\n"`` over the USART.
+
+.. cpp:function:: HardwareSerial::write(unsigned char ch)
+
+ Sends one character over the USART. This function is currently
+ blocking, although nonblocking writes are a planned future
+ extension.
+
+ This is a low-level function. One of the ``print()`` or
+ ``println()`` functions is likely to be more useful when printing
+ multiple characters, when formatting numbers for printing, etc.
+
+.. cpp:function:: HardwareSerial::write(const char* str)
+
+ Send the given null-terminated character string over the USART.
+
+ This is a low-level function. One of the ``print()`` or
+ ``println()`` functions is likely to be more useful when printing
+ multiple characters, when formatting numbers for printing, etc.
+
+.. cpp:function:: HardwareSerial::write(void *buf, unsigned int size)
+
+ Writes the first ``size`` bytes of ``buf`` over the USART. Each
+ byte is transmitted as an individual character.
+
+ This is a low-level function. One of the ``print()`` or
+ ``println()`` functions is likely to be more useful when printing
+ multiple characters, when formatting numbers for printing, etc.
+
+Arduino Compatibility Note
+--------------------------
+
+Unlike the Arduino, none of the Maple's serial ports is connected to
+the USB port on the Maple board (for that, use :ref:`SerialUSB
+<lang-serialusb>`). Thus, to use these pins to communicate with your
+personal computer, you will need an additional USB-to-serial adaptor.
+
+.. TODO LATER port these examples over
+
+.. Examples
+.. --------
+
+.. - `ASCII Table <http://arduino.cc/en/Tutorial/ASCIITable>`_
+.. - `Dimmer <http://arduino.cc/en/Tutorial/Dimmer>`_
+.. - `Graph <http://arduino.cc/en/Tutorial/Graph>`_
+.. - `Physical Pixel <http://arduino.cc/en/Tutorial/PhysicalPixel>`_
+.. - `Virtual Color Mixer <http://arduino.cc/en/Tutorial/VirtualColorMixer>`_
+.. - `Serial Call Response <http://arduino.cc/en/Tutorial/SerialCallResponse>`_
+.. - `Serial Call Response ASCII <http://arduino.cc/en/Tutorial/SerialCallResponseASCII>`_
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/serialusb.rst b/docs/source/lang/api/serialusb.rst
new file mode 100644
index 0000000..3bb8c00
--- /dev/null
+++ b/docs/source/lang/api/serialusb.rst
@@ -0,0 +1,243 @@
+.. highlight:: cpp
+
+.. _lang-serialusb:
+
+``SerialUSB``
+=============
+
+Used for communication between the Maple board and a computer.
+
+.. contents:: Contents
+ :local:
+
+Introduction
+------------
+
+In addition to three :ref:`serial ports <lang-serial>`, the Maple's
+STM32 microprocessor includes a dedicated USB peripheral. This
+peripheral is used 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).
+
+Library access to the emulated serial port is provided through the
+``SerialUSB`` object. You can mostly use ``SerialUSB`` as a drop-in
+replacement for ``Serial1``, ``Serial2``, and ``Serial3``.
+
+.. warning:: The ``SerialUSB`` functionality 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 calls to one of the
+ ``SerialUSB`` ``write()`` or ``print()`` functions in your code,
+ and you are not monitoring the emulated on a computer, your program
+ will run much, much slower than if it is being monitored or totally
+ disconnected (run off of a battery).
+
+ You can avoid this behavior by :ref:`deciphering the port status
+ using the DTR and RTS line status <lang-serialusb-safe-print>`; the
+ behavior of these control lines is platform dependent and we no
+ longer interpret them by default.
+
+Library Documentation
+---------------------
+
+The ``SerialUSB`` object is an instance of the ``USBSerial`` class,
+which is documented in this section. This means that you can use any
+of these functions by writing
+``SerialUSB.functionName(arguments...)``. For example, to print the
+message "hello, world!", you can write ``USBSerial.println("hello,
+world!")``.
+
+.. cpp:class:: USBSerial
+
+ Emulated serial-over-USB class. ``SerialUSB`` is the predefined
+ (singleton) instance.
+
+.. _lang-serialusb-begin:
+
+.. cpp:function:: USBSerial::begin()
+
+ Set up the USB peripheral for emulated serial communication. The
+ peripheral is configured this way by default; calling this function
+ should only be necessary if you have disabled the peripheral using
+ ``SerialUSB.end()``.
+
+.. _lang-serialusb-end:
+
+.. cpp:function:: USBSerial::end()
+
+ Disables the USB peripheral. Note that using this function will
+ terminate all USB communications between the Maple and the USB
+ host; in particular, it implies that you won't be able to upload
+ any new programs without resetting the board or using
+ :ref:`perpetual bootloader mode
+ <troubleshooting-perpetual-bootloader>`.
+
+.. cpp:function:: unsigned int USBSerial::available()
+
+ Returns the number of bytes available for reading.
+
+.. _lang-serialusb-read:
+
+.. cpp:function:: unsigned char USBSerial::read()
+
+ Returns the next available, unread character. If there are no
+ available characters (you can check this with :cpp:func:`available
+ <USBSerial::available>`), the call will block until one
+ becomes available.
+
+.. cpp:function:: USBSerial::print(unsigned char b)
+
+ Print the given byte over the USB connection.
+
+.. cpp:function:: USBSerial::print(char c)
+
+ Print the given character over the USB connection. 7-bit clean characters
+ are typically interpreted as ASCII text.
+
+.. cpp:function:: USBSerial::print(const char *str)
+
+ Print the given null-terminated string over the USB connection.
+
+.. cpp:function:: USBSerial::print(int n)
+
+ Print the argument's digits over the USB connection, in decimal format.
+ Negative values will be prefixed with a ``'-'`` character.
+
+.. cpp:function:: USBSerial::print(unsigned int n)
+
+ Print the argument's digits over the USB connection, in decimal format.
+
+.. cpp:function:: USBSerial::print(long n)
+
+ Print the argument's digits over the USB connection, in decimal
+ format. Negative values will be prefixed with a ``'-'`` character.
+
+.. cpp:function:: USBSerial::print(unsigned long n)
+
+ Print the argument's digits over the USB connection, in decimal
+ format.
+
+.. cpp:function:: USBSerial::print(long n, int base)
+
+ Print the digits of ``n`` over the USB connection, in base ``base``
+ (which may be between 2 and 16). The ``base`` value 2 corresponds
+ to binary, 8 to octal, 10 to decimal, and 16 to hexadecimal.
+ Negative values will be prefixed with a ``'-'`` character.
+
+.. cpp:function:: USBSerial::print(double n)
+
+ Print ``n``, accurate to 2 digits after the decimal point.
+
+.. _lang-serialusb-println:
+
+.. cpp:function:: USBSerial::println(char c)
+
+ Like ``print(c)``, followed by ``"\r\n"``.
+
+.. cpp:function:: USBSerial::println(const char *c)
+
+ Like ``print(c)``, followed by ``"\r\n"``.
+
+.. cpp:function:: USBSerial::println(unsigned char b)
+
+ Like ``print(b)``, followed by ``"\r\n"``.
+
+.. cpp:function:: USBSerial::println(int n)
+
+ Like ``print(n)``, followed by ``"\r\n"``.
+
+.. cpp:function:: USBSerial::println(unsigned int n)
+
+ Like ``print(n)``, followed by ``"\r\n"``.
+
+.. cpp:function:: USBSerial::println(long n)
+
+ Like ``print(n)``, followed by ``"\r\n"``.
+
+.. cpp:function:: USBSerial::println(unsigned long n)
+
+ Like ``print(n)``, followed by ``"\r\n"``.
+
+.. cpp:function:: USBSerial::println(long n, int base)
+
+ Like ``print(n, b)``, followed by ``"\r\n"``.
+
+.. cpp:function:: USBSerial::println(double n)
+
+ Like ``print(n)``, followed by ``"\r\n"``.
+
+.. cpp:function:: USBSerial::println()
+
+ Prints ``"\r\n"`` over the USB connection.
+
+.. cpp:function:: USBSerial::write(unsigned char ch)
+
+ Sends one character over the USB connection. This function is
+ currently blocking, although nonblocking writes are a planned
+ future extension.
+
+ This is a low-level function. One of the ``print()`` or
+ ``println()`` functions is likely to be more useful when printing
+ multiple characters, when formatting numbers for printing, etc.
+
+.. cpp:function:: USBSerial::write(const char* str)
+
+ Send the given null-terminated character string over the USB
+ connection.
+
+ This is a low-level function. One of the ``print()`` or
+ ``println()`` functions is likely to be more useful when printing
+ multiple characters, when formatting numbers for printing, etc.
+
+.. cpp:function:: USBSerial::write(void *buf, unsigned int size)
+
+ Writes the first ``size`` bytes of ``buf`` over the USB connection.
+ Each byte is transmitted as an individual character.
+
+ This is a low-level function. One of the ``print()`` or
+ ``println()`` functions is likely to be more useful when printing
+ multiple characters, when formatting numbers for printing, etc.
+
+Examples
+--------
+
+.. _lang-serialusb-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);
+ }
+
diff --git a/docs/source/lang/api/setup.rst b/docs/source/lang/api/setup.rst
new file mode 100644
index 0000000..837ddd6
--- /dev/null
+++ b/docs/source/lang/api/setup.rst
@@ -0,0 +1,29 @@
+.. highlight:: cpp
+
+.. _lang-setup:
+
+setup()
+=======
+
+The ``setup()`` function is called when a sketch starts. Use it to
+initialize :ref:`variables <lang-variables>`, :ref:`pin modes
+<lang-pinmode>`, start using :ref:`libraries <libraries>`, etc. The
+``setup()`` function will only run once, after each power-up or reset
+of the Maple board.
+
+Example
+-------
+
+::
+
+ int buttonPin = 38;
+
+ void setup() {
+ pinMode(buttonPin, INPUT);
+ }
+
+ void loop() {
+ // ...
+ }
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/sin.rst b/docs/source/lang/api/sin.rst
new file mode 100644
index 0000000..398b8f3
--- /dev/null
+++ b/docs/source/lang/api/sin.rst
@@ -0,0 +1,32 @@
+.. _lang-sin:
+
+sin()
+=====
+
+Calculates the `sine <http://en.wikipedia.org/wiki/Sine>`_ of an
+angle.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: sin
+
+Arduino Compatibility
+---------------------
+
+The Maple version of ``sin()`` is compatible with Arduino.
+
+Note that the Maple implementation comes from `newlib
+<http://sourceware.org/newlib/>`_\ , while Arduino's is that of
+`avr-libc <http://avr-libc.nongnu.org/>`_\ .
+
+See Also
+--------
+
+- :ref:`cos <lang-cos>`
+- :ref:`tan <lang-tan>`
+- :ref:`float <lang-float>`
+- :ref:`double <lang-double>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/sq.rst b/docs/source/lang/api/sq.rst
new file mode 100644
index 0000000..bd32648
--- /dev/null
+++ b/docs/source/lang/api/sq.rst
@@ -0,0 +1,46 @@
+.. highlight:: cpp
+
+.. _lang-sq:
+
+sq()
+====
+
+(Macro) computes the square of a number.
+
+Syntax
+------
+
+::
+
+ sq(a)
+
+Parameters
+----------
+
+**a**: the number.
+
+Returns
+-------
+
+**a** squared (**a** × **a**).
+
+Warning
+-------
+
+Because of the way ``sq()`` is implemented, avoid using other
+functions or causing side effects inside the parentheses, as it may
+lead to incorrect results::
+
+ b = sq(a++); // avoid this - yields incorrect results
+
+ b = sq(a); // use this instead -
+ a++; // keep other operations outside sq()
+
+
+Arduino Compatibility
+---------------------
+
+Maple's implementation of ``sq()`` is compatible with Arduino.
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/tan.rst b/docs/source/lang/api/tan.rst
new file mode 100644
index 0000000..4bbe0db
--- /dev/null
+++ b/docs/source/lang/api/tan.rst
@@ -0,0 +1,31 @@
+.. _lang-tan:
+
+tan()
+=====
+
+Calculates the tangent of an angle.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: tan
+
+Arduino Compatibility
+---------------------
+
+The Maple version of ``tan()`` is compatible with Arduino.
+
+Note that the Maple implementation comes from `newlib
+<http://sourceware.org/newlib/>`_\ , while Arduino's is that of
+`avr-libc <http://avr-libc.nongnu.org/>`_\ .
+
+See Also
+--------
+
+
+- :ref:`sin <lang-sin>`
+- :ref:`cos <lang-cos>`
+- :ref:`float <lang-float>`
+- :ref:`double <lang-double>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/toggleled.rst b/docs/source/lang/api/toggleled.rst
new file mode 100644
index 0000000..0cc20c2
--- /dev/null
+++ b/docs/source/lang/api/toggleled.rst
@@ -0,0 +1,17 @@
+.. _lang-toggleled:
+
+toggleLED()
+===========
+
+Switches the LED from off to on, or on to off.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: toggleLED
+
+See Also
+--------
+
+- :ref:`BOARD_LED_PIN <lang-constants-led>`
+- :ref:`togglePin() <lang-togglepin>`
diff --git a/docs/source/lang/api/togglepin.rst b/docs/source/lang/api/togglepin.rst
new file mode 100644
index 0000000..290718d
--- /dev/null
+++ b/docs/source/lang/api/togglepin.rst
@@ -0,0 +1,17 @@
+.. _lang-togglepin:
+
+togglePin()
+===========
+
+Switches a digital output pin from :ref:`HIGH <lang-constants-high>`
+to :ref:`LOW <lang-constants-low>`, or from LOW to HIGH.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: togglePin
+
+See Also
+--------
+
+- :ref:`toggleLED() <lang-toggleled>`
diff --git a/docs/source/lang/api/volatile.rst b/docs/source/lang/api/volatile.rst
new file mode 100644
index 0000000..276bb6a
--- /dev/null
+++ b/docs/source/lang/api/volatile.rst
@@ -0,0 +1,65 @@
+.. highlight:: cpp
+
+.. _lang-volatile:
+
+``volatile``
+============
+
+The ``volatile`` keyword known is a variable *qualifier*. It is
+usually used before the datatype of a variable, to modify the way in
+which the compiler treats the variable.
+
+Declaring a variable ``volatile`` is a directive to the compiler. The
+compiler is software which translates your C++ code into the machine
+code, which are the real instructions for the STM32 chip in the
+Maple. (The particular compiler we provide for use with the Maple is a
+version of :ref:`GCC <arm-gcc>`).
+
+Specifically, it directs the compiler to read the variable's value
+fresh every time it is used, rather than "backing up" the value and
+reading from its backup copy. (Compilers often "back up" a variable's
+value in RAM into a storage location called a *register*; this is done
+for efficiency).
+
+A variable should be declared ``volatile`` whenever its value can be
+changed by something beyond the control of the code section in which
+it appears, such as an :ref:`external interrupt
+<external-interrupts>`. On the Maple, the only place that this is
+likely to occur is in sections of code associated with interrupts.
+
+Example
+-------
+
+::
+
+ // toggles LED when interrupt pin changes state
+
+ int pin = 13;
+ volatile int state = LOW;
+
+ void setup() {
+ pinMode(pin, OUTPUT);
+ attachInterrupt(0, blink, CHANGE);
+ }
+
+ void loop() {
+ digitalWrite(pin, state);
+ }
+
+ void blink() {
+ if (state == HIGH) {
+ state = LOW;
+ } else {
+ // state must be HIGH
+ state = HIGH;
+ }
+ }
+
+See also
+--------
+
+- :ref:`External Interrupts <external-interrupts>`
+- :ref:`lang-attachinterrupt`
+- :ref:`lang-detachinterrupt`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/api/waitforbuttonpress.rst b/docs/source/lang/api/waitforbuttonpress.rst
new file mode 100644
index 0000000..34c5066
--- /dev/null
+++ b/docs/source/lang/api/waitforbuttonpress.rst
@@ -0,0 +1,17 @@
+.. _lang-waitforbuttonpress:
+
+waitForButtonPress()
+====================
+
+Wait for the board's built-in button (labeled BUT on the silkscreen)
+to be pressed, possibly with timeout.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: waitForButtonPress
+
+See Also
+--------
+
+- :ref:`lang-isbuttonpressed`
diff --git a/docs/source/lang/cc-attribution.txt b/docs/source/lang/cc-attribution.txt
new file mode 100644
index 0000000..e100140
--- /dev/null
+++ b/docs/source/lang/cc-attribution.txt
@@ -0,0 +1,9 @@
+.. Included in all this directory's files in order to satisfy the
+.. Arduino CC Attribution-ShareAlike 3.0 License
+
+.. admonition:: License and Attribution
+
+ This documentation page was adapted from the `Arduino Reference
+ Documentation <http://arduino.cc/en/Reference/HomePage>`_\ , which
+ is released under a `Creative Commons Attribution-ShareAlike 3.0
+ License <http://creativecommons.org/licenses/by-sa/3.0/>`_.
diff --git a/docs/source/lang/cpp/arithmetic.rst b/docs/source/lang/cpp/arithmetic.rst
new file mode 100644
index 0000000..7e8c3fc
--- /dev/null
+++ b/docs/source/lang/cpp/arithmetic.rst
@@ -0,0 +1,127 @@
+.. highlight:: cpp
+
+.. _lang-arithmetic:
+
+Arithmetic Operators (``+``, ``-``, ``*``, ``/``)
+=================================================
+
+The operators ``+``, ``-``, ``*``, and ``/`` respectively evaluate to
+the sum, difference, product, or quotient (respectively) of the two
+operands. The operation is conducted using the data type of the
+operands, so, for example, ``9 / 4`` gives ``2`` since 9 and 4 are
+:ref:`int variables <lang-int>`.
+
+This also means that the operation can overflow if the result is
+larger than that which can be stored in the data type (e.g. adding 1
+to an :ref:`lang-int` with the value 2,147,483,647 gives
+-2,147,483,648).
+
+.. _lang-arithmetic-typeconversion:
+
+If the operands are of different types, the "larger" type is used for
+the calculation. If one of the numbers (operands) are of the type
+**float** or of type **double**, floating point math will be used for
+the calculation.
+
+.. note:: The specifics of these rules are beyond the scope of this
+ documentation; for more information, see `The C++ Programming
+ Language <http://www2.research.att.com/~bs/3rd.html>`_\ , by Bjarne
+ Stroustroup, Appendix C, especially §§C.4-C.6, or `this WikiBooks
+ entry on C++ type conversion
+ <http://en.wikibooks.org/wiki/C%2B%2B_Programming/Programming_Languages/C%2B%2B/Code/Statements/Variables/Type_Casting#Automatic_type_conversion>`_.
+
+.. note:: For more information on how computers represent integers,
+ see the Wikipedia page on `two's complement
+ <http://en.wikipedia.org/wiki/Two's_complement>`_.
+
+.. contents:: Contents
+ :local:
+
+Examples
+--------
+
+ ::
+
+ y = y + 3;
+ x = x - 7;
+ i = j * 6;
+ r = r / 5;
+
+
+Syntax
+------
+
+ ::
+
+ result = value1 + value2;
+ result = value1 - value2;
+ result = value1 * value2;
+ result = value1 / value2;
+
+
+Parameters
+----------
+
+**value1**: any numeric variable or constant
+
+**value2**: any numeric variable or constant
+
+Programming Tips
+----------------
+
+- Know that :ref:`integer constants <lang-constants-integers>`
+ default to :ref:`int <lang-int>`, so some constant calculations
+ may overflow (e.g., 200000 * 5000000 will yield a negative result).
+
+- Choose variable sizes that are large enough to hold the largest
+ results from your calculations.
+
+- Know at what point your variable will "roll over" and also what
+ happens in the other direction e.g. (0 - 1) for unsigned arithmetic,
+ or (0 - -2,147,483,648) for signed arithmetic.
+
+- For math that requires fractions, float variables may be used, but
+ be aware of their drawbacks: large size and slow computation speeds
+ (the STM32 has no floating point hardware, so all floating point
+ calculations have to be done in software).
+
+- Use cast operator, e.g. ``(int)myFloat`` to convert one variable type
+ to another on the fly.
+
+Arduino Compatibility
+---------------------
+
+Since the STM32 processor on the Maple is a 32-bit machine, the int
+type overflows at a much higher value on Maple than on Arduino. In
+particular, on Maple, ints do not overflow (become negative) until
+they reach 2,147,483,648; on the Arduino, they overflow at 32,767.
+Because of this, programs running on Maple are much less likely to run
+into overflow issues. The following table summarizes the sizes and
+ranges of integer datatypes on the Maple (the ranges of ``long long``
+types are approximate):
+
+.. _lang-arithmetic-int-sizes:
+
+.. csv-table::
+ :header: Datatype, Unsigned range, Signed range, Size (bytes)
+ :widths: 8, 12, 17, 8
+
+ ``char``, 0 --- 255, -128 --- 127, 1
+ ``short``, "0 --- 65,535", "-32,768 --- 32,767", 2
+ ``int``, "0 --- 4,294,967,295", "-2,147,483,648 --- 2,147,483,647", 4
+ ``long``, "0 --- 4,294,967,295", "-2,147,483,648 --- 2,147,483,647", 4
+ ``long long``, "0 --- 1.8*10\ :sup:`19`\ " (approx.), "-9.2*10\ :sup:`18` --- 9.2*10\ :sup:`18` (approx.)", 8
+
+
+See Also
+--------
+
+- The individual sizes (in bits) of various available types are
+ defined in `libmaple_types.h
+ <http://github.com/leaflabs/libmaple/blob/master/libmaple/libmaple_types.h>`_\
+ .
+
+- :ref:`sizeof <lang-sizeof>`\ ()
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/array.rst b/docs/source/lang/cpp/array.rst
new file mode 100644
index 0000000..30a818f
--- /dev/null
+++ b/docs/source/lang/cpp/array.rst
@@ -0,0 +1,123 @@
+.. highlight:: cpp
+
+.. _lang-array:
+
+Arrays
+======
+
+An array is a collection of variables that are accessed with an index
+number. Arrays in the C++ programming language, in which the Maple is
+programmed, can be complicated, but using simple arrays is relatively
+straightforward.
+
+.. contents:: Contents
+ :local:
+
+Creating (Declaring) an Array
+-----------------------------
+
+All of the methods below are valid ways to create (declare) an
+array. ::
+
+ int myInts[6];
+ int myPins[] = {2, 4, 8, 3, 6};
+ int mySensVals[6] = {2, 4, -8, 3, 2};
+ char message[6] = "hello";
+
+You can declare an array without initializing it, as with myInts. In
+the line referring to myPins, we declare an array without explicitly
+choosing a size. The compiler counts the elements and creates an
+array of the appropriate size.
+
+Finally, you can both initialize and size your array, as in
+mySensVals. Note that when declaring an array with elements of type
+char, one more element than your initialization is required, to hold
+the required `null character <http://en.wikipedia.org/wiki/Null-terminated_string>`_.
+
+
+Accessing an Array
+------------------
+
+
+.. compound::
+
+ Arrays are **zero indexed**; that is, referring to the array
+ initialization above, the first element of the array is at index 0,
+ hence ::
+
+ mySensVals[0] == 2;
+ mySensVals[1] == 4
+
+ and so forth.
+
+It also means that in an array with ten elements, index nine is the
+last element. Hence::
+
+ int myArray[10]={9,3,2,4,3,2,7,8,9,11};
+ // myArray[9] contains 11
+ // myArray[10] is invalid and contains random information (other memory address)
+
+For this reason, you should be careful in accessing arrays. Accessing
+past the end of an array (using an index number greater than your
+declared array size - 1) is reading from memory that is in use for
+other purposes. Reading from these locations is probably not going to
+do much except yield invalid data. Writing to random memory locations
+is definitely a bad idea, and can often lead to unhappy results such
+as crashes or program malfunction. This can also be a difficult bug to
+track down.
+
+Unlike Basic or Java, the C compiler does no checking to see if array
+access is within legal bounds of the array size that you have
+declared.
+
+
+To assign a value to an array
+-----------------------------
+ ::
+
+ mySensVals[0] = 10;
+
+
+To retrieve a value from an array
+---------------------------------
+
+ ::
+
+ x = mySensVals[4];
+
+
+Arrays and ``for`` Loops
+------------------------
+
+Arrays are often manipulated inside :ref:`for loops <lang-for>`, where
+the loop counter is used as the index for each array element. For
+example, to print the elements of an array over the serial port, you
+could do something like this::
+
+ int i;
+ for (i = 0; i < 5; i = i + 1) {
+ SerialUSB.println(myPins[i]);
+ }
+
+
+Example
+-------
+
+For a complete program that demonstrates the use of arrays, see the
+Arduino `Knight Rider example
+<http://www.arduino.cc/en/Tutorial/KnightRider>`_\ (which will run
+unmodified on the Maple).
+
+Arduino Compatibility
+---------------------
+
+Arrays on Maple are identical those on Arduino.
+
+See also
+--------
+
+- :ref:`Storing arrays in FLASH memory <arm-gcc-attribute-flash>`
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/assignment.rst b/docs/source/lang/cpp/assignment.rst
new file mode 100644
index 0000000..f9430b4
--- /dev/null
+++ b/docs/source/lang/cpp/assignment.rst
@@ -0,0 +1,60 @@
+.. highlight:: cpp
+
+.. _lang-assignment:
+
+Assignment Operator (``=``)
+===========================
+
+Stores the value to the right of the equal sign in the variable to
+the left of the equal sign.
+
+The single equal sign in the C++ programming language is called the
+assignment operator. It has a different meaning than in algebra
+class, where it indicated an equation or equality. The assignment
+operator tells the microcontroller to evaluate whatever value or
+expression is on the right side of the equal sign, and store it in
+the variable to the left of the equal sign [#fgross]_.
+
+Example
+-------
+
+::
+
+ int sensVal; // declare an integer variable named sensVal
+ sensVal = analogRead(0); // store the (digitized) input voltage at analog pin 0 in sensVal
+
+Programming Tips
+----------------
+
+The variable on the left side of the assignment operator (``=`` sign)
+needs to be able to hold the value stored in it. If it is not large
+enough to hold a value, the value stored in the variable will be
+incorrect.
+
+Don't confuse the assignment operator ``=`` (single equal sign) with
+the comparison operator ``==`` (double equal signs), which evaluates
+whether two expressions are equal.
+
+Arduino Compatibility
+---------------------
+
+Assignments on the Maple are identical to those on Arduino.
+
+See Also
+--------
+
+- :ref:`if <lang-if>`
+- :ref:`char <lang-char>`
+- :ref:`int <lang-int>`
+- :ref:`long long <lang-longlong>`
+
+.. rubric:: Footnotes
+
+.. [#fgross] Experienced C++ programmers know this to be an
+ oversimplification of what happens when the variable on the left
+ hand side is an object. See Richard Gillam's wonderful and scary
+ `The Anatomy of the Assignment Operator
+ <http://icu-project.org/docs/papers/cpp_report/the_anatomy_of_the_assignment_operator.html>`_
+ for more information.
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/bitshift.rst b/docs/source/lang/cpp/bitshift.rst
new file mode 100644
index 0000000..e1c8de0
--- /dev/null
+++ b/docs/source/lang/cpp/bitshift.rst
@@ -0,0 +1,144 @@
+.. highlight:: cpp
+
+.. _lang-bitshift:
+
+Bit Shift Operators (``<<``, ``>>``)
+====================================
+
+(Adapted from `The Bit Math Tutorial
+<http://www.arduino.cc/playground/Code/BitMath>`_ in `The Arduino
+Playground <http://www.arduino.cc/playground/Main/HomePage>`_\ )
+
+There are two bit shift operators in C++: the left shift operator
+``<<`` and the right shift operator ``>>``. These operators cause the
+bits in the left operand to be shifted left or right by the number of
+positions specified by the right operand.
+
+More information on bitwise math can be obtained in the Wikipedia
+article on `bitwise operations
+<http://en.wikipedia.org/wiki/Bitwise_operation>`_\ , especially the
+section on shifts in `C, C++, and Java
+<http://en.wikipedia.org/wiki/Bitwise_operation#Shifts_in_C.2C_C.2B.2B.2C_C.23_and_Java>`_\ .
+
+
+Syntax
+------
+
+``some_int << number_of_bits``
+
+``some_int >> number_of_bits``
+
+
+Parameters
+----------
+
+* **some_int** An integer value or variable.
+
+* **number_of_bits** integer whose value is at most ``8 *
+ sizeof(variable)`` (so ``number_of_bits`` can be at most 32 for
+ ``int`` values, at most ``8`` for ``char`` values, etc.; the various
+ integer sizes are summarized :ref:`in this table
+ <lang-arithmetic-int-sizes>`\ ).
+
+
+
+Example:
+--------
+
+Here are some examples of bit shifting, with the binary representation of the number in comments::
+
+ int a = 5; // binary: 101
+ int b = a << 3; // binary: 101000, or 40 in decimal
+ int c = b >> 3; // binary: 101, or back to 5 like we started with
+
+
+When you left shift a value x by y bits (x << y), the leftmost y bits
+in x are lost, literally shifted out of existence. We'll do this
+example with ``char`` values (which are integers in the range 0-255,
+and take up 8 bits of memory)::
+
+ char a = 5; // binary (all 8 bits): 00000101
+ char b = a << 7; // binary: 10000000 - the first 1 in 101 was discarded
+
+
+If you are certain that none of the ones in a value are being shifted
+into oblivion, a simple way to think of the left-shift operator is
+that it multiplies the left operand by 2 raised to the right operand
+power (in math notation, ``x << y`` equals x * 2\ :sup:`y`\ , as long
+as none of the bits of x get shifted out). For example, to generate
+powers of 2, the following expressions can be employed::
+
+ 1 << 0 == 1
+ 1 << 1 == 2
+ 1 << 2 == 4
+ 1 << 3 == 8
+ ...
+ 1 << 8 == 256
+ 1 << 9 == 512
+ 1 << 10 == 1024
+ ...
+
+.. _lang-bitshift-signbit-gotcha:
+
+When you shift x right by y bits (``x >> y``), and the highest bit in
+x is a 1, the behavior depends on the exact data type of x. If x is of
+type ``int``, the highest bit is special, and determines whether x is
+negative or not; the details are too complicated to explain here, but
+they are thoroughly explained in the Wikipedia article on `two's
+complement arithmetic
+<http://en.wikipedia.org/wiki/Two%27s_complement>`_\ , which the
+system most computers use to store integers. In that case, the sign
+bit is copied into lower bits, for esoteric historical reasons::
+
+ int x = -16; // binary (all 32 bits): 11111111111111111111111111110000
+ int y = x >> 3; // binary: 11111111111111111111111111111110
+
+
+
+This behavior, called "sign extension", is often not what you
+want. You probably wish zeros to be shifted in from the left. It
+turns out that the right shift rules are different for ``unsigned
+int`` values, so you can use a type cast to suppress ones being copied
+from the left::
+
+ int x = -16; // binary: 11111111111111111111111111110000
+ int y = (unsigned int)x >> 3; // binary: 00011111111111111111111111111110
+
+
+
+If you are careful to avoid sign extension, you can use the
+right-shift operator, ``>>``, as a way to divide by powers of 2. For
+example::
+
+ int x = 1000;
+ int y = x >> 3; // integer division of 1000 by 8, causing y = 125.
+
+
+Arduino Compatibility
+---------------------
+
+Since it's part of the C++ language, bit shifting on the Maple is
+compatible with the Arduino; however, you should keep in mind that the
+Maple has bigger integer types (as in, more bits) than the Arduino.
+
+Since the STM32 is a 32-bit processor, the ``int`` type takes up 32
+bits instead of 16, like on Arduino's 16-bit microcontroller. This
+means that you can shift left, like ``x << y``, with bigger values of
+``y`` on the Maple before ones in ``x`` start to get shifted out.
+
+To calculate the number of bits of an integer type on the Maple,
+multiply its size in bytes (see :ref:`this table
+<lang-arithmetic-int-sizes>` for these) by 8, since there are 8
+bits in 1 byte. For example, a ``short`` takes up 2 bytes of memory,
+or 2 * 8 = 16 bits.
+
+See Also
+--------
+
+- :ref:`lang-bit`
+- :ref:`lang-bitread`
+- :ref:`lang-bitwrite`
+- :ref:`lang-bitclear`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/bitwisemath.rst b/docs/source/lang/cpp/bitwisemath.rst
new file mode 100644
index 0000000..28fe6bf
--- /dev/null
+++ b/docs/source/lang/cpp/bitwisemath.rst
@@ -0,0 +1,186 @@
+.. highlight:: cpp
+
+.. _lang-bitwisemath:
+
+Bitwise Operators (``&``, ``|``, ``^``, ``~``)
+==============================================
+
+The bitwise operators perform their calculations at the bit level of
+variables. They help solve a wide range of common programming
+problems.
+
+Much of the material here is adapted for Maple from an (Arduino)
+`tutorial on bitwise math
+<http://www.arduino.cc/playground/Code/BitMath>`_\ . Another great
+resource is the Wikipedia article on `bitwise operations
+<http://en.wikipedia.org/wiki/Bitwise_operation>`_\ .
+
+Below are descriptions and syntax for all of the operators.
+
+.. contents:: Contents
+ :local:
+
+.. _lang-bitwisemath-and:
+
+Bitwise AND (``&``)
+-------------------
+
+The bitwise AND operator in C++ is a single ampersand, ``&``, used
+between two other integer expressions. Bitwise AND operates on each
+bit position of the surrounding expressions independently, according
+to this rule: if both input bits are 1, the resulting output is 1,
+otherwise the output is 0. Another way of expressing this is::
+
+ 0 0 1 1 operand1
+ 0 1 0 1 operand2
+ ----------
+ 0 0 0 1 (operand1 & operand2) = result
+
+
+On the Maple, the type ``int`` is a 32-bit value, so using ``&``
+between two ``int`` expressions causes 32 simultaneous AND operations
+to occur. In a code fragment like::
+
+ int a = 92; // in binary: 00000000000000000000000001011100
+ int b = 101; // in binary: 00000000000000000000000001100101
+ int c = a & b; // result: 00000000000000000000000001000100,
+ // (or 68 in decimal).
+
+
+Each of the 32 bits in ``a`` and ``b`` are processed using bitwise
+AND, and all 32 resulting bits are stored in ``c``, resulting in the
+value 1000100 in binary, which is 68 in decimal.
+
+
+.. _lang-bitwisemath-or:
+
+Bitwise OR (``|``)
+------------------
+
+The bitwise OR operator in C++ is the vertical bar symbol, ``|``. Like
+the ``&`` operator, ``|`` operates independently on each bit in its
+two surrounding integer expressions, but what it does is
+different. The bitwise OR of two bits is 1 if either or both of the
+input bits is 1, otherwise it is 0. For example::
+
+ 0 0 1 1 operand1
+ 0 1 0 1 operand2
+ ----------
+ 0 1 1 1 (operand1 | operand2) = result
+
+Here is an example of bitwise OR used in a snippet of C++ code (using
+``char``, which takes up 8 bits of memory, instead of ``int``, which
+uses 32)::
+
+ char a = 92; // in binary: 01011100
+ char b = 101; // in binary: 01100101
+ char c = a | b; // result: 01111101, or 125 in decimal.
+
+.. _lang-bitwisemath-xor:
+
+Bitwise XOR (``^``)
+-------------------
+
+There is a somewhat unusual operator in C++ called bitwise EXCLUSIVE
+OR, also known as bitwise XOR. (In English, this is usually pronounced
+"zor" or "ex-or"). The bitwise XOR operator is written using the caret
+symbol, ``^``. This operator is very similar to the bitwise OR
+operator ``|``, except it evaluates to 0 for a given bit position when
+both of the input bits for that position are 1::
+
+ 0 0 1 1 operand1
+ 0 1 0 1 operand2
+ ----------
+ 0 1 1 0 (operand1 ^ operand2) = result
+
+
+Another way to look at bitwise XOR is that each bit in the result
+is a 1 if the input bits are different, or 0 if they are the same.
+
+Here is a simple example::
+
+ int x = 12; // binary (ignoring extra bits): 1100
+ int y = 10; // binary: 1010
+ int z = x ^ y; // binary: 0110, or decimal 6
+
+
+
+The ^ operator is often used to toggle (i.e. change from 0 to 1, or 1
+to 0) some of the bits in an integer expression. In a bitwise OR
+operation if there is a 1 in the mask bit, that bit is inverted; if
+there is a 0, the bit is not inverted and stays the same. Below is a
+program to blink digital pin 13 (the LED pin on Maple)::
+
+ // Blink Maple LED pin
+
+ int led_pin = 13;
+ int toggle = 0;
+
+ // demo for Exclusive OR
+ void setup(){
+ pinMode(led_pin, OUTPUT);
+ }
+
+ void loop(){
+ toggle = toggle ^ 1;
+ digitalWrite(led_pin, toggle);
+ delay(100);
+ }
+
+.. _lang-bitwisemath-not:
+
+Bitwise NOT (``~``)
+-------------------
+
+The bitwise NOT operator in C++ is the tilde character ``~``. Unlike
+``&`` and ``|``, the bitwise NOT operator is applied to a single
+operand to its right. Bitwise NOT changes each bit to its opposite: 0
+becomes 1, and 1 becomes 0. For example::
+
+ 0 1 operand1
+ ----
+ 1 0 ~operand1 = result
+
+Another example::
+
+ char a = 103; // binary: 01100111
+ char b = ~a; // binary: 10011000 = -104
+
+You might be surprised to see a negative number like -104 as the
+result of this operation. This is because the highest bit in an int
+variable is the so-called "sign bit". If the highest bit is 1, the
+number is interpreted as negative. This encoding of positive and
+negative numbers is referred to as *two's complement*. For more
+information, see the Wikipedia article on `two's
+complement. <http://en.wikipedia.org/wiki/Twos_complement>`_
+
+As an aside, it is interesting to note that (under two's complement
+arithmetic) for any integer ``x``, ``~x`` is the same as ``-x-1``.
+
+At times, the sign bit in a signed integer expression can cause
+some unwanted surprises.
+
+
+Uses
+----
+
+One of the most common uses of bitwise operations is to select or
+manipulate a particular bit (or bits) from an integer value, often
+called `bit masking
+<http://en.wikipedia.org/wiki/Mask_%28computing%29>`_\ . See the
+linked Wikipedia article for more information and examples.
+
+If you really want to see bit-twiddling techniques in their full
+glory, you could do much worse than to get yourself a copy of
+`Hacker's Delight <http://www.hackersdelight.org/>`_\ .
+
+
+See Also
+--------
+
+- :ref:`Boolean operations <lang-boolean>` (``&&``, ``||``)
+- :ref:`Compound bitwise operations <lang-compoundbitwise>` (``&=``,
+ ``|=``, ``^=``).
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/boolean.rst b/docs/source/lang/cpp/boolean.rst
new file mode 100644
index 0000000..8d6aa5c
--- /dev/null
+++ b/docs/source/lang/cpp/boolean.rst
@@ -0,0 +1,91 @@
+.. highlight:: cpp
+
+.. _lang-boolean:
+
+Boolean Operators
+=================
+
+These can be used inside the condition of an :ref:`if <lang-if>`
+statement. Evaluate to :ref:`true <lang-constants-true>` or
+:ref:`false <lang-constants-false>`.
+
+.. contents:: Contents
+ :local:
+
+.. _lang-boolean-and:
+
+&& (logical and)
+----------------
+
+True only if both operands are true. For example::
+
+ if (digitalRead(2) == HIGH && digitalRead(3) == HIGH) { // read two switches
+ // ...
+ }
+
+is true only if both inputs are high. Another example::
+
+ if (a >= 10 && a <= 20){} // true if a is between 10 and 20
+
+**Be careful** not to say ``10 <= a <= 20``! This won't work the way
+you want. You have to separately test whether ``a`` is at least 10
+using ``a >= 10``, then test whether ``a`` is at most 20 using ``a <=
+20``, then combine the results using ``&&``.
+
+
+.. _lang-boolean-or:
+
+\|\| (logical or)
+-----------------
+
+True if either operand is true. For example::
+
+ if (x > 0 || y > 0) {
+ // ...
+ }
+
+is true if either ``x`` or ``y`` is greater than 0.
+
+.. _lang-boolean-not:
+
+! (logical not)
+---------------
+
+True if the operand is false. For example::
+
+ if (!x) {
+ // ...
+ }
+
+is true if ``x`` is false (i.e. if ``x`` is zero).
+
+Some Advice
+-----------
+
+.. warning::
+
+ Make sure you don't mistake the boolean AND operator ``&&``
+ (double ampersand) for the :ref:`bitwise AND operator
+ <lang-bitwisemath-and>` ``&`` (single ampersand). They are
+ entirely different beasts.
+
+ Similarly, do not confuse the boolean OR operator ``||`` (double
+ pipe) with the :ref:`bitwise OR operator <lang-bitwisemath-or>`
+ ``|`` (single pipe).
+
+ The :ref:`bitwise NOT operator <lang-bitwisemath-not>` ``~``
+ (tilde) looks much different than the boolean not operator ``!``
+ (exclamation point, or "bang", as some programmers say), but you
+ still have to be sure which one you want.
+
+
+See Also
+--------
+
+- :ref:`Bitwise operators <lang-bitwisemath>` (``&``, ``|``, ``^``, ``~``)
+- :ref:`Compound bitwise operators <lang-compoundbitwise>` (``&=``,
+ ``|=``, ``^=``).
+- :ref:`if statement <lang-if>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/booleanvariables.rst b/docs/source/lang/cpp/booleanvariables.rst
new file mode 100644
index 0000000..6051b8c
--- /dev/null
+++ b/docs/source/lang/cpp/booleanvariables.rst
@@ -0,0 +1,54 @@
+.. highlight:: cpp
+
+.. _lang-booleanvariables:
+
+Booleans
+========
+
+A **boolean** holds one of two values, :ref:`true
+<lang-constants-true>` or :ref:`false <lang-constants-false>`. On a
+Maple, each boolean variable has type ``bool``.
+
+.. warning::
+
+ On an Arduino, the type ``boolean`` is also provided. While the
+ Maple also has this type for compatibility, **its use is strongly
+ discouraged**. The ``bool`` type is a standard part of C++, while
+ ``boolean`` is a non-standard extension that serves no purpose.
+
+Example
+-------
+
+::
+
+ int ledPin = 13; // LED on pin 13
+ int switchPin = 12; // momentary switch on 12, other side connected to ground
+
+ // running is a boolean variable:
+ bool running = false;
+
+ void setup() {
+ pinMode(ledPin, OUTPUT);
+ pinMode(switchPin, INPUT);
+ digitalWrite(switchPin, HIGH); // turn on pullup resistor
+ }
+
+ void loop() {
+ if (digitalRead(switchPin) == LOW) {
+ // switch is pressed - pullup keeps pin high normally
+ delay(100); // delay to debounce switch
+ running = !running; // toggle running variable
+ digitalWrite(ledPin, running) // indicate via LED
+ }
+ }
+
+See also
+--------
+
+
+- :ref:`Boolean constants <lang-constants-bool>`
+- :ref:`Boolean operators <lang-boolean>`
+- :ref:`Variables <lang-variables>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/break.rst b/docs/source/lang/cpp/break.rst
new file mode 100644
index 0000000..ce8ac17
--- /dev/null
+++ b/docs/source/lang/cpp/break.rst
@@ -0,0 +1,35 @@
+.. highlight:: cpp
+
+.. _lang-break:
+
+``break``
+=========
+
+``break`` is used to exit from a :ref:`while <lang-while>`\ ,
+:ref:`for <lang-for>`\ , or :ref:`do/while <lang-dowhile>` loop,
+bypassing the normal loop condition. It is also used to exit from a
+:ref:`switch <lang-switchcase>` statement.
+
+
+Example
+-------
+
+::
+
+ for (x = 0; x < 255; x ++)
+ {
+ digitalWrite(PWMpin, x);
+ sens = analogRead(sensorPin);
+ if (sens > threshold){ // bail out on sensor detect
+ x = 0;
+ // this line of code means that we'll immediately exit
+ // from the "for" loop:
+ break;
+ }
+ delay(50);
+ }
+
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/built-in-types.rst b/docs/source/lang/cpp/built-in-types.rst
new file mode 100644
index 0000000..a7349e6
--- /dev/null
+++ b/docs/source/lang/cpp/built-in-types.rst
@@ -0,0 +1,95 @@
+.. highlight:: cpp
+
+.. _lang-built-in-types:
+
+================
+ Built-in Types
+================
+
+This document serves as a reference for many of the built-in types
+which are available when programming in the IDE. Programmers using
+the :ref:`command-line tools <unix-toolchain>` will have access to
+these types as long as they have imported `wirish.h
+<https://github.com/leaflabs/libmaple/blob/master/wirish/wirish.h>`_;
+several are defined in in `libmaple_types.h
+<https://github.com/leaflabs/libmaple/blob/master/libmaple/libmaple_types.h>`_.
+
+.. _lang-built-in-types-integral:
+
+Integral types
+--------------
+
+.. cpp:type:: char
+
+ 8-bit integer value.
+
+.. cpp:type:: short
+
+ 16-bit integer value.
+
+.. cpp:type:: int
+
+ 32-bit integer value.
+
+.. cpp:type:: long
+
+ 32-bit integer value.
+
+.. cpp:type:: long long
+
+ 64-bit integer value.
+
+.. cpp:type:: int8
+
+ Synonym for ``char``.
+
+.. cpp:type:: uint8
+
+ Synonym for ``unsigned char``.
+
+.. cpp:type:: int16
+
+ Synonym for ``short``.
+
+.. cpp:type:: uint16
+
+ Synonym for ``unsigned short``.
+
+.. cpp:type:: int32
+
+ Synonym for ``int``.
+
+.. cpp:type:: uint32
+
+ Synonym for ``unsigned int``
+
+.. cpp:type:: int64
+
+ Synonym for ``long long``
+
+.. cpp:type:: uint64
+
+ Synonym for ``unsigned long long``.
+
+Floating-Point Types
+--------------------
+
+.. cpp:type:: float
+
+ 32-bit, IEEE 754 single-precision floating-point type.
+
+.. cpp:type:: double
+
+ 64-bit, IEEE 754 double-precision floating-point type.
+
+Other Types
+-----------
+
+.. cpp:type:: voidFuncPtr
+
+ Pointer to a function that takes no arguments and returns nothing, i.e.
+
+ ::
+
+ typedef void (*voidFuncPtr)(void);
+
diff --git a/docs/source/lang/cpp/byte.rst b/docs/source/lang/cpp/byte.rst
new file mode 100644
index 0000000..45c9d5f
--- /dev/null
+++ b/docs/source/lang/cpp/byte.rst
@@ -0,0 +1,34 @@
+.. highlight:: cpp
+
+.. _lang-byte:
+
+byte
+====
+
+The ``byte`` type stores a 1-byte (8-bit) unsigned integer number,
+from 0 to 255.
+
+.. warning::
+
+ The ``byte`` type is provided for compatibility with Arduino.
+ However, it is a non-standard extension. The standard C++ type for
+ storing an 8-bit unsigned integer is ``unsigned char``; we
+ recommend using that instead. (Your code will still work on an
+ Arduino).
+
+
+Example
+-------
+
+::
+
+ byte b = 134;
+
+See Also
+--------
+
+- :ref:`byte() <lang-bytecast>` (casting a value to a byte)
+- :ref:`Variables <lang-variables>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/bytecast.rst b/docs/source/lang/cpp/bytecast.rst
new file mode 100644
index 0000000..b3f0de2
--- /dev/null
+++ b/docs/source/lang/cpp/bytecast.rst
@@ -0,0 +1,50 @@
+.. highlight:: cpp
+
+.. _lang-bytecast:
+
+byte() (cast)
+=============
+
+Converts a value to the :ref:`byte <lang-byte>` data type.
+
+.. note::
+
+ Casting to the byte type is provided for compatibility with
+ Arduino. However, the recommended Maple type for storing an 8-bit
+ unsigned integer is ``uint8``. (C and C++ programmers: ``stdint.h``
+ is also available).
+
+ In order to cast a variable ``x`` to a ``uint8``, the
+ following syntax can be used::
+
+ uint8(x);
+
+Syntax
+------
+
+``byte(x)``
+
+
+Parameters
+----------
+
+**x**: a value of any integer type
+
+
+Returns
+-------
+
+The value, converted to a ``byte``. Note, however, that if the value
+is larger than the maximum value you can store in a byte (255), then
+the results might be strange and unexpected.
+
+
+See Also
+--------
+
+- :ref:`lang-byte`
+
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/cc-attribution.txt b/docs/source/lang/cpp/cc-attribution.txt
new file mode 100644
index 0000000..e100140
--- /dev/null
+++ b/docs/source/lang/cpp/cc-attribution.txt
@@ -0,0 +1,9 @@
+.. Included in all this directory's files in order to satisfy the
+.. Arduino CC Attribution-ShareAlike 3.0 License
+
+.. admonition:: License and Attribution
+
+ This documentation page was adapted from the `Arduino Reference
+ Documentation <http://arduino.cc/en/Reference/HomePage>`_\ , which
+ is released under a `Creative Commons Attribution-ShareAlike 3.0
+ License <http://creativecommons.org/licenses/by-sa/3.0/>`_.
diff --git a/docs/source/lang/cpp/char.rst b/docs/source/lang/cpp/char.rst
new file mode 100644
index 0000000..b8747f3
--- /dev/null
+++ b/docs/source/lang/cpp/char.rst
@@ -0,0 +1,50 @@
+.. highlight:: cpp
+
+.. _lang-char:
+
+``char``
+========
+
+The ``char`` type stores a 1-byte character value (or integer with
+value from -128 to 127). Character literals are written in single
+quotes, like this: ``'A'`` (for multiple characters - strings - use
+double quotes: ``"ABC"``).
+
+
+Just like everything else on a computer, characters are stored as
+numbers. You can see the specific encoding in the `ASCII chart
+<http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters>`_\
+. This means that it is possible to do arithmetic on characters, in
+which the ASCII value of the character is used (e.g. ``'A' + 1`` has the
+decimal value 66, since the ASCII value of the capital letter A in
+decimal is 65). See the :ref:`Serial.println()
+<lang-serial-println>` documentation for more information about how
+characters are converted into numbers.
+
+The ``char`` datatype is a signed type, meaning that it encodes
+numbers from -128 to 127. For an unsigned type, which stores values
+from 0 to 255, just use the type ``unsigned char`` (two words).
+
+
+Example
+-------
+
+::
+
+ // the following two lines are equivalent, using the ASCII
+ // character encoding:
+ char c = 'A';
+ char c = 65;
+
+
+See also
+--------
+
+
+- :ref:`lang-int`
+- :ref:`lang-array` (a string is just an array of ``char``\ s)
+- :ref:`Serial.println() <lang-serial-println>`
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/charcast.rst b/docs/source/lang/cpp/charcast.rst
new file mode 100644
index 0000000..a480dec
--- /dev/null
+++ b/docs/source/lang/cpp/charcast.rst
@@ -0,0 +1,36 @@
+.. highlight:: cpp
+
+.. _lang-charcast:
+
+``char()`` (cast)
+=================
+
+Converts a value to the :ref:`char <lang-char>` data type.
+
+Syntax
+------
+
+``char(x)``
+
+
+Parameters
+----------
+
+**x**: a value of any type
+
+
+Returns
+-------
+
+The value, converted to a ``char``. Note, however, that if the value
+is outside the range of a ``char`` (-128 to 127), then the results
+might be strange and unexpected.
+
+
+See Also
+--------
+
+- :ref:`char <lang-char>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/comments.rst b/docs/source/lang/cpp/comments.rst
new file mode 100644
index 0000000..c5f118a
--- /dev/null
+++ b/docs/source/lang/cpp/comments.rst
@@ -0,0 +1,67 @@
+.. highlight:: cpp
+
+.. _lang-comments:
+
+Comments
+========
+
+Comments are lines in the program that are used to inform yourself or
+others about the way the program works. They are ignored by the
+compiler, and not exported to the processor, so they don't take up any
+space in RAM or Flash.
+
+One use for comments is to help you understand (or remember) how your
+program works, or to inform others how your program works. There are
+two different ways of making comments.
+
+.. _lang-comments-singleline:
+
+**Single line comment**: Anything following two slashes, ``//``, until
+the end of the line, is a comment::
+
+ x = 5; // the rest of this line is a comment
+
+.. _lang-comments-multiline:
+
+**Multi-line comment**: Anything in between a pair of ``/*`` and ``*/``
+is a comment::
+
+ /* <-- a slash-star begins a multi-line comment
+
+ all of this in the multi-line comment - you can use it to comment
+ out whole blocks of code
+
+ if (gwb == 0){ // single line comment is OK inside a multi-line comment
+ x = 3;
+ }
+
+ // don't forget the "closing" star-slash - they have to be balanced:
+ */
+
+Note that it's okay to use single-line comments within a multi-line
+comment, but you can't use multi-line comments within a multi-line
+comment. Here's an example::
+
+ /* ok, i started a multi-line comment
+
+ x = 3; /* this next star-slash ENDS the multi-line comment: */
+
+ x = 4; // this line is outside of the multi-line comment
+
+ // next line is also outside of the comment, and causes a compile error:
+ */
+
+Programming Tip
+---------------
+
+When experimenting with code, "commenting out" parts of your program
+is a convenient way to remove lines that may be buggy. This leaves
+the lines in the code, but turns them into comments, so the compiler
+just ignores them. This can be especially useful when trying to locate
+a problem, or when a program refuses to compile and the compiler error
+is cryptic or unhelpful.
+
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/comparison.rst b/docs/source/lang/cpp/comparison.rst
new file mode 100644
index 0000000..b24355f
--- /dev/null
+++ b/docs/source/lang/cpp/comparison.rst
@@ -0,0 +1,87 @@
+.. highlight:: cpp
+
+.. _lang-comparison:
+
+Comparison Operators (``==``, ``!=``, ``<``, ``>``, ``<=``, ``>=``)
+===================================================================
+
+The comparison operators ``==``, ``!=``, ``<``, ``>``, ``<=``, and
+``>=`` are used to compare two numbers. They are :ref:`true
+<lang-constants-true>` when the comparison is true, and :ref:`false
+<lang-constants-false>` otherwise. They are based on the symbols
+=, ≠, <, >, ≤, and ≥ from mathematics.
+
+Here are some examples, with their meaning in comments::
+
+ // "eq" is true when x is equal to y
+ bool eq = (x == y);
+
+ // "neq" is true when x is different than y
+ bool neq = (x != y);
+
+ // "lt" is true when x is less than, but NOT equal to, y
+ bool lt = (x < y);
+
+ // "gt" is true when x is greater than, but NOT equal to, y
+ bool gt = (x > y);
+
+ // "lte" is true when x is less than or equal to y
+ bool lte = (x <= y);
+
+ // "gte" is true when x is greater than or equal to y
+ bool gte = (x >= y);
+
+The parentheses are optional; they are present only for clarity. For
+example, the following two lines are the same::
+
+ bool eq = x == y;
+
+ bool eq = (x == y);
+
+Uses
+----
+
+Comparison operators, along with :ref:`boolean operators
+<lang-boolean>`, are useful inside the conditionals of :ref:`if
+<lang-if>` statements. Here's one example::
+
+ if (x < 50) {
+ // only execute these lines if x is less than 50
+ SerialUSB.println("delaying:");
+ SerialUSB.println(x);
+ delay(x);
+ }
+
+.. warning::
+ Beware of accidentally using the single equal sign (``=``) when you
+ meant to test if two numbers are equal (``==``). This is a common
+ mistake inside of ``if`` statement conditionals, e.g.::
+
+ // DON'T MAKE THIS MISTAKE
+ if (x = 10) {
+ // body
+ }
+
+ The single equal sign is the assignment operator, and sets x to 10
+ (puts the value 10 into the variable x). Instead use the double equal
+ sign (e.g. ``if (x == 10)``), which is the comparison operator, and
+ tests *whether* x is equal to 10 or not. The latter statement is only
+ true if x equals 10, but the former statement will always be true.
+
+ This is because C evaluates the statement ``if (x=10)`` as follows: 10
+ is assigned to x (remember that the single equal sign is the
+ :ref:`assignment operator <lang-assignment>`), so x now
+ contains 10. Then the 'if' conditional evaluates 10, which evaluates
+ to :ref:`true <lang-constants-true>`, since any non-zero number
+ evaluates to ``true``.
+
+ Consequently, the conditional of an ``if`` statement like ``if (x =
+ 10) {...}`` will always evaluate to ``true``, and the variable x
+ will be set to 10, which is probably not what you meant.
+
+ (This sometimes has uses, though, so just because an assignment
+ appears within a conditional doesn't mean it's automatically wrong.
+ Be careful to know what you mean.)
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/compoundarithmetic.rst b/docs/source/lang/cpp/compoundarithmetic.rst
new file mode 100644
index 0000000..420f1db
--- /dev/null
+++ b/docs/source/lang/cpp/compoundarithmetic.rst
@@ -0,0 +1,44 @@
+.. highlight:: cpp
+
+.. _lang-compoundarithmetic:
+
+Compound Arithmetic Operators (``+=`` , ``-=``, ``*=``, ``/=``)
+===============================================================
+
+These oparators perform a mathematical operation on a variable with
+another constant or variable. These operators are just a convenient
+shorthand::
+
+ x += y; // equivalent to the expression x = x + y;
+ x -= y; // equivalent to the expression x = x - y;
+ x *= y; // equivalent to the expression x = x * y;
+ x /= y; // equivalent to the expression x = x / y;
+
+Here is an example::
+
+ int x = 2;
+ int y = 10;
+
+ x += 4; // x now contains 6
+ x -= 3; // x now contains 3
+ x *= y; // x now contains 30
+ x /= 2; // x now contains 15
+ x += max(20, 6); // x now contains 35
+ x -= sq(5); // x now contains 15
+
+Parameters
+----------
+
+**x**: a numeric variable
+
+**y**: a numeric variable, number constant, or any other expression
+that evaluates to a number (e.g. call to a function that returns a
+number).
+
+See Also
+--------
+
+- :ref:`Arithmetic operators <lang-arithmetic>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/compoundbitwise.rst b/docs/source/lang/cpp/compoundbitwise.rst
new file mode 100644
index 0000000..8231130
--- /dev/null
+++ b/docs/source/lang/cpp/compoundbitwise.rst
@@ -0,0 +1,230 @@
+.. highlight:: cpp
+
+.. _lang-compoundbitwise:
+
+Compound Bitwise Operators (``&=``, ``|=``, ``^=``)
+===================================================
+
+The compound bitwise operators perform their calculations at the
+bit level of variables. They are often used to clear and set
+specific bits of a variable.
+
+See the :ref:`bitwise math tutorial <lang-bitwisemath>` for more
+information on bitwise operators.
+
+.. contents:: Contents
+ :local:
+
+.. _lang-compoundbitwise-and:
+
+Compound bitwise AND (``&=``)
+-----------------------------
+
+The compound bitwise AND operator ``&=`` is often used with a variable
+and a constant to force particular bits in a variable to be zero. This
+is often referred to in programming guides as "clearing" or
+"resetting" bits. In a program, writing the line ``x &= y;`` is
+equivalent to writing ``x = x & y;``. That is, the value of ``x``
+after the line will be equal to its old value bitwise ANDed with the
+value of ``y``::
+
+ x &= y; // equivalent to x = x & y;
+
+You can use any integer variable for ``x`` (i.e., any variable of type
+``int``, ``char``, ``byte``, ``long long``, etc.). You can use either
+an integer variable or any :ref:`integer value
+<lang-constants-integers>` (like ``3`` or ``0x20``) for ``y``.
+
+Before doing an example of ``&=``, let's first review the Bitwise AND
+(``&``) operator::
+
+ 0 0 1 1 operand1
+ 0 1 0 1 operand2
+ ----------
+ 0 0 0 1 (operand1 & operand2) = result
+
+As shown above, bits that are "bitwise ANDed" with 0 become 0, while
+bits that are "bitwise ANDed" with 1 are left unchanged. So, if ``b``
+is a ``byte`` variable, then ``b & B00000000`` equals zero, and ``b &
+B11111111`` equals ``b``.
+
+.. _lang-compoundbitwise-binconst:
+
+.. note:: The above uses :ref:`binary constants
+ <lang-constants-integers-bin>`\ . The numbers are still the same
+ value in other representations, they just might not be as easy to
+ understand.
+
+ Normally, in C and C++ code, :ref:`hexadecimal
+ <lang-constants-integers-hex>` or :ref:`octal
+ <lang-constants-integers-oct>` are used when we're interested in
+ an integer's bits, rather than its value as a number.
+
+ While hexadecimal and octal literals might be harder to understand
+ at first, you should really take the time to learn them. They're
+ part of C, C++, and many other programming languages, while binary
+ constants are available only for compatibility with Arduino.
+
+ Also, ``B00000000`` is shown for clarity, but zero in any number
+ format is zero.
+
+So, to clear (set to zero) bits 0 and 1 of a one-byte variable, while
+leaving the rest of the variable's bits unchanged, use the compound
+bitwise AND operator ``&=`` with the constant ``B11111100``
+(hexadecimal ``0xFC``\ )::
+
+ 1 0 1 0 1 0 1 0 variable
+ 1 1 1 1 1 1 0 0 mask
+ ----------------------
+ 1 0 1 0 1 0 0 0
+ ^^^^^^^^^^^^^^^^ ^^^^
+ unchanged cleared
+
+
+Here is the same representation with the variable's bits replaced
+with the symbol ``x``\ ::
+
+ x x x x x x x x variable
+ 1 1 1 1 1 1 0 0 mask
+ ----------------------
+ x x x x x x 0 0
+ ^^^^^^^^^^^^^^^^ ^^^^
+ unchanged cleared
+
+
+So, using a byte variable ``b``\ , if we say::
+
+ b = B10101010; // B10101010 == 0xAA
+ b &= B11111100; // B11111100 == 0xFC
+
+then we will have ::
+
+ b == B10101000; // B10101000 == 0xA8
+
+.. _lang-compoundbitwise-or:
+
+Compound bitwise OR (``|=``)
+----------------------------
+
+The compound bitwise OR operator ``|=`` is often used with a variable
+and a constant to "set" (set to 1) particular bits in a variable. In
+a program, writing the line ``x |= y;`` is equivalent to writing ``x =
+x | y;``. That is, the value of ``x`` after the line will be equal to
+its old value bitwise ORed with the value of ``y``::
+
+ x |= y; // equivalent to x = x | y;
+
+You can use any integer variable for ``x`` (i.e., any variable of type
+``int``, ``char``, ``long long`` etc.). You can use either an integer
+variable or any integer value (like ``3`` or ``0x20``) for ``y``.
+(This works the same way as :ref:`compound bitwise AND
+<lang-compoundbitwise-and>`\ , ``&=``).
+
+Before doing an example of ``|=``, let's first review the Bitwise OR
+(``|``) operator::
+
+ 0 0 1 1 operand1
+ 0 1 0 1 operand2
+ ----------
+ 0 1 1 1 (operand1 | operand2) = result
+
+Bits that are "bitwise ORed" with 0 are unchanged, while bits that are
+"bitwise ORed" with 1 are set to 1. So if ``b`` is a ``byte``
+variable, then ``b | B00000000`` equals ``b``, and ``b & B11111111``
+equals ``B11111111`` (here we've used binary constants; see the
+:ref:`note <lang-compoundbitwise-binconst>` above).
+
+So, to set bits 0 and 1 of a one-byte variable, while leaving the rest
+of the variable unchanged, use the compound bitwise OR operator
+(``|=``) with the constant ``B00000011`` (hexadecimal ``0x3``)::
+
+ 1 0 1 0 1 0 1 0 variable
+ 0 0 0 0 0 0 1 1 mask
+ ----------------------
+ 1 0 1 0 1 0 1 1
+ ^^^^^^^^^^^^^^^^ ^^^^
+ unchanged set
+
+Here is the same representation with the variable's bits replaced with
+the symbol ``x``::
+
+ x x x x x x x x variable
+ 0 0 0 0 0 0 1 1 mask
+ ----------------------
+ x x x x x x 1 1
+ ^^^^^^^^^^^^^^^^ ^^^^
+ unchanged set
+
+So, using a byte variable ``b``, if we say::
+
+ b = B10101010; // B10101010 == 0xAA
+ b |= B00000011; // B00000011 == 0x3
+
+then we will have ::
+
+ b == B10101011; // B10101011 == 0xAB
+
+.. _lang-compoundbitwise-xor:
+
+Compound bitwise XOR (``^=``)
+-----------------------------
+
+The compound bitwise XOR operator ``^=`` is used with a variable and a
+constant to "toggle" (change 0 to 1, and 1 to 0) particular bits in a
+variable. In a program, writing the line ``x ^= y;`` is equivalent to
+writing ``x = x ^ y;``. That is, the value of ``x`` after the line
+will be equal to its old value bitwise XORed with the value of ``y``::
+
+ x ^= y; // equivalent to x = x ^ y;
+
+You can use any integer variable for ``x`` (i.e., any variable of type
+``int``, ``char``, ``long long``, etc.). You can use either an
+integer variable or any integer value (like ``3`` or ``0x20``) for
+``y``. (This works the same way as :ref:`&=
+<lang-compoundbitwise-and>` and :ref:`\|= <lang-compoundbitwise-or>`;
+in fact, these three operators all work the same in this way).
+
+Before doing an example of ``^=``, let's first review the Bitwise
+XOR operator, ``^``::
+
+ 0 0 1 1 operand1
+ 0 1 0 1 operand2
+ ----------
+ 0 1 1 0 (operand1 ^ operand2) = result
+
+One way to look at bitwise XOR is that each bit in the result is a 1
+if the input bits are different, or 0 if they are the same. Another
+way to think about it is that the result bit will be 1 when *exactly*
+one (no more, no less) of the input bits is 1; otherwise, it will be
+zero. This means that if you XOR a bit with 1, it will change (or
+toggle) its value, while if you XOR a bit with 0, it stays the same.
+
+So, to toggle bits 0 and 1 of a one-byte variable, while leaving the
+rest of the variable unchanged, use the compound bitwise XOR operator
+``^=`` with the constant ``B00000011`` (hexadecimal ``0x3``\ ; see
+:ref:`note <lang-compoundbitwise-binconst>` above)::
+
+ 1 0 1 0 1 0 1 0 variable
+ 0 0 0 0 0 0 1 1 mask
+ ----------------------
+ 1 0 1 0 1 0 1 1
+ ^^^^^^^^^^^^^^^^ ^^^^
+ unchanged toggled
+
+So, using a byte variable ``b``, if we say::
+
+ b = B10101010; // B10101010 == 0xAA
+ b ^= B00000011; // B00000011 == 0x3
+
+then we will have ::
+
+ b == B10101001; // B10101001 == 0xA9
+
+See Also
+--------
+
+- :ref:`Boolean operations <lang-boolean>` (``&&``, ``||``)
+- :ref:`Bitwise operators <lang-bitwisemath>` (``&``, ``|``, ``^``, ``~``)
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/const.rst b/docs/source/lang/cpp/const.rst
new file mode 100644
index 0000000..52de85f
--- /dev/null
+++ b/docs/source/lang/cpp/const.rst
@@ -0,0 +1,52 @@
+.. highlight:: cpp
+
+.. _lang-const:
+
+``const``
+=========
+
+The ``const`` keyword stands for "constant". It is a variable
+*qualifier* that modifies the behavior of the variable, making a
+variable "*read-only*". This means that the variable can be used just
+as any other variable of its type, but its value cannot be
+changed. You will get a compiler error if you try to assign a value to
+a ``const`` variable.
+
+Constants defined with the ``const`` keyword obey the same rules of
+:ref:`variable scoping <lang-scope>` that govern other
+variables. This, and the pitfalls of using :ref:`#define
+<lang-define>`, often makes using the ``const`` keyword a superior
+method for defining constants than ``#define``.
+
+Example
+-------
+
+::
+
+ // this defines a variable called "pi", which cannot be changed:
+ const float pi = 3.14;
+ float x;
+
+ // ....
+
+ x = pi * 2; // it's fine to find the value of a const variable
+
+ pi = 7; // illegal - you can't write to (modify) a constant
+
+
+**#define** or **const**
+------------------------
+
+You can use either ``const`` or ``#define`` for creating numeric or
+string constants. For :ref:`arrays <lang-array>`\ , you will need
+to use ``const``. In general, ``const`` is preferred over ``#define``
+for defining constants.
+
+See Also
+--------
+
+- :ref:`#define <lang-define>`
+- :ref:`volatile <lang-volatile>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/continue.rst b/docs/source/lang/cpp/continue.rst
new file mode 100644
index 0000000..13d1815
--- /dev/null
+++ b/docs/source/lang/cpp/continue.rst
@@ -0,0 +1,32 @@
+.. highlight:: cpp
+
+.. _lang-continue:
+
+``continue``
+============
+
+The ``continue`` keyword skips the rest of the current iteration of a
+:ref:`while <lang-while>`\ , :ref:`for <lang-for>`\ , or
+:ref:`do/while <lang-dowhile>` loop. It continues by checking the
+conditional expression of the loop, and proceeding with any subsequent
+iterations.
+
+Example
+-------
+
+::
+
+
+ for (x = 0; x < 255; x ++) {
+ if (x > 40 && x < 120) { // create jump in values
+ continue; // skips the next two lines and goes to the
+ // beginning of the loop, with the next value of x
+ }
+
+ digitalWrite(PWMpin, x);
+ delay(50);
+ }
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/curly-braces.rst b/docs/source/lang/cpp/curly-braces.rst
new file mode 100644
index 0000000..a4bd3dc
--- /dev/null
+++ b/docs/source/lang/cpp/curly-braces.rst
@@ -0,0 +1,109 @@
+.. highlight:: cpp
+
+.. _lang-curly-braces:
+
+Curly Braces (``{``, ``}``)
+===========================
+
+.. contents:: Contents
+ :local:
+
+Introduction
+------------
+
+Curly braces (also referred to as just "braces" or as "curly
+brackets") are a major part of the C and C++ programming
+languages. They are used in several different constructs, outlined
+below, and this can sometimes be confusing for beginners.
+
+An opening curly brace, ``{`` must always be followed by a closing
+curly brace ``}``. This is a condition that is often referred to as
+the braces being *balanced*. The Maple IDE (integrated development
+environment) includes a convenient feature to check the balance of
+curly braces. Just select a brace, or even click the insertion point
+immediately following a brace, and its companion will be highlighted\
+[#fbug]_\ .
+
+Beginning programmers, and programmers coming to C++ from languages
+without braces, often find using them confusing or daunting.
+
+Because the use of the curly brace is so varied, it is good
+programming practice to type the closing brace immediately after
+typing the opening brace when inserting a construct which requires
+curly braces. Then insert some blank lines between your braces and
+begin inserting statements. Your braces, and your attitude, will never
+become unbalanced.
+
+Unbalanced braces can often lead to cryptic, impenetrable compiler
+errors that can sometimes be hard to track down in a large program.
+Because of their varied usages, braces are also incredibly important
+to the syntax of a program and moving a brace one or two lines will
+usually dramatically affect the meaning of a program.
+
+The main uses of curly braces
+-----------------------------
+
+**Functions**::
+
+ // a function body needs braces around it
+ void myFunction(datatype argument) {
+ // ... function body goes in here ...
+ }
+
+**Loops** (see the :ref:`while <lang-while>`\ , :ref:`for
+<lang-for>`\ , and :ref:`do/while <lang-dowhile>` loop reference
+pages for more information)::
+
+ // you should put braces around the body of a loop:
+
+ while (boolean expression) {
+ // code inside the loop goes here
+ }
+
+ for (initialisation; termination condition; incrementing expr) {
+ // code inside the loop goes here
+ }
+
+ do {
+ // code inside the loop goes here
+ } while (boolean expression);
+
+
+**Conditional statements** (see the :ref:`if statement <lang-if>`
+reference page for more information)::
+
+ // you should put braces around the body of an "if", "else if",
+ // or "else":
+
+ if (boolean expression) {
+ // code inside the "if"
+ }
+ else if (boolean expression) {
+ // code inside the "else if"
+ }
+ else {
+ // code inside the "else"
+ }
+
+**Switch statements** (see the :ref:`switch statement
+<lang-switchcase>` reference page for more information)::
+
+ switch (var) {
+ case 1:
+ doThing1();
+ break;
+ case 2:
+ doThing2();
+ break;
+ }
+
+.. rubric:: Footnotes
+
+.. TODO remove this once IDE 0.1.0 released
+
+.. [#fbug] At present this feature is slightly buggy as the IDE will
+ often find (incorrectly) a brace in text that has been commented
+ out.
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/define.rst b/docs/source/lang/cpp/define.rst
new file mode 100644
index 0000000..677390d
--- /dev/null
+++ b/docs/source/lang/cpp/define.rst
@@ -0,0 +1,56 @@
+.. highlight:: cpp
+
+.. _lang-define:
+
+``#define``
+===========
+
+``#define`` is a useful C and C++ feature that allows the programmer
+to give a name to a constant value before the program is compiled.
+The compiler will replace references to these constants with the
+defined value at compile time.
+
+This can have some unwanted side effects. In general, the :ref:`const
+<lang-const>` keyword is preferred for defining constants.
+
+
+Syntax
+------
+
+The following line would define the name ``MY_CONSTANT`` to have value
+``value``::
+
+ #define MY_CONSTANT value
+
+Note that the ``#`` is necessary. It is usually good style for the
+name to be capitalized, although this is not required.
+
+There is no semicolon after the #define statement. If you include one,
+the compiler will likely throw cryptic errors in unrelated places.
+That is, **don't do this**::
+
+ // DON'T DO THIS! THE SEMICOLON SHOULDN'T BE THERE!
+ #define NAME value;
+
+Similarly, including an equal sign after the ``#define`` line will
+also generate a cryptic compiler error further down the page. That
+is, **don't do this, either**::
+
+ // DON'T DO THIS, EITHER! THE EQUALS SIGN SHOULDN'T BE THERE!
+ #define NAME = value
+
+Example
+-------
+
+::
+
+ #define LED_PIN 13
+ // The compiler will replace any mention of LED_PIN with
+ // the value 3 at compile time.
+
+See Also
+--------
+- :ref:`const <lang-const>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/double.rst b/docs/source/lang/cpp/double.rst
new file mode 100644
index 0000000..1527778
--- /dev/null
+++ b/docs/source/lang/cpp/double.rst
@@ -0,0 +1,48 @@
+.. _lang-double:
+
+``double``
+==========
+
+Double precision floating point type. Occupies 8 bytes. On Maple, the
+``double`` type has a range of approximately -1.79769×10^308 to
+1.79769×10^308; the ``double`` type subject to the same :ref:`overflow
+issues <lang-variables-rollover>` as any numeric data type.
+
+Floating point numbers are not exact, and may yield strange results
+when compared. For example ``6.0 / 3.0`` may not equal ``2.0``. You
+should instead check that the absolute value of the difference between
+the numbers is less than some small number.
+
+Floating point math is also much slower than integer math in
+performing calculations, so should be avoided if, for example, a loop
+has to run at top speed for a critical timing function. Programmers
+often go to some lengths to convert floating point calculations to
+integer math to increase speed.
+
+For more information, see the `Wikipedia article on floating point
+math <http://en.wikipedia.org/wiki/Floating_point>`_\ .
+
+Floating-point numbers represent numbers with "decimal point", unlike
+integral types, which always represent whole numbers. Floating-point
+numbers are often used to approximate analog and continuous values
+because they have greater resolution than integers.
+
+The double implementation on the Maple uses twice the number of bytes
+as a :ref:`float <lang-float>`, with the corresponding gains in
+precision.
+
+Tip
+---
+
+Users who borrow code from other sources that includes ``double``
+variables may wish to examine the code to see if the implied range and
+precision are different from that actually achieved on the Maple.
+
+See Also
+--------
+
+- :ref:`float <lang-float>`
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/doublecast.rst b/docs/source/lang/cpp/doublecast.rst
new file mode 100644
index 0000000..16a9907
--- /dev/null
+++ b/docs/source/lang/cpp/doublecast.rst
@@ -0,0 +1,27 @@
+.. highlight:: cpp
+
+.. _lang-doublecast:
+
+``double()`` (cast)
+===================
+
+Converts a value to the :ref:`double <lang-double>` floating point
+data type. Here is an example::
+
+ int x = 2;
+ double d = double(x); // d now holds 2.0, a double value
+
+The value ``x`` can be of any type. However, if ``x`` is not a number
+(like an ``int`` or ``long long``), you will get strange results.
+
+See the :ref:`double <lang-double>` reference for details about the
+precision and limitations of ``double`` values on the Maple.
+
+See Also
+--------
+
+- :ref:`double <lang-double>`
+- :ref:`float <lang-float>`
+- :ref:`float() <lang-floatcast>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/dowhile.rst b/docs/source/lang/cpp/dowhile.rst
new file mode 100644
index 0000000..fe92226
--- /dev/null
+++ b/docs/source/lang/cpp/dowhile.rst
@@ -0,0 +1,27 @@
+.. highlight:: cpp
+
+.. _lang-dowhile:
+
+``do``/``while``
+================
+
+A ``do`` loop works in the same manner as a :ref:`while
+<lang-while>` loop, with the exception that the condition is tested
+at the end of the loop, so the ``do`` loop will *always* run at least
+once.
+
+This is the basic syntax::
+
+ do {
+ // statement block
+ } while (test condition);
+
+Example::
+
+ do {
+ delay(50); // wait for sensors to stabilize
+ x = readSensors(); // check the sensors
+ } while (x < 100);
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/enum.rst b/docs/source/lang/cpp/enum.rst
new file mode 100644
index 0000000..b6409eb
--- /dev/null
+++ b/docs/source/lang/cpp/enum.rst
@@ -0,0 +1,52 @@
+.. highlight:: cpp
+
+.. _lang-enum:
+
+``enum``
+========
+
+The ``enum`` keyword is used to specify an enumeration type. An
+enumeration type is a type whose values are taken from a specified,
+fixed list of constant values.
+
+Example
+-------
+
+Here's an example defining an enumeration type called ``weather``,
+which has values ``HOT``, ``COMFY``, and ``COLD``::
+
+ enum weather {HOT, COMFY, COLD};
+
+Once you've defined this type, you can create variables of type
+``weather``, in the same way you would with an :ref:`int <lang-int>`::
+
+ // create a weather variable named theWeather, with value COMFY:
+ weather theWeather = COMFY;
+
+Enumeration types are useful within :ref:`switch statements
+<lang-switchcase>`. If you know that an argument is of an enumeration
+type, you can make ``case`` statements for all of that type's possible
+values, so you know you won't miss anything::
+
+ void describeWeather(weather currentWeather) {
+ switch(currentWeather) {
+ case HOT:
+ SerialUSB.println("it's hot out");
+ break;
+ case COMFY:
+ SerialUSB.println("it's nice today");
+ break;
+ case COLD:
+ SerialUSB.println("it's freezing!");
+ break;
+ }
+ }
+
+Such a ``switch`` statement would need no :ref:`default
+<lang-switchcase-default>`, since we know that ``currentWeather`` must
+be either ``HOT``, ``COMFY``, or ``COLD``.
+
+See Also
+--------
+
+- :ref:`lang-switchcase`
diff --git a/docs/source/lang/cpp/float.rst b/docs/source/lang/cpp/float.rst
new file mode 100644
index 0000000..6937c8c
--- /dev/null
+++ b/docs/source/lang/cpp/float.rst
@@ -0,0 +1,50 @@
+.. highlight:: cpp
+
+.. _lang-float:
+
+``float``
+=========
+
+Single-precision floating point number. Occupies 4 bytes. On Maple,
+the ``float`` type has a range of approximately -3.40282×10^38 to
+3.40282×10^38; the ``float`` type is subject to the same
+:ref:`overflow issues <lang-variables-rollover>` as any numeric data
+type.
+
+``float``\ s have only 6-7 decimal digits of precision. That means the
+total number of digits, not the number to the right of the decimal
+point. You can get more precision by using a :ref:`double
+<lang-double>` (which has a precision of about 16 decimal digits).
+
+The following example declares a ``float`` value named ``myfloat``::
+
+ float myfloat;
+
+This example declares a ``float`` value named ``sensorCalibrate``,
+with value 1.117::
+
+ float sensorCalibrate = 1.117;
+
+The general syntax for declaring a float named ``var`` with value
+``val`` is::
+
+ float var = val;
+
+Here is a more extended example involving a :ref:`float cast
+<lang-floatcast>`::
+
+ int x;
+ int y;
+ float z;
+
+ x = 1;
+ y = x / 2; // y now contains 0, ints can't hold fractions
+ z = float(x) / 2; // z now contains .5
+
+See Also
+--------
+
+- :ref:`double <lang-double>`
+- :ref:`Variables <lang-variables>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/floatcast.rst b/docs/source/lang/cpp/floatcast.rst
new file mode 100644
index 0000000..4766478
--- /dev/null
+++ b/docs/source/lang/cpp/floatcast.rst
@@ -0,0 +1,28 @@
+.. highlight:: cpp
+
+.. _lang-floatcast:
+
+``float()`` (cast)
+==================
+
+Converts a value to the :ref:`float <lang-float>` data type. Here is
+an example (see the :ref:`constants reference <lang-constants-fp>` for
+an explanation of the "2.0f")::
+
+ int x = 2;
+ float f = float(x); // f now holds 2.0f, a float value
+
+The value ``x`` can be of any type. However, if ``x`` is not a number
+(like an ``int``), you will get strange results.
+
+See the :ref:`float <lang-float>` reference for details about the
+precision and limitations of ``float`` values on the Maple.
+
+See Also
+--------
+
+- :ref:`float <lang-float>`
+- :ref:`double <lang-double>`
+- :ref:`double() <lang-doublecast>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/for.rst b/docs/source/lang/cpp/for.rst
new file mode 100644
index 0000000..71c5aca
--- /dev/null
+++ b/docs/source/lang/cpp/for.rst
@@ -0,0 +1,142 @@
+.. highlight:: cpp
+
+.. _lang-for:
+
+``for``
+=======
+
+A ``for`` loop is used to repeat a block of statements enclosed in
+curly braces. ``for`` loops are useful for performing repetitive
+operations, and are often used in combination with :ref:`arrays
+<lang-array>` to operate on collections of data or multiple
+:ref:`pins <gpio>`. A ``for`` loop is composed of two parts: first, a
+*header*, which sets up the for loop, and then a *body*, which is made
+up of lines of code enclosed in curly braces.
+
+.. contents:: Contents
+ :local:
+
+Syntax
+------
+
+There are three parts to the ``for`` loop header: an *initialization*
+expression, *loop condition* expression, and a *post-loop*
+expression. The general syntax looks like this::
+
+ for (initialization; condition; post-loop) {
+ // all of these lines inside the curly braces are part
+ // of the loop body.
+ statement 1;
+ statement 2;
+ ...
+ }
+
+(Note that there is no semicolon after the post-loop). The
+initialization happens first and exactly once, before the loop begins.
+Each time through the loop, the condition is tested. The condition is
+a :ref:`boolean <lang-boolean>` expression. If it is true, then the
+list of statements inside the curly braces are executed. Next, the
+post-loop is executed. The loop then begins again by evaluating the
+condition again, entering the loop body if it is true. This proceeds
+until the condition becomes false.
+
+Examples
+--------
+
+Here's an example::
+
+ // Dim an LED using a PWM pin
+ int pwmPin = 9; // LED in series with 470 ohm resistor on pin 9
+
+ void setup() {
+ pinMode(pwmPin, PWM);
+ }
+
+ void loop() {
+ for (int i=0; i <= 65535; i++) {
+ pwmWrite(pwmPin, i);
+ delay(1);
+ }
+ }
+
+There is a ``for`` loop In the :ref:`loop() <lang-loop>` function of
+the above example. This loop starts by declaring an ``int`` variable
+named ``i``, whose value starts out at zero. The loop proceeds by
+checking if ``i`` is less than or equal to 65535. Since ``i`` is
+zero, this is true, and so the calls to :ref:`pwmWrite()
+<lang-pwmwrite>` and :ref:`delay() <lang-delay>` happen next. At this
+point, the post-loop expression ``i++`` is evaluated, which
+:ref:`increments <lang-increment>` ``i``, so that ``i`` becomes one.
+That concludes the first time through the loop. Each "time through
+the loop" is referred to as an *iteration*.
+
+The loop then jumps back to the beginning, checking the condition as
+the beginning of its second iteration (initialization is skipped,
+since this only happens once, before the first iteration). One is
+less than 65535, so the loop statements are executed again. This
+proceeds over and over until the iteration when ``i`` finally
+reaches 65536. At that point, the condition is no longer true, so the
+loop stops executing, and the ``loop()`` function returns.
+
+Here's another example, using a ``for`` loop to brighten and fade an
+LED (see the :ref:`pwmWrite() <lang-pwmwrite>` reference for more
+information)::
+
+ int pwmPin = 9; // hook up the LED to pin 9
+ void loop() {
+ int x = 1;
+ for (int i = 0; i >= 0; i += x) {
+ analogWrite(pwmPin, i); // controls the brightness of the LED
+ if (i == 65535) {
+ x = -1; // switch direction, so i starts decreasing
+ }
+ delay(1);
+ }
+ }
+
+Coding Tips
+-----------
+
+The C ``for`` loop is more flexible than ``for`` loops found in some
+other computer languages, including BASIC. Any or all of the three
+header elements may be left blank, although the semicolons are
+required. Also the statements for initialization, condition, and
+post-loop can be any valid C statements, and use any C datatypes,
+including :ref:`floating point numbers <lang-double>`. These types
+of unusual ``for`` loops sometimes provide solutions to less-common
+programming problems.
+
+For example, using a multiplication in the post-loop line will
+generate a `geometric progression
+<http://en.wikipedia.org/wiki/Geometric_progression>`_::
+
+ for(int x = 1; x <= 100; x = x * 2) {
+ SerialUSB.println(x);
+ }
+
+
+This loop prints out the numbers 1, 2, 4, 8, ..., 64. Check
+your understanding of ``for`` loops by answering the following two
+questions (answers are in footnote [#fanswers]_\ ):
+
+1. How many iterations occur before the loop finishes?
+
+2. Why does it stop at 64?
+
+See also
+--------
+
+- :ref:`while <lang-while>` loops
+- :ref:`do <lang-dowhile>` loops
+
+.. rubric:: Footnotes
+
+.. [#fanswers]
+ 1. Seven.
+
+ 2. After the seventh iteration, the post-loop causes ``x`` to
+ equal 128. This is larger than 100, so the loop condition is
+ false, and the loop stops.
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/goto.rst b/docs/source/lang/cpp/goto.rst
new file mode 100644
index 0000000..ff2f248
--- /dev/null
+++ b/docs/source/lang/cpp/goto.rst
@@ -0,0 +1,130 @@
+.. highlight:: cpp
+
+.. _lang-goto:
+
+Labels and ``goto``
+===================
+
+A *label* gives a name to a line of code within a function. You can
+label a line by writing a name for it, then a colon (``:``), before
+the line starts. The ``goto`` keyword allows program flow to transfer
+to a labeled line from anywhere within the same function.
+
+.. warning:: The use of ``goto`` is discouraged in C and C++
+ programming. It is *never necessary* to use ``goto`` to write a
+ program.
+
+ Unless you know what you're doing, using ``goto`` tends to
+ encourage code which is harder to debug and understand than
+ programs without ``goto`` that do the same thing. That said,
+ however, it's sometimes useful; :ref:`see below <goto-when-to-use>`
+ for a concrete example.
+
+Using Labels and goto
+---------------------
+
+Labels and ``goto`` are probably best explained through example.
+Let's start with an example of how to label lines. The first line
+(``int x = analogRead(some_pin);``) in the :ref:`loop <lang-loop>`
+function below has label ``readpin``. The third line (``delay(x);``)
+has label ``startdelay``. The second line (``SerialUSB.println(x);``)
+does not have a label::
+
+ void loop() {
+ readpin:
+ int x = analogRead(some_pin);
+ SerialUSB.println(x); // for debugging
+ startdelay:
+ delay(x);
+ // ... more code ...
+ }
+
+Anything which can be a :ref:`variable <lang-variables>` name can
+be a label.
+
+Let's say that we wanted to print ``x`` only if it was very large, say
+at least 2000. We might want to do this just so anybody watching on a
+:ref:`serial monitor <ide-serial-monitor>` would know they were in for
+a longer wait than usual. We can accomplish this through the use of a
+``goto`` statement that skips the printing if ``x`` is less than
+2000::
+
+ void loop() {
+ readpin:
+ int x = analogRead(some_pin);
+ if (x < 2000) {
+ goto startdelay;
+ }
+ SerialUSB.println(x); // for debugging
+ startdelay:
+ delay(x);
+ // ... more code ...
+ }
+
+In this modified program, whenever ``x`` is less than 2000, the body
+of the :ref:`if <lang-if>` statement in the second line is
+executed. The ``goto`` statement inside the ``if`` body skips
+straight to the line labeled ``startdelay``, passing over the line
+doing the printing.
+
+A ``goto`` does not have to "move forwards"; it can go "backwards",
+too. For example, the following program prints "5" forever (why?)::
+
+ void loop() {
+ printfive:
+ SerialUSB.println(5);
+ goto printfive;
+ SerialUSB.println(6);
+ }
+
+.. _goto-when-to-use:
+
+When to Use goto
+----------------
+
+As mentioned above, use of ``goto`` is `generally discouraged
+<http://en.wikipedia.org/wiki/Goto#Criticism_and_decline>`_. However,
+when used with care, ``goto`` can simplify certain programs. One
+important use case for ``goto`` is breaking out of deeply nested
+:ref:`for <lang-for>` loops or :ref:`if <lang-if>` logic blocks.
+Here's an example::
+
+ for(int r = 0; r < 255; r++) {
+ for(int g = 255; g > -1; g--) {
+ for(int b = 0; b < 255; b++) {
+ if (analogRead(0) > 250) {
+ goto bailout;
+ }
+ // more statements ...
+ }
+ // innermost loop ends here
+ }
+ }
+ bailout:
+ // more code here
+
+In the above example, whenever the :ref:`analog reading
+<lang-analogread>` on pin 0 was greater than 250, the program would
+jump to the line labeled ``bailout``, exiting all three loops at once.
+
+While there is already a :ref:`break <lang-break>` keyword for
+breaking out of a loop, it will only break out of the *innermost*
+loop. So, if instead of saying "``goto bailout;``", there was a
+"``break;``" instead, the program would only exit from the loop with
+header "``for(int b = 0; b < 255; b++)``". The program would continue
+at the line which reads "``// innermost loop ends here``", which is
+clearly undesirable if you wanted to leave all three loops at once.
+
+More examples of when ``goto`` is a good choice are given in Donald
+Knuth's paper, "Structured Programming with go to Statements"; see
+below for a link.
+
+See Also
+--------
+
+- Dijkstra, Edsger W. `Go To Statement Considered Harmful <http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.92.4846&rep=rep1&type=pdf>`_ (PDF)
+
+- Knuth, Donald. `Structured Programming with go to Statements <http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf>`_ (PDF)
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/if.rst b/docs/source/lang/cpp/if.rst
new file mode 100644
index 0000000..bef89e2
--- /dev/null
+++ b/docs/source/lang/cpp/if.rst
@@ -0,0 +1,121 @@
+.. highlight:: cpp
+
+.. _lang-if:
+
+``if``/``else``
+===============
+
+An ``if`` statement is used to execute code when certain conditions
+are met. The general syntax for an ``if`` statement is::
+
+ if (condition) {
+ body
+ }
+
+An ``if`` statement first tests whether its *condition* is true (such
+as an input being above a certain number). If the condition is true,
+the ``if`` statement executes its *body*, which is made up of lines of
+code inside :ref:`curly braces <lang-curly-braces>`. If the condition
+is false, the body is not executed. Here's a more concrete example::
+
+ if (someVariable > 50) {
+ // do something here
+ }
+
+The program tests to see if ``someVariable`` is greater than 50. If it
+is, the program executes every line in the curly braces (which in the
+above example does nothing, since the body is just the :ref:`comment
+<lang-comments>` line "``// do something here``").
+
+Put another way, if the statement in parentheses is true, the
+statements inside the braces are run. If not, the program skips over
+the code.
+
+An ``if`` statement's condition (which is inside the parentheses after
+``if``) often uses one or more :ref:`boolean <lang-boolean>` or
+:ref:`comparison <lang-comparison>` operators.
+
+Writing the if Body
+-------------------
+
+The brackets may be omitted after an ``if`` statement's
+conditional. If this is done, the next line (which ends in a
+semicolon) becomes the only line in the body. The following three
+``if`` statements all do the same thing::
+
+ if (x > 120) digitalWrite(ledPin, HIGH);
+
+ if (x > 120)
+ digitalWrite(ledPin, HIGH);
+
+ if (x > 120) {
+ digitalWrite(ledPin, HIGH);
+ }
+
+However, the following two examples are different::
+
+ // example 1: two lines of code in the if body
+ if (x > 120) {
+ digitalWrite(ledPin1, HIGH);
+ digitalWrite(ledPin2, HIGH);
+ }
+
+ // example 2: one line of code in the if body, and
+ // another line of code after the if statement
+ if (x > 120)
+ digitalWrite(ledPin1, HIGH); // this is in the if body
+ digitalWrite(ledPin2, HIGH); // this is NOT in the if body
+
+In the first example, since the body is enclosed in curly braces, both
+lines are included. In the second example, since the curly braces are
+missing, only the first line is in the ``if`` body.
+
+``else``
+--------
+
+``if``/\ ``else`` allows greater control over the flow of code than
+the basic :ref:`if <lang-if>` statement, by allowing multiple tests to
+be grouped together. For example, an :ref:`analog input
+<lang-analogread>` could be tested, with one action taken if the input
+was less than 500, and another action taken if the input was 500 or
+greater. The code would look like this::
+
+ if (pinFiveInput < 500) {
+ // action A
+ } else {
+ // action B
+ }
+
+``else`` can precede another ``if`` test, so that multiple, mutually
+exclusive tests can be run at the same time.
+
+Each test will proceed to the next one until a true test is
+encountered. When a true test is found, its associated block of code
+is run, and the program then skips to the line following the entire
+if/else construction. If no test proves to be true, the default
+``else`` block is executed, if one is present, and sets the default
+behavior.
+
+Note that an ``else if`` block may be used with or without a
+terminating ``else`` block, and vice-versa. An unlimited number of
+such ``else if`` branches is allowed. Here is a code example::
+
+ if (pinFiveInput < 500) {
+ // do Thing A
+ } else if (pinFiveInput >= 1000) {
+ // do Thing B
+ } else {
+ // do Thing C
+ }
+
+Another way to express branching, mutually exclusive tests, is with a
+:ref:`switch/case <lang-switchcase>` statement.
+
+
+See Also
+--------
+
+- :ref:`boolean operators <lang-boolean>`
+- :ref:`comparison operators <lang-comparison>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/include.rst b/docs/source/lang/cpp/include.rst
new file mode 100644
index 0000000..74fe7af
--- /dev/null
+++ b/docs/source/lang/cpp/include.rst
@@ -0,0 +1,72 @@
+.. highlight:: cpp
+
+.. _lang-include:
+
+``#include``
+============
+
+``#include`` is used to include outside libraries in your sketch.
+This gives the programmer access to a large group of standard C
+libraries (groups of pre-made functions and data types), and also
+libraries written especially for Maple.
+
+Example
+-------
+
+This example (from the `Arduino LiquidCrystal Tutorial
+<http://arduino.cc/en/Tutorial/LiquidCrystal>`_) includes a library
+that is used to control :ref:`LCD displays
+<libraries-liquid-crystal>`::
+
+ // include the library code:
+ #include <LiquidCrystal.h>
+
+ // initialize the library with the numbers of the interface pins
+ LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
+
+ void setup() {
+ // set up the LCD's number of columns and rows:
+ lcd.begin(16, 2);
+ // Print a message to the LCD.
+ lcd.print("hello, world!");
+ }
+
+ void loop() {
+ // set the cursor to column 0, line 1
+ // (note: line 1 is the second row, since counting begins with 0):
+ lcd.setCursor(0, 1);
+ // print the number of seconds since reset:
+ lcd.print(millis()/1000);
+ }
+
+Note that a ``#include`` line, like :ref:`#define <lang-define>`,
+has **no semicolon**. The compiler will print strange error messages
+if you add one.
+
+C Standard Library
+------------------
+
+The standard C library that comes with Maple is called `newlib
+<http://sourceware.org/newlib/>`_. Its main sources of documentation
+are its `main reference <http://sourceware.org/newlib/libc.html>`_
+page and its `math functions
+<http://sourceware.org/newlib/libm.html>`_ reference page. Here's an
+example that imports the math.h library in order to take the `cube
+root <http://en.wikipedia.org/wiki/Cube_root>`_ of a number::
+
+ #include <math.h>
+
+ void setup() {
+ // no setup necessary
+ }
+
+ void loop() {
+ // "cbrt" stands for "cube root"
+ double cubeRootOf3 = cbrt(3.0);
+ // prints a number that is approximately the cube root of 3:
+ SerialUSB.println(cubeRootOf3);
+ }
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/increment.rst b/docs/source/lang/cpp/increment.rst
new file mode 100644
index 0000000..6dffa80
--- /dev/null
+++ b/docs/source/lang/cpp/increment.rst
@@ -0,0 +1,37 @@
+.. highlight:: cpp
+
+.. _lang-increment:
+
+Increment and Decrement Operators (``++``, ``--``)
+==================================================
+
+These operators increment (add one to) or decrement (subtract one
+from) a variable. If they come before the variable, they return its
+new value; otherwise, they return its old value.
+
+Some quick examples::
+
+ x++; // adds one to x, and returns the old value of x
+ ++x; // adds one to x, and returns the new value of x
+
+ x--; // decrement x by one and returns the old value of x
+ --x; // decrement x by one and returns the new value of x
+
+A more extended example::
+
+ x = 2;
+ y = ++x; // x now contains 3, y contains 3
+ y = x--; // x contains 2 again, y still contains 3
+
+.. warning:: Be careful! You cannot put a space in between the two
+ ``+`` or ``-`` signs. This example is broken::
+
+ // this line won't compile (notice the extra space):
+ int y = x+ +;
+
+See Also
+--------
+
+- :ref:`lang-compoundarithmetic`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/int.rst b/docs/source/lang/cpp/int.rst
new file mode 100644
index 0000000..3e96b69
--- /dev/null
+++ b/docs/source/lang/cpp/int.rst
@@ -0,0 +1,68 @@
+.. highlight:: cpp
+
+.. _lang-int:
+
+``int``
+=======
+
+The ``int`` data type represents integers. Integers are your primary
+data type for number storage, and store a 4 byte value. This yields a
+range of -2,147,483,648 to 2,147,483,647 (minimum value of -2^31 and a
+maximum value of (2^31) - 1; that's about negative 2 billion to
+positive 2 billion).
+
+An ``int`` stores a negative number with a technique called `two's
+complement math
+<http://en.wikipedia.org/wiki/Two%27s_complement#Explanation>`_\ .
+The highest bit in an ``int``, sometimes refered to as the "sign" bit,
+flags the number as a negative number. (See the linked article on
+two's complement for more information).
+
+The Maple takes care of dealing with negative numbers for you, so that
+arithmetic operations work mostly as you'd expect. There can be an
+:ref:`unexpected complication <lang-bitshift-signbit-gotcha>` in
+dealing with the :ref:`bitshift right operator (>>)
+<lang-bitshift>`, however.
+
+.. _lang-long:
+
+The ``long`` type is a synonym for ``int``.
+
+Here is an example of declaring an ``int`` variable named ``ledPin``,
+then giving it value 13::
+
+ int ledPin = 13;
+
+The general syntax for declaring an ``int`` variable named ``var``,
+then giving it value ``val``, looks like::
+
+ int var = val;
+
+.. _lang-int-overflow:
+
+Integer Overflow
+----------------
+
+When ``int`` variables leave the range specified above, they
+:ref:`roll over <lang-variables-rollover>` in the other direction.
+Here are some examples::
+
+ int x;
+ x = -2,147,483,648;
+ x--; // x now contains 2,147,483,647; rolled over "left to right"
+
+ x = 2,147,483,647;
+ x++; // x now contains -2,147,483,648; rolled over "right to left"
+
+See Also
+--------
+
+- :ref:`unsigned int <lang-unsignedint>`
+- :ref:`char <lang-char>`
+- :ref:`unsigned char <lang-unsignedchar>`
+- :ref:`long long <lang-longlong>`
+- :ref:`unsigned long long <lang-unsignedlonglong>`
+- :ref:`Integer Constants <lang-constants-integers>`
+- :ref:`Variables <lang-variables>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/intcast.rst b/docs/source/lang/cpp/intcast.rst
new file mode 100644
index 0000000..386fe14
--- /dev/null
+++ b/docs/source/lang/cpp/intcast.rst
@@ -0,0 +1,29 @@
+.. highlight:: cpp
+
+.. _lang-intcast:
+
+``int()`` (cast)
+================
+
+Converts a value to the :ref:`int <lang-int>` data type. Here is
+an example::
+
+ double d = 2.5;
+ int i = int(d); // i holds "2", an int value
+
+The value inside of the parentheses (``int(...)``) can be of any type.
+However, if it is not a numeric type (like ``double``, ``char``,
+etc.), you will get strange results.
+
+See the :ref:`int <lang-int>` reference for details about the
+precision and limitations of ``int`` variables on the Maple.
+
+See Also
+--------
+
+- :ref:`int <lang-int>`
+
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/keywords.rst b/docs/source/lang/cpp/keywords.rst
new file mode 100644
index 0000000..f21cd0d
--- /dev/null
+++ b/docs/source/lang/cpp/keywords.rst
@@ -0,0 +1,204 @@
+.. _lang-keywords:
+
+Keywords
+========
+
+This page lists all of the C++ keywords, and either links to a
+reference page explaining their use, or provides a brief description.
+
+List of Keywords
+----------------
+
+The C++ keywords are:
+
+``and``, ``and_eq``, ``asm``, ``auto``, ``bitand``, ``bitor``,
+``bool``, ``break``, ``case``, ``catch``, ``char``, ``class``,
+``compl``, ``const``, ``const_cast``, ``continue``, ``default``,
+``delete``, ``do``, ``double``, ``dynamic_cast``, ``else``, ``enum``,
+``explicit``, ``export``, ``extern``, ``false``, ``float``, ``for``,
+``friend``, ``goto``, ``if``, ``inline``, ``int``, ``long``,
+``mutable``, ``namespace``, ``new``, ``not``, ``not_eq``,
+``operator``, ``or``, ``or_eq``, ``private``, ``protected``,
+``public``, ``register``, ``reinterpret_cast``, ``return``, ``short``,
+``signed``, ``sizeof``, ``static``, ``static_cast``, ``struct``,
+``switch``, ``template``, ``this``, ``throw``, ``true``, ``try``,
+``typedef``, ``typeid``, ``typename``, ``union``, ``unsigned``,
+``using``, ``virtual``, ``void``, ``volatile``, ``wchar_t``,
+``while``, ``xor``, ``xor_eq``
+
+Boolean Operator Synonyms
+-------------------------
+
+- ``and`` is a synonym for :ref:`&& <lang-boolean-and>`.
+- ``not`` is a synonym for :ref:`\! <lang-boolean-not>`.
+- ``not_eq`` is a synonym for :ref:`\!= <lang-comparison>`.
+- ``or`` is a synonym for :ref:`|| <lang-boolean-or>`.
+
+Bitwise Operator Synonyms
+-------------------------
+
+- ``and_eq`` is a synonym for :ref:`&= <lang-compoundbitwise-and>`.
+- ``bitand`` is a synonym for (bitwise) :ref:`& <lang-bitwisemath-and>`.
+- ``bitor`` is a synonym for :ref:`\| <lang-bitwisemath-or>`.
+- ``compl`` is a synonym for :ref:`~ <lang-bitwisemath-not>`.
+- ``or_eq`` is a synonym for :ref:`|= <lang-compoundbitwise-or>`.
+- ``xor`` is a synonym for :ref:`^ <lang-bitwisemath-xor>`.
+- ``xor_eq`` is a synonym for :ref:`^= <lang-compoundbitwise-xor>`.
+
+Constants
+---------
+
+- ``true`` and ``false`` are the :ref:`boolean constants
+ <lang-booleanvariables>`.
+
+Control Flow
+------------
+
+- ``break`` can exit out of a :ref:`switch statement
+ <lang-switchcase>` or a :ref:`for <lang-for>`, :ref:`do
+ <lang-dowhile>`, or :ref:`while <lang-while>` loop.
+
+- ``case`` defines alternatives in a :ref:`switch statement <lang-switchcase>`.
+
+- ``continue`` will move control flow to the next iteration of the
+ enclosing :ref:`for <lang-for>`, :ref:`do <lang-dowhile>`, or
+ :ref:`while <lang-while>` loop.
+
+- ``default`` defines the default alternative in a :ref:`switch
+ statement <lang-switchcase>`.
+
+- ``do`` introduces a :ref:`do <lang-dowhile>` loop.
+
+- ``else`` is used in :ref:`if statements <lang-if>`.
+
+- ``for`` introduces a :ref:`for <lang-for>` loop.
+
+- ``goto`` :ref:`jumps <lang-goto>` to a label.
+
+- ``if`` introduces an :ref:`if statement <lang-if>`.
+
+- ``return`` :ref:`transfers flow to a function's caller <lang-return>`.
+
+- ``switch`` introduces a :ref:`switch statement <lang-switchcase>`.
+
+- ``while`` introduces a :ref:`while <lang-while>` loop.
+
+Types
+-----
+
+The following keywords are used for built-in types.
+
+- :ref:`bool <lang-booleanvariables>`
+- :ref:`char <lang-char>`
+- :ref:`double <lang-double>`
+- :ref:`float <lang-float>`
+- :ref:`int <lang-int>`
+- :ref:`long <lang-long>`
+- :ref:`short <lang-built-in-types-integral>`
+- :ref:`void <lang-void>` (not really a type, but used in the absence
+ of one)
+
+The following keywords are used to introduce new types.
+
+- :ref:`enum <lang-enum>`
+
+Qualifiers
+----------
+
+- :ref:`static <lang-static>` can be used to declare persistent local
+ variables; it has other uses not documented here.
+
+- ``unsigned`` is used to specify an unsigned integral type.
+ Examples: :ref:`lang-unsignedint`, :ref:`lang-unsignedchar`.
+
+- :ref:`volatile <lang-volatile>` is useful when declaring variables
+ that may be modified by external interrupts.
+
+- :ref:`const <lang-const>` is used to define constants.
+
+Other
+-----
+
+These keywords are not described in the Maple documentation. For more
+information, consult a C++ reference.
+
+- ``asm`` is used to insert literal assembly language.
+
+- ``auto`` is used to declare that a variable has automatic storage.
+
+- ``catch`` is used in exception handling. Note that the default
+ flags we pass to :ref:`GCC <arm-gcc>` include ``-fno-exceptions``.
+
+- ``class`` is used to define classes.
+
+- ``const_cast`` is used in typecasting.
+
+- ``delete`` is used to free ``new``\ -allocated storage. Note that
+ dynamic memory allocation is not available by default on the Maple,
+ so you'll have to bring your own ``new`` and ``delete`` if you want
+ this.
+
+- ``dynamic_cast`` is used in typecasting.
+
+- ``explicit`` is used to declare constructors that can be called only
+ explicitly.
+
+- ``export`` declares a template definition accessible to other
+ compilation units.
+
+- ``extern`` can mark a declaration as a declaration and not a
+ definition, and also grant external linkage to a ``const`` or
+ ``typedef``.
+
+- ``friend`` is used to declare that certain functions have access to
+ a class's private variables.
+
+- ``inline`` is a compiler hint to inline a function.
+
+- ``mutable`` specifies that a member can be updated, even when a
+ member of a ``const`` object.
+
+- ``namespace`` declares a new namespace.
+
+- ``new`` dynamically allocates space for a value. Note that dynamic
+ memory allocation is not available by default on the Maple, so
+ you'll have to bring your own ``new`` and ``delete`` if you want
+ this.
+
+- ``operator`` is used to define type-specific operator overrides.
+
+- ``private`` declares a private class member.
+
+- ``protected`` declares a protected class member.
+
+- ``public`` declares a public class member.
+
+- ``register`` is a compiler hint to store a variable in a register.
+
+- ``reinterpret_cast`` is used in typecasting.
+
+- ``signed`` is the opposite of ``unsigned``.
+
+- ``static_cast`` is used in typecasting.
+
+- ``struct`` declares a new struct.
+
+- ``template`` introduces a template class, function, etc.
+
+- ``this`` is a pointer to the receiver object.
+
+- ``throw`` is used in exception handling. Note that the default
+ flags we pass to :ref:`GCC <arm-gcc>` include ``-fno-exceptions``.
+
+- ``try`` is used in exception handling. Note that the default
+ flags we pass to :ref:`GCC <arm-gcc>` include ``-fno-exceptions``.
+
+- ``typedef`` defines a type synonym.
+
+- ``union`` defines an untagged union.
+
+- ``using`` is a directive related to namespaces.
+
+- ``virtual`` declares a method which may be overridden.
+
+- ``wchar_t`` is the wide character type.
diff --git a/docs/source/lang/cpp/longcast.rst b/docs/source/lang/cpp/longcast.rst
new file mode 100644
index 0000000..f588fc6
--- /dev/null
+++ b/docs/source/lang/cpp/longcast.rst
@@ -0,0 +1,27 @@
+.. highlight:: cpp
+
+.. _lang-longcast:
+
+``long()`` (cast)
+=================
+
+Converts a value to the :ref:`long <lang-long>` data type. Here is
+an example::
+
+ double d = 2.5;
+ long i = long(d); // i holds "2L", an long value
+
+The value inside of the parentheses (``long(...)``) can be of any type.
+However, if it is not a numeric type (like ``double``, ``char``,
+etc.), you will get strange results.
+
+See the :ref:`long <lang-long>` reference for details about the
+precision and limitations of ``long`` variables on the Maple.
+
+See Also
+--------
+
+- :ref:`long <lang-long>`
+- :ref:`long long <lang-longlong>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/longlong.rst b/docs/source/lang/cpp/longlong.rst
new file mode 100644
index 0000000..0ba56ed
--- /dev/null
+++ b/docs/source/lang/cpp/longlong.rst
@@ -0,0 +1,56 @@
+.. highlight:: cpp
+
+.. _lang-longlong:
+
+``long long``
+=============
+
+The ``long long`` data type stores extended size integer values. You
+can use a ``long long`` when your values are too large to fit into an
+:ref:`int <lang-int>`. A ``long long`` occupies 8 bytes of memory.
+This yields a range of approximately -9.2×10^18 to 9.2×10^18 (that's
+9.2 billion billion, or about 92 million times the number of stars in
+the Milky Way galaxy). The exact range of a ``long long`` on the
+Maple is from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807,
+or -2^63 to (2^63-1). A ``long long`` it is subject to the same
+:ref:`overflow issues <lang-variables-rollover>` as any numeric data
+type.
+
+A synonym for the ``long long`` type is ``int64``.
+
+Here's an example of declaring a long long (see :ref:`integer
+constants <lang-constants-integers-u-l>` for an explanation of the
+"LL" at the end of the number)::
+
+ // Speed of light in nanometers per second (approximate).
+ long long c = 299792458000000000LL;
+
+The general syntax for declaring an ``long long`` variable named ``var``,
+then giving it value ``val``, looks like::
+
+ long long var = val;
+
+This is identical to the ``int`` syntax, with ``long long`` (or, at
+your option, ``int64``) replacing ``int``.
+
+Note that ``long long`` values will still :ref:`overflow
+<lang-int-overflow>`, just like ``int`` values, but their much larger
+range makes this less likely to happen.
+
+The downside to using a ``long long`` instead of an ``int`` (besides
+the extra storage) is that :ref:`arithmetic <lang-arithmetic>`
+operations on ``long long``\ s will take slightly longer than on
+``int``\ s.
+
+See Also
+--------
+
+- :ref:`char <lang-char>`
+- :ref:`unsigned char <lang-unsignedchar>`
+- :ref:`int <lang-int>`
+- :ref:`unsigned int <lang-unsignedint>`
+- :ref:`unsigned long long <lang-unsignedlonglong>`
+- :ref:`Integer Constants <lang-constants-integers>`
+- :ref:`Variables <lang-variables>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/modulo.rst b/docs/source/lang/cpp/modulo.rst
new file mode 100644
index 0000000..289fba0
--- /dev/null
+++ b/docs/source/lang/cpp/modulo.rst
@@ -0,0 +1,70 @@
+.. highlight:: cpp
+
+.. _lang-modulo:
+
+Modulo Operator (``%``)
+=======================
+
+Calculates the `remainder <http://en.wikipedia.org/wiki/Remainder>`_
+when one integer is divided by another. It is useful for keeping a
+variable within a particular range (e.g. the size of an array).
+
+Syntax
+------
+
+::
+
+ dividend % divisor
+
+Parameters
+----------
+
+**dividend**: the number to be divided
+
+**divisor**: the number to divide by
+
+Returns
+-------
+
+The remainder of **dividend**\ /\ **divisor**\ .
+
+Examples
+--------
+
+::
+
+ int x;
+ x = 7 % 5; // x now contains 2
+ x = 9 % 5; // x now contains 4
+ x = 5 % 5; // x now contains 0
+ x = 4 % 5; // x now contains 4
+
+::
+
+ /* update one value in an array each time through a loop */
+
+ int values[10];
+ int i = 0;
+
+ void setup() {
+ // no setup necessary
+ }
+
+ void loop() {
+ values[i] = analogRead(0);
+ i = (i + 1) % 10; // modulo operator makes sure i stays between 0 and 9
+ }
+
+Tip
+---
+
+The modulo operator does not work on floats. For that, you can use
+the C standard library function `fmod()
+<http://sourceware.org/newlib/libm.html#fmod>`_.
+
+See Also
+--------
+
+- :ref:`Arithmetic <lang-arithmetic>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/pointer.rst b/docs/source/lang/cpp/pointer.rst
new file mode 100644
index 0000000..0a42270
--- /dev/null
+++ b/docs/source/lang/cpp/pointer.rst
@@ -0,0 +1,31 @@
+.. _lang-pointer:
+
+Pointer Operators (``&``, ``*``)
+================================
+
+The pointer operators ``&`` (reference) and ``*`` (dereference) are
+different from the bitwise math operator :ref:`&
+<lang-bitwisemath-and>` and the arithmetic operator :ref:`*
+<lang-arithmetic>`.
+
+Pointers are one of the more complicated subjects for beginners in
+learning C, and it is possible to write many useful Arduino sketches
+without ever encountering pointers. However, for manipulating certain
+data structures, the use of pointers can simplify the code, improve
+its efficiency, and generally provide many benefits that would be
+difficult to achieve without the use of pointers.
+
+Introducing pointers is somewhat outside the scope of this
+documentation. However, a good `pointer tutorial
+<http://www.cplusplus.com/doc/tutorial/pointers/>`_ is available.
+Also see the `Wikipedia article on pointers
+<http://en.wikipedia.org/wiki/Pointer_%28computing%29>`_, especially
+the section on `pointers in C
+<http://en.wikipedia.org/wiki/Pointer_%28computing%29#C_pointers>`_.
+
+See Also
+--------
+
+- http://xkcd.com/138/
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/return.rst b/docs/source/lang/cpp/return.rst
new file mode 100644
index 0000000..b4ef5fd
--- /dev/null
+++ b/docs/source/lang/cpp/return.rst
@@ -0,0 +1,61 @@
+.. highlight:: cpp
+
+.. _lang-return:
+
+``return``
+==========
+
+Terminates a function and return a value from a function to the
+calling function, if the function has non-``void`` return type.
+
+Syntax:
+-------
+
+::
+
+ // from within a "void" function:
+ return;
+
+ // from within a non-"void" function:
+ return value;
+
+In the second case, ``value`` should have a type which is the same as
+the return type of the function, or be convertible to it (like an
+``int`` to a ``double``, etc.; see :ref:`this note
+<lang-arithmetic-typeconversion>` for some references).
+
+Examples:
+---------
+
+A function to compare a sensor input to a threshold::
+
+ // converts analog readings between 0 and 400 to 0, and 400 up to 1.
+ int checkSensor() {
+ if (analogRead(0) > 400) {
+ return 1;
+ else {
+ return 0;
+ }
+ }
+
+An early ``return`` is also useful when testing a section of code
+without having to "comment out" large sections of possibly buggy code,
+like so::
+
+ void loop() {
+
+ // brilliant code idea to test here
+
+ return;
+
+ // the rest of a dysfunctional sketch here
+ // this code will never be executed
+ }
+
+See Also
+--------
+
+- :ref:`comments <lang-comments>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/scope.rst b/docs/source/lang/cpp/scope.rst
new file mode 100644
index 0000000..7b65bab
--- /dev/null
+++ b/docs/source/lang/cpp/scope.rst
@@ -0,0 +1,120 @@
+.. highlight:: cpp
+
+.. _lang-scope:
+
+Scope
+=====
+
+Variables in the C++ programming language, which Maple uses (all of
+your sketches are C++ programs in disguise), have a property called
+*scope*. Simply put, a variable's scope is made up of all of the
+lines where the variable can be used.
+
+Scope in C++ is a fairly complex topic, so we won't try to describe it
+in full here. Instead, we present a simplified view, describing two
+different kinds of scopes, *global* and *local*. For more detailed
+information, consult a C++ reference.
+
+Global and Local Variables
+--------------------------
+
+A global variable is one that can be "seen" by every function in a
+program. In the :ref:`Maple IDE <ide>`, any variable declared outside
+of a function (like :ref:`setup() <lang-setup>` and :ref:`loop()
+<lang-loop>`) is a global variable.
+
+A local variable can only be "seen" inside of a particular function.
+You can declare a variable to be local to a function by declaring it
+inside of the :ref:`curly braces <lang-curly-braces>` which enclose
+that function.
+
+When programs start to get larger and more complex, local variables
+are a useful way to ensure that a function has exclusive access to its
+own variables. This prevents programming errors when one function
+mistakenly modifies variables used by another function.
+
+It is also sometimes useful to declare and initialize a variable
+inside a :ref:`for <lang-for>` loop. This creates a variable that
+can only be accessed from inside the loop body.
+
+Example
+-------
+
+Here is an example sketch (which you can copy into the Maple IDE and
+run on your Maple) that illustrates the use of global and local
+variables, as well as declaring variables inside of a ``for`` loop.
+Be sure to open a :ref:`serial monitor <ide-serial-monitor>` after you
+:ref:`verify <ide-verify>` and :ref:`upload <ide-upload>` the sketch::
+
+ int globalVar; // any function will see this variable
+
+ void setup() {
+ // since "globalVar" is declared outside of any function,
+ // every function can "see" and use it:
+ globalVar = 50;
+
+ // the variables "i" and "d" declared inside the "loop" function
+ // can't be seen here. see what happens when you uncomment the
+ // following lines, and try to Verify (compile) the sketch:
+ //
+ // i = 16;
+ // SerialUSB.print("i = ");
+ // SerialUSB.println(i);
+ // d = 26.5;
+ // SerialUSB.print("d = ");
+ // SerialUSB.println(d);
+ }
+
+ void loop() {
+ // since "i" and "d" are declared inside of the "loop" function,
+ // they can only be seen and used from inside of it:
+ int i;
+ double d;
+
+ for (int j = 0; j < 5; j++) {
+ // variable i can be used anywhere inside the "loop" function;
+ // variable j can only be accessed inside the for-loop brackets:
+ i = j * j;
+ SerialUSB.print("i = ");
+ SerialUSB.println(i);
+ }
+
+ // globalVar can be accessed from anywhere. note how even
+ // though we set globalVar = 50 in the "setup" function, we can
+ // see that value here:
+ SerialUSB.print("globalVar = ");
+ SerialUSB.println(globalVar);
+
+ // d can be accessed from anywhere inside the "loop" function:
+ d = 26.5;
+ SerialUSB.print("d = ");
+ SerialUSB.print(d);
+ SerialUSB.println(" (before separateFunction())");
+
+ separateFunction();
+
+ // notice how even though separateFunction() has a variable
+ // named "d", it didn't touch our (local) variable which has
+ // the same name:
+ SerialUSB.print("d = ");
+ SerialUSB.print(d);
+ SerialUSB.println(" (after separateFunction())");
+ }
+
+ void separateFunction() {
+ // variable "d" here has the same name as variable "d" inside of
+ // the "loop" function, but since they're both _local_
+ // variables, they don't affect each other:
+ double d = 30.5;
+ SerialUSB.print("d = ");
+ SerialUSB.print(d);
+ SerialUSB.println(" (inside of separateFunction())");
+ }
+
+See Also
+--------
+
+- `C++ programming Wikibook <http://en.wikibooks.org/wiki/C%2B%2B_Programming/Programming_Languages/C%2B%2B/Code/Statements/Scope>`_.
+- Wikipedia article on `scope <http://en.wikipedia.org/wiki/Scope_%28programming%29>`_
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/semicolon.rst b/docs/source/lang/cpp/semicolon.rst
new file mode 100644
index 0000000..8164616
--- /dev/null
+++ b/docs/source/lang/cpp/semicolon.rst
@@ -0,0 +1,25 @@
+.. highlight:: cpp
+
+.. _lang-semicolon:
+
+Semicolon (``;``)
+=================
+
+Used to end a line of code. Example::
+
+ int a = 13;
+
+Tip
+---
+
+Forgetting to end a line in a semicolon will result in a compiler
+error. The error text may be obvious, and refer to a missing
+semicolon, or it may not. If an impenetrable or seemingly illogical
+compiler error comes up, one of the first things to check is a
+missing semicolon, in the immediate vicinity, preceding the line at
+which the compiler complained.
+
+
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/sizeof.rst b/docs/source/lang/cpp/sizeof.rst
new file mode 100644
index 0000000..eae509c
--- /dev/null
+++ b/docs/source/lang/cpp/sizeof.rst
@@ -0,0 +1,64 @@
+.. highlight:: cpp
+
+.. _lang-sizeof:
+
+``sizeof()``
+============
+
+The ``sizeof`` operator on the Maple returns the number of bytes
+needed to store a value of a given type\ [#fcharsize]_. This can be
+an ordinary numeric type, like ``int``. It can be something more
+complicated, like a ``struct`` or ``union``. If the argument to
+``sizeof`` is an array, it returns the total number of bytes occupied
+by the array.
+
+The general syntax looks like this::
+
+ sizeof(type)
+ sizeof(var)
+
+Example
+-------
+
+The ``sizeof`` operator is useful for dealing with arrays (such as
+strings) where it is convenient to be able to change the size of the
+array without breaking other parts of the program.
+
+This program prints out a text string one character at a time. Try
+changing the text phrase::
+
+ char myStr[] = "this is a test";
+ int i;
+
+ void setup() {
+ Serial.begin(9600);
+ }
+
+ void loop() {
+ for (i = 0; i < sizeof(myStr) - 1; i++) {
+ Serial.print(i, DEC);
+ Serial.print(" = ");
+ Serial.println(myStr[i], BYTE);
+ }
+ }
+
+
+Note that ``sizeof`` returns the total number of bytes. So for larger
+variable types such as ``int``, the :ref:`for loop <lang-for>`
+would look something like this::
+
+ for (i = 0; i < (sizeof(myInts)/sizeof(int)) - 1; i++) {
+ // do something with myInts[i]
+ }
+
+.. rubric:: Footnotes
+
+.. [#fcharsize] Technically (and pedantically) speaking, ``sizeof``
+ returns a multiple of the number of bits a ``char`` occupies in
+ memory. However, on the Maple (this goes for most C++
+ implementations), a ``char`` occupies 8 bits = 1 byte. All the C++
+ standard guarantees, however, is that a ``char`` occupies at
+ *least* 8 bits.
+
+.. include:: cc-attribution.txt
+
diff --git a/docs/source/lang/cpp/sqrt.rst b/docs/source/lang/cpp/sqrt.rst
new file mode 100644
index 0000000..956a754
--- /dev/null
+++ b/docs/source/lang/cpp/sqrt.rst
@@ -0,0 +1,25 @@
+.. _lang-sqrt:
+
+sqrt()
+======
+
+Calculates the square root of a number.
+
+Library Documentation
+---------------------
+
+.. doxygenfunction:: sqrt
+
+Arduino Compatibility
+---------------------
+
+The Maple versino of ``sqrt()`` is compatible with Arduino.
+
+See Also
+--------
+
+- :ref:`pow <lang-pow>`
+- :ref:`sq <lang-sq>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/static.rst b/docs/source/lang/cpp/static.rst
new file mode 100644
index 0000000..5d1802e
--- /dev/null
+++ b/docs/source/lang/cpp/static.rst
@@ -0,0 +1,57 @@
+.. highlight:: cpp
+
+.. _lang-static:
+
+``static``
+==========
+
+The ``static`` keyword can be used to create variables that are
+visible to only one function. However, unlike local variables that get
+created and destroyed every time a function is called, ``static``
+variables persist beyond the function call, preserving their data
+between function calls.
+
+Variables declared as ``static`` will only be created and initialized
+the first time a function is called.
+
+.. note:: This is only one use of the ``static`` keyword in C++. It
+ has some other important uses that are not documented here; consult
+ a reliable C++ reference for details.
+
+Example
+-------
+
+One use case for ``static`` variables is implementing counters that
+last longer than the functions which need them, but shouldn't be
+shared to other functions. Here's an example::
+
+ void setup() {
+ SerialUSB.begin();
+ }
+
+ void loop() {
+ int reading;
+ if (timeToReadSensors()) {
+ reading = readSensors();
+ }
+ // do something with reading
+ }
+
+ int readSensors() {
+ static int numSensorReadings = 0;
+ numSensorReadings++;
+ if (numSensorReadings % 100 == 0) {
+ SerialUSB.print("just got to another 100 sensor readings");
+ }
+ return analogRead(...);
+ }
+
+In this example, the static variable ``numSensorReadings`` is
+initialized to zero the first time ``readSensors()`` is called, and
+then incremented, so it starts out at one. Subsequent calls to
+``readSensors()`` won't reset ``numSensorReadings`` to zero, because
+it was declared ``static``. Thus, ``numSensorReadings`` is a count of
+the number of times that ``readSensors()`` has been called.
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/string.rst b/docs/source/lang/cpp/string.rst
new file mode 100644
index 0000000..0a270da
--- /dev/null
+++ b/docs/source/lang/cpp/string.rst
@@ -0,0 +1,128 @@
+.. highlight:: cpp
+
+.. _lang-string:
+
+Strings
+=======
+
+Text strings can be represented in two ways. You can
+
+1. Use the :ref:`String <lang-stringclass>` data type, which is
+part of the core as of version 0.0.9, or
+
+2. You can make a string out of an array of type :ref:`char
+<lang-char>` and null-terminate it.
+
+This page describes the second method.
+
+Examples
+--------
+
+All of the following are valid declarations for strings::
+
+ char str1[15];
+ char str2[6] = {'m', 'a', 'p', 'l', 'e'};
+ char str3[6] = {'m', 'a', 'p', 'l', 'e', '\0'};
+ char str4[ ] = "maple";
+ char str5[6] = "maple";
+ char str6[15] = "maple";
+
+As you can see, there are several methods available for declaring and
+initializing strings:
+
+- Declare an array of ``char`` without initializing it, as with ``str1``.
+
+- Declare an array of ``char`` (with one extra ``char``) and the
+ compiler will add the required null character, as with ``str2``.
+
+- Explicitly add the null character (``'\0'``), as with ``str3``.
+
+- Initialize with a string constant in quotation marks (``"..."``);
+ the compiler will size the array to fit the string constant and a
+ terminating null character (``str4``).
+
+- Initialize the array with an explicit size and string constant,
+ (``str5``).
+
+- Initialize the array, leaving extra space for a larger string
+ (``str6``).
+
+Null Termination
+----------------
+
+Generally, strings are terminated with a null character (`ASCII
+<http://en.wikipedia.org/wiki/ASCII>`_ code 0). This allows functions
+(like ``SerialUSB.print()``) to tell where the end of a string is.
+Otherwise, they would continue reading subsequent bytes of memory that
+aren't actually part of the string.
+
+This means that your string needs to have space for one more character
+than the text you want it to contain. That is why ``str2`` and
+``str5`` need to be six characters, even though "maple" is only five
+-- the last position is automatically filled with a NULL
+character. ``str4`` will be automatically sized to six characters, one
+for the extra null. In the case of ``str3``, we've explicitly included
+the null character (written ``'\0'``) ourselves.
+
+Note that it's possible to have a string without a final null
+character (e.g. if you had specified the length of ``str2`` as five
+instead of six). This will break most functions that use strings, so
+you shouldn't do it intentionally. If you notice something behaving
+strangely (operating on characters not in the string), however, this
+could be the problem.
+
+Single quotes or double quotes?
+-------------------------------
+
+Strings are always defined inside double quotes (``"Abc"``) and
+characters are always defined inside single quotes (``'A'``).
+
+Wrapping long strings
+---------------------
+
+You can wrap long strings like this::
+
+ char myString[] = "This is the first line"
+ " this is the second line"
+ " etcetera";
+
+Arrays of Strings
+-----------------
+
+It is often convenient, when working with large amounts of text,
+such as a project with an LCD display, to setup an array of
+strings. Because strings themselves are arrays, this is in actually
+an example of a two-dimensional array.
+
+In the code below, the asterisk after the datatype char ``char *``
+indicates that this is an array of "pointers". All array names are
+actually pointers, so this is required to make an array of arrays.
+Pointers are one of the more esoteric parts of C for beginners to
+understand, but it isn't necessary to understand pointers in detail to
+use them effectively here::
+
+ char* myStrings[] = {"This is string 1", "This is string 2",
+ "This is string 3", "This is string 4",
+ "This is string 5", "This is string 6"};
+
+ void setup() {
+ SerialUSB.begin();
+ }
+
+ void loop() {
+ for (int i = 0; i < 6; i++) {
+ SerialUSB.println(myStrings[i]);
+ delay(500);
+ }
+ }
+
+
+See Also
+--------
+
+- :ref:`array <lang-array>`
+- :ref:`__attribute__ <arm-gcc-attribute-flash>`
+- :ref:`Variables <lang-variables>`
+
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/switchcase.rst b/docs/source/lang/cpp/switchcase.rst
new file mode 100644
index 0000000..b484bc5
--- /dev/null
+++ b/docs/source/lang/cpp/switchcase.rst
@@ -0,0 +1,118 @@
+.. highlight:: cpp
+
+.. _lang-switchcase:
+
+``switch``\ /\ ``case``
+=======================
+
+Like :ref:`if <lang-if>` statements, A ``switch`` statement controls
+program flow by allowing you to specify different code that should be
+executed under various cases.
+
+The general syntax looks like this::
+
+ switch (var) {
+ case val1:
+ // statements
+ break;
+ case val2:
+ // statements
+ break;
+ ...
+ default:
+ // statements
+ }
+
+Where ``var`` is a variable whose value to investigate, and the
+``val1``, ``val2`` after each ``case`` are constant values that
+``var`` might be.
+
+Description
+-----------
+
+A ``switch`` statement compares the value of a variable to the values
+specified in ``case`` statements. When a ``case`` statement is found
+whose value matches that of the variable, the code in that case
+statement is run.
+
+Here's a more concrete example::
+
+ switch (var) {
+ case 1:
+ doThing1();
+ break;
+ case 2:
+ doThing2();
+ break;
+ }
+ afterTheSwitch();
+
+In the above example, if ``var == 1``, then the code beginning on the
+line after ``case 1`` gets executed. That is, if ``var`` is one,
+``doThing1()`` gets called first, and then the ``break`` statement is
+executed.
+
+The ``break`` keyword exits the ``switch`` statement, and is typically
+used at the end of each ``case``. Since there is a ``break`` at the
+end of ``case 1``, the ``switch`` statement exits, and the next line
+to be run is the one which calls ``afterTheSwitch()``.
+
+Without a ``break``, the ``switch`` statement will continue executing
+the following ``case`` expressions ("falling-through") until a
+``break`` (or the end of the switch statement) is reached. Let's
+pretend the ``switch`` looked like this instead::
+
+ switch (var) {
+ case 1:
+ doThing1();
+ // no break statement anymore
+ case 2:
+ doThing2();
+ break;
+ }
+ afterTheSwitch();
+
+Now, if ``var`` is one, ``doThing1()`` gets executed like before.
+However, without a ``break``, the code would continue to be executed
+line-by-line, so ``doThing2()`` would be called next. At this point,
+a ``break`` has been reached, so the program continues by calling
+``afterTheSwitch()``. This is usually not what you want, which is why
+each ``case`` usually has a ``break`` at the end.
+
+.. _lang-switchcase-default:
+
+Writing "``default:``" instead of a ``case`` statement allows you to
+specify what to do if none of the ``case`` statements matches. Having
+a ``default`` is optional (you can leave it out), but if you have one,
+it must appear after all of the ``case`` statements. Let's add a
+``default`` to the ``switch`` we've been discussing::
+
+ switch (var) {
+ case 1:
+ doThing1();
+ break;
+ case 2:
+ doThing2();
+ break;
+ default:
+ doSomethingElse();
+ }
+ afterTheSwitch();
+
+If ``var`` is one, then ``doThing1()`` gets called. If ``var`` is
+two, ``doThing2()`` gets called. If ``var`` is anything else,
+``doSomethingElse()`` gets called. As stated above, a ``default`` is
+optional. If you're missing one and none of the ``case`` statements
+match, the ``switch`` does nothing at all, as if it weren't there.
+
+``switch`` statements are often used with an :ref:`enum <lang-enum>`
+value as the variable to compare. In this case, you can write down
+all of the values the ``enum`` takes as ``case`` statements, and be
+sure you've covered all the possibilities.
+
+See also:
+---------
+
+- :ref:`if/else <lang-if>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/unsignedchar.rst b/docs/source/lang/cpp/unsignedchar.rst
new file mode 100644
index 0000000..5b946ed
--- /dev/null
+++ b/docs/source/lang/cpp/unsignedchar.rst
@@ -0,0 +1,33 @@
+.. highlight:: cpp
+
+.. _lang-unsignedchar:
+
+``unsigned char``
+=================
+
+An unsigned version of the :ref:`char <lang-char>` data type. An
+``unsigned char`` occupies 1 byte of memory; it stores an integer from
+0 to 255.
+
+Like an :ref:`unsigned int <lang-unsignedint>`, an ``unsigned char``
+won't store negative numbers; it is also subject to the same
+:ref:`overflow issues <lang-int-overflow>` as any integral data type.
+
+Example
+-------
+
+::
+
+ unsigned char c = 240;
+
+See Also
+--------
+
+
+- :ref:`byte <lang-byte>`
+- :ref:`int <lang-int>`
+- :ref:`array <lang-array>`
+- :ref:`SerialUSB.println() <lang-serialusb-println>`
+- :ref:`Serial.println() <lang-serial-println>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/unsignedint.rst b/docs/source/lang/cpp/unsignedint.rst
new file mode 100644
index 0000000..ad3e2f2
--- /dev/null
+++ b/docs/source/lang/cpp/unsignedint.rst
@@ -0,0 +1,59 @@
+.. highlight:: cpp
+
+.. _lang-unsignedint:
+
+``unsigned int``
+================
+
+An ``unsigned int`` (unsigned integer) is the same as an :ref:`int
+<lang-int>` in that it stores a 4 byte integer value. However,
+Instead of storing both negative and positive numbers, an ``unsigned
+int`` can only store nonnegative values, yielding a range of 0 to
+4,294,967,295 (the positive value is 2^32 - 1).
+
+The difference between an ``unsigned int`` and a (signed) ``int`` lies
+in the way the highest bit, sometimes referred to as the "sign" bit,
+is interpreted. In the case of the Maple ``int`` type (which is
+signed), if the high bit is a "1", the number is interpreted as a
+negative number, using a technique known as `two's complement math
+<http://en.wikipedia.org/wiki/Two%27s_complement#Explanation>`_. The
+bits in an an ``unsigned int`` are interpreted according to the usual
+rules for converting `binary to decimal
+<http://en.wikipedia.org/wiki/Binary_numeral_system#Counting_in_binary>`_.
+
+An ``unsigned int`` is subject to the same :ref:`overflow issues
+<lang-int-overflow>` as a regular ``int``; the only difference is
+that an ``unsigned int`` will "underflow" at 0, and "overflow" at
+4,294,967,295. Here is some example code which illustrates this::
+
+ unsigned int x;
+ x = 0;
+ x--; // x now contains 4,294,967,295; rolled over "left to right"
+ x++; // x now contains 0; rolled over "right to left"
+
+.. _lang-unsignedlong:
+
+The ``unsigned long`` type is a synonym for ``unsigned int``.
+
+Here is an example of declaring an ``unsigned int`` variable named
+``ledPin``, then giving it value 13::
+
+ unsigned int ledPin = 13;
+
+The general syntax for declaring an ``unsigned int`` variable named
+``var``, then giving it value ``val``, looks like::
+
+ unsigned int var = val;
+
+See Also
+--------
+
+- :ref:`int <lang-int>`
+- :ref:`char <lang-char>`
+- :ref:`unsigned char <lang-unsignedchar>`
+- :ref:`long long <lang-longlong>`
+- :ref:`unsigned long long <lang-unsignedlonglong>`
+- :ref:`Integer Constants <lang-constants-integers>`
+- :ref:`Variables <lang-variables>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/unsignedlonglong.rst b/docs/source/lang/cpp/unsignedlonglong.rst
new file mode 100644
index 0000000..910b7e4
--- /dev/null
+++ b/docs/source/lang/cpp/unsignedlonglong.rst
@@ -0,0 +1,43 @@
+.. highlight:: cpp
+
+.. _lang-unsignedlonglong:
+
+``unsigned long long``
+======================
+
+An unsigned version of the :ref:`long long <lang-longlong>` data type.
+An ``unsigned long long`` occupies 8 bytes of memory; it stores an
+integer from 0 to 2^64-1, which is approximately 1.8×10^19 (18
+quintillion, or 18 billion billion).
+
+A synonym for the ``unsigned long long`` type is ``uint64``.
+
+Like an :ref:`unsigned int <lang-unsignedint>`, an ``unsigned long
+long`` won't store negative numbers; it is also subject to the same
+:ref:`overflow issues <lang-int-overflow>` as any integral data type.
+
+Here is an example of declaring an ``unsigned long long`` variable
+named ``c``, then giving it value 299,792,458,000,000,000 (see
+:ref:`integer constants <lang-constants-integers-u-l>` for an
+explanation of the "ULL" at the end of the number)::
+
+ // Speed of light in nanometers per second (approximate).
+ unsigned long long c = 299792458000000000ULL;
+
+The general syntax for declaring an ``unsigned long long`` variable named
+``var``, then giving it value ``val``, looks like::
+
+ unsigned long long var = val;
+
+See Also
+--------
+
+- :ref:`long long <lang-longlong>`
+- :ref:`int <lang-int>`
+- :ref:`unsigned <lang-unsignedint>`
+- :ref:`char <lang-char>`
+- :ref:`unsigned char <lang-unsignedchar>`
+- :ref:`Integer Constants <lang-constants-integers>`
+- :ref:`Variables <lang-variables>`
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/variables.rst b/docs/source/lang/cpp/variables.rst
new file mode 100644
index 0000000..336d5ab
--- /dev/null
+++ b/docs/source/lang/cpp/variables.rst
@@ -0,0 +1,170 @@
+.. highlight:: cpp
+
+.. _lang-variables:
+
+Variables
+=========
+
+A variable is a way of naming and storing a value for later use by
+the program, such as data from a sensor or an intermediate value
+used in a calculation.
+
+.. contents:: Contents
+ :local:
+
+.. _lang-variables-declaring:
+
+Declaring Variables
+-------------------
+
+Before they are used, all variables have to be *declared*. Declaring a
+variable means defining its type, giving it a name, and (optionally)
+giving it an initial value (this is often referred to as
+*initializing* the variable). Variables do not have to be initialized
+(given a value) when they are declared, but it is good style to give
+them an initial value whenever possible.
+
+Here is an example of declaring a variable named ``inputVariable1``
+with type :ref:`int <lang-int>` (the ``int`` type is used to store
+integers, like -2, -1, 0, 1, etc.)::
+
+ int inputVariable1;
+
+In the above declaration, we did not give the variable an initial
+value. Here is another example, where we declare an ``int`` variable
+named ``inputVariable2``, with an initial value of ``0``::
+
+ int inputVariable2 = 0;
+
+The Maple environment comes ready to use with many useful types of
+variables. See the :ref:`built-in types <lang-built-in-types>` page
+for more information.
+
+Here are a few examples of declaring variables of different types::
+
+ int lightSensVal;
+ char currentLetter;
+ unsigned long long speedOfLight = 186000ULL;
+ char errorMessage = {"choose another option"}; // see string
+
+Naming Variables
+----------------
+
+The rules for naming a variable are simple. Names for variables can
+contain letters, numbers, and underscores (the underscore is the
+:kbd:`_` character), and cannot begin with a number. So
+``temperature_reading``, ``tempReading``, ``tempReading1``, and
+``tempReading2`` are all valid variable names, but ``4_temp_readings``
+is not, because it begins with a number.
+
+You cannot choose a name for a variable that is one of the C++
+:ref:`keywords <lang-keywords>`.
+
+Variable names are case-sensitive, so "tempreading" and "tempReading"
+are different variables. However, it is very bad style to write code
+that chooses variables which are the same up to case.
+
+You should give your variables descriptive names, so as to make your
+code more readable. Variable names like ``tiltSensor`` or
+``pushButton`` help you (and anyone else reading your code) understand
+what the variable represents. Variable names like ``var`` or
+``value``, on the other hand, do little to make your code readable.
+
+.. _lang-variables-scope:
+
+Variable Scope
+--------------
+
+An important choice that programmers face is where (in the program
+text) to declare variables. The specific place that variables are
+declared influences how various functions in a program will "see" the
+variable. This is called variable *scope*. See the :ref:`scope
+reference <lang-scope>` for more information.
+
+.. _lang-variables-initializing:
+
+Initializing Variables
+----------------------
+
+Variables may be *initialized* (assigned a starting value) when they
+are declared or not. It is always good programming practice however to
+double check that a variable has valid data in it before it is used.
+Using a variable before you give it a value is a common source of
+bugs.
+
+.. _lang-variables-rollover:
+
+Variable Rollover
+-----------------
+
+Every (numeric) type has a valid *range*. The range of a type is the
+smallest and largest value that a variable of that type can store.
+For example, the :ref:`int <lang-int>` type has a range of
+-2,147,483,648 to 2,147,483,647 [#frange]_.
+
+When variables are made to exceed their range's maximum value, they
+"roll over" back to their minimum value. Note that this happens in
+both directions. It's like in the game *Pac-Man* -- when Pac-Man goes
+past the right edge of the screen, he reappears on the left, and when
+he goes past the left side of the screen, he reappears on the right::
+
+ int x;
+ x = -2,147,483,648;
+ x = x - 1; // x now contains -2,147,483,647; rolled over "left to right"
+
+ x = 2,147,483,647;
+ x = x + 1; // x now contains -2,147,483,648; rolled over "right to left"
+
+Each numeric type's reference page includes its range. See the
+:ref:`built-in types <lang-built-in-types>` reference for links to each
+type's reference page.
+
+Using Variables
+---------------
+
+Once variables have been declared, they are given values using the
+:ref:`assignment operator <lang-assignment>`, which is a single equals
+sign, ``=``. The assignment operator tells the program to store the
+value on the right side of the equals sign into the variable on the
+left side::
+
+ inputVariable1 = 7; // sets variable named inputVariable1 to 7
+ inputVariable2 = analogRead(2); // sets variable named inputVariable2 to
+ // the (digitized) input voltage read from
+ // analog pin #2
+
+Once a variable has been set (assigned a value), you can test its
+value to see if it meets certain conditions, or you can use its value
+directly. For instance, the following code tests whether the
+inputVariable2 is less than 100, then sets a delay based on
+inputVariable2 (which, at that point, is at least 100)::
+
+ if (inputVariable2 < 100) {
+ inputVariable2 = 100;
+ }
+
+ delay(inputVariable2);
+
+See Also
+--------
+
+- :ref:`lang-scope`
+- :ref:`lang-built-in-types`
+
+.. rubric:: Footnotes
+
+.. [#frange] This range might seem a little weird at first. The
+ reasons for this range of values have to do with the fact that an
+ ``int`` occupies 32 bits of memory, and the facts ::
+
+ 2^31 = -2,147,483,648
+ 2^31 - 1 = 2,147,483,647
+
+
+ Why 2^31 instead of 2^32? Well, that has to do with `how ints are
+ (usually) stored
+ <http://en.wikipedia.org/wiki/Two%27s_complement>`_ on computers.
+
+
+.. include:: cc-attribution.txt
+
diff --git a/docs/source/lang/cpp/void.rst b/docs/source/lang/cpp/void.rst
new file mode 100644
index 0000000..88c9c64
--- /dev/null
+++ b/docs/source/lang/cpp/void.rst
@@ -0,0 +1,33 @@
+.. highlight:: cpp
+
+.. _lang-void:
+
+``void``
+========
+
+.. cpp:type:: void
+
+ The ``void`` keyword is used in function declarations. It indicates
+ that the function is expected to return no information to the
+ function from which it was called, or that it expects no arguments
+ from its caller.
+
+Example
+-------
+
+::
+
+ // actions are performed in the functions "setup" and "loop"
+ // but no information is reported to the larger program
+
+ void setup() {
+ // ...
+ }
+
+ void loop() {
+ // ...
+ }
+
+.. TODO doc page on function declaration?
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/cpp/while.rst b/docs/source/lang/cpp/while.rst
new file mode 100644
index 0000000..9047d05
--- /dev/null
+++ b/docs/source/lang/cpp/while.rst
@@ -0,0 +1,38 @@
+.. highlight:: cpp
+
+.. _lang-while:
+
+``while``
+=========
+
+Syntax
+------
+
+::
+
+ while (expression) {
+ // block of code
+ }
+
+Description
+-----------
+
+``while`` loops will repeat the statements inside their associated
+block of code until the expression inside the parentheses becomes
+:ref:`false <lang-constants-false>`. Something must change the tested
+expressions' value, or the ``while`` loop will never exit. This could
+be in your code, such as an incremented variable, or an external
+condition, such as testing a sensor.
+
+Example
+-------
+
+::
+
+ var = 0;
+ while(var < 200) {
+ // do something repetitive 200 times
+ var++;
+ }
+
+.. include:: cc-attribution.txt
diff --git a/docs/source/lang/unimplemented/notone.rst b/docs/source/lang/unimplemented/notone.rst
new file mode 100644
index 0000000..485c9c5
--- /dev/null
+++ b/docs/source/lang/unimplemented/notone.rst
@@ -0,0 +1,50 @@
+.. _lang-notone:
+
+noTone()
+========
+
+Description
+-----------
+
+Stops the generation of a square wave triggered by
+`tone <http://arduino.cc/en/Reference/Tone>`_\ (). Has no effect if
+no tone is being generated.
+
+
+
+**NOTE:** if you want to play different pitches on multiple pins,
+you need to call noTone() on one pin before calling tone() on the
+next pin.
+
+
+
+Syntax
+------
+
+noTone(pin)
+
+
+
+Parameters
+----------
+
+pin: the pin on which to stop generating the tone
+
+
+
+Returns
+-------
+
+nothing
+
+
+
+See also
+--------
+
+
+- `tone <http://arduino.cc/en/Reference/Tone>`_ ()
+
+
+
+.. include:: /lang/cc-attribution.txt
diff --git a/docs/source/lang/unimplemented/pulsein.rst b/docs/source/lang/unimplemented/pulsein.rst
new file mode 100644
index 0000000..2b52428
--- /dev/null
+++ b/docs/source/lang/unimplemented/pulsein.rst
@@ -0,0 +1,82 @@
+.. _lang-pulsein:
+
+pulseIn()
+=========
+
+Description
+-----------
+
+Reads a pulse (either HIGH or LOW) on a pin. For example, if
+**value** is **HIGH**, **pulseIn()** waits for the pin to go
+**HIGH**, starts timing, then waits for the pin to go **LOW** and
+stops timing. Returns the length of the pulse in microseconds.
+Gives up and returns 0 if no pulse starts within a specified time
+out.
+
+
+
+The timing of this function has been determined empirically and
+will probably show errors in longer pulses. Works on pulses from 10
+microseconds to 3 minutes in length.
+
+
+
+Syntax
+------
+
+pulseIn(pin, value)
+pulseIn(pin, value, timeout)
+
+
+
+Parameters
+----------
+
+pin: the number of the pin on which you want to read the pulse.
+(*int*)
+
+
+
+value: type of pulse to read: either
+`HIGH <http://arduino.cc/en/Reference/Constants>`_ or
+`LOW <http://arduino.cc/en/Reference/Constants>`_. (*int*)
+
+
+
+timeout (optional): the number of microseconds to wait for the
+pulse to start; default is one second (*unsigned long*)
+
+
+
+Returns
+-------
+
+the length of the pulse (in microseconds) or 0 if no pulse started
+before the timeout (*unsigned long*)
+
+
+
+Example
+-------
+
+::
+
+
+
+ int pin = 7;
+ unsigned long duration;
+
+ void setup()
+ {
+ pinMode(pin, INPUT);
+ }
+
+ void loop()
+ {
+ duration = pulseIn(pin, HIGH);
+ }
+
+
+
+
+.. include:: /lang/cc-attribution.txt
diff --git a/docs/source/lang/unimplemented/shiftout.rst b/docs/source/lang/unimplemented/shiftout.rst
new file mode 100644
index 0000000..ff3852f
--- /dev/null
+++ b/docs/source/lang/unimplemented/shiftout.rst
@@ -0,0 +1,136 @@
+.. _lang-shiftout:
+
+shiftOut()
+==========
+
+Description
+-----------
+
+Shifts out a byte of data one bit at a time. Starts from either the
+most (i.e. the leftmost) or least (rightmost) significant bit. Each
+bit is written in turn to a data pin, after which a clock pin is
+pulsed to indicate that the bit is available.
+
+
+
+This is a software implementation; Arduino (as of 0019) also
+provides an `SPI library <http://arduino.cc/en/Reference/SPI>`_
+that uses the hardware implementation.
+
+
+
+Syntax
+------
+
+shiftOut(dataPin, clockPin, bitOrder, value)
+
+
+
+Parameters
+----------
+
+dataPin: the pin on which to output each bit (*int*)
+
+
+
+clockPin: the pin to toggle once the **dataPin** has been set to
+the correct value (*int*)
+
+
+
+bitOrder: which order to shift out the bits; either **MSBFIRST** or
+**LSBFIRST**.
+(Most Significant Bit First, or, Least Significant Bit First)
+
+
+
+value: the data to shift out. (*byte*)
+
+
+
+Returns
+-------
+
+None
+
+
+
+Note
+----
+
+The **dataPin** and **clockPin** must already be configured as
+outputs by a call to
+`pinMode <http://arduino.cc/en/Reference/PinMode>`_\ ().
+
+
+
+**shiftOut** is currently written to output 1 byte (8 bits) so it
+requires a two step operation to output values larger than 255.
+
+::
+
+ // Do this for MSBFIRST serial
+ int data = 500;
+ // shift out highbyte
+ shiftOut(dataPin, clock, MSBFIRST, (data >> 8));
+ // shift out lowbyte
+ shiftOut(data, clock, MSBFIRST, data);
+
+ // Or do this for LSBFIRST serial
+ data = 500;
+ // shift out lowbyte
+ shiftOut(dataPin, clock, LSBFIRST, data);
+ // shift out highbyte
+ shiftOut(dataPin, clock, LSBFIRST, (data >> 8));
+
+
+
+Example
+-------
+
+*For accompanying circuit, see the `tutorial on controlling a 74HC595 shift register <http://arduino.cc/en/Tutorial/ShiftOut>`_.*
+
+
+
+::
+
+ //**************************************************************//
+ // Name : shiftOutCode, Hello World //
+ // Author : Carlyn Maw,Tom Igoe //
+ // Date : 25 Oct, 2006 //
+ // Version : 1.0 //
+ // Notes : Code for using a 74HC595 Shift Register //
+ // : to count from 0 to 255 //
+ //****************************************************************
+
+ //Pin connected to ST_CP of 74HC595
+ int latchPin = 8;
+ //Pin connected to SH_CP of 74HC595
+ int clockPin = 12;
+ ////Pin connected to DS of 74HC595
+ int dataPin = 11;
+
+ void setup() {
+ //set pins to output because they are addressed in the main loop
+ pinMode(latchPin, OUTPUT);
+ pinMode(clockPin, OUTPUT);
+ pinMode(dataPin, OUTPUT);
+ }
+
+ void loop() {
+ //count up routine
+ for (int j = 0; j < 256; j++) {
+ //ground latchPin and hold low for as long as you are transmitting
+ digitalWrite(latchPin, LOW);
+ shiftOut(dataPin, clockPin, LSBFIRST, j);
+ //return the latch pin high to signal chip that it
+ //no longer needs to listen for information
+ digitalWrite(latchPin, HIGH);
+ delay(1000);
+ }
+ }
+
+
+
+
+.. include:: /lang/cc-attribution.txt
diff --git a/docs/source/lang/unimplemented/stringclass.rst b/docs/source/lang/unimplemented/stringclass.rst
new file mode 100644
index 0000000..b893e83
--- /dev/null
+++ b/docs/source/lang/unimplemented/stringclass.rst
@@ -0,0 +1,6 @@
+.. _lang-stringclass:
+
+String Class
+============
+
+.. include:: /lang/cc-attribution.txt
diff --git a/docs/source/lang/unimplemented/stringobject.rst b/docs/source/lang/unimplemented/stringobject.rst
new file mode 100644
index 0000000..e47ed7e
--- /dev/null
+++ b/docs/source/lang/unimplemented/stringobject.rst
@@ -0,0 +1,89 @@
+.. _lang-stringobject:
+
+String
+======
+
+Description
+-----------
+
+The String class, part of the core as of version 0019, allows you to
+use and manipulate strings of text in more complex ways than character
+arrays do. You can concatenate Strings, append to them, search for and
+replace substrings, and more. It takes more memory than a simple
+character array, but it is also more useful.
+
+
+
+For reference, character arrays are referred to as strings with a
+small s, and instances of the String class are referred to as
+Strings with a capital S. Note that constant strings, specified in
+"double quotes" are treated as char arrays, not instances of the
+String class.
+
+
+
+Functions
+---------
+
+
+- `String <http://arduino.cc/en/Reference/StringConstructor>`_\ ()
+- `charAt <http://arduino.cc/en/Reference/StringCharAt>`_\ ()
+- `compareTo <http://arduino.cc/en/Reference/StringCompareTo>`_\ ()
+- `concat <http://arduino.cc/en/Reference/StringConcat>`_\ ()
+- `endsWith <http://arduino.cc/en/Reference/StringEndsWith>`_\ ()
+- `equals <http://arduino.cc/en/Reference/StringEquals>`_\ ()
+- `equalsIgnoreCase <http://arduino.cc/en/Reference/StringEqualsIgnoreCase>`_\ ()
+- `getBytes <http://arduino.cc/en/Reference/StringGetBytes>`_\ ()
+- `indexOf <http://arduino.cc/en/Reference/StringIndexOf>`_\ ()
+- `lastIndexOf <http://arduino.cc/en/Reference/StringLastIndexOf>`_\ ()
+- `length <http://arduino.cc/en/Reference/StringLength>`_\ ()
+- `replace <http://arduino.cc/en/Reference/StringReplace>`_\ ()
+- `setCharAt <http://arduino.cc/en/Reference/StringSetCharAt>`_\ ()
+- `startsWith <http://arduino.cc/en/Reference/StringStartsWith>`_\ ()
+- `substring <http://arduino.cc/en/Reference/StringSubstring>`_\ ()
+- `toCharArray <http://arduino.cc/en/Reference/StringToCharArray>`_\ ()
+- `toLowerCase <http://arduino.cc/en/Reference/StringToLowerCase>`_\ ()
+- `toUpperCase <http://arduino.cc/en/Reference/StringToUpperCase>`_\ ()
+- `trim <http://arduino.cc/en/Reference/StringTrim>`_\ ()
+
+
+
+Operators
+---------
+
+
+- `[] (element access) <http://arduino.cc/en/Reference/StringBrackets>`_
+- `+ (concatenation) <http://arduino.cc/en/Reference/StringPlus>`_
+- `== (comparison) <http://arduino.cc/en/Reference/StringComparison>`_
+
+
+
+Examples
+--------
+
+
+- `StringConstructors <http://arduino.cc/en/Tutorial/StringConstructors>`_
+- `StringAdditionOperator <http://arduino.cc/en/Tutorial/StringAdditionOperator>`_
+- `StringIndexOf <http://arduino.cc/en/Tutorial/StringIndexOf>`_
+- `StringAppendOperator <http://arduino.cc/en/Tutorial/StringAppendOperator>`_
+- `StringLengthTrim <http://arduino.cc/en/Tutorial/StringLengthTrim>`_
+- `StringCaseChanges <http://arduino.cc/en/Tutorial/StringCaseChanges>`_
+- `StringReplace <http://arduino.cc/en/Tutorial/StringReplace>`_
+- `StringCharacters <http://arduino.cc/en/Tutorial/StringCharacters>`_
+- `StringStartsWithEndsWith <http://arduino.cc/en/Tutorial/StringStartsWithEndsWith>`_
+- `StringComparisonOperators <http://arduino.cc/en/Tutorial/StringComparisonOperators>`_
+- `StringSubstring <http://arduino.cc/en/Tutorial/StringSubstring>`_
+
+
+
+See Also
+--------
+
+
+- `Character array strings <http://arduino.cc/en/Reference/String>`_
+- `Variable Declaration <http://arduino.cc/en/Reference/VariableDeclaration>`_
+
+
+
+
+.. include:: /lang/cc-attribution.txt
diff --git a/docs/source/lang/unimplemented/tone.rst b/docs/source/lang/unimplemented/tone.rst
new file mode 100644
index 0000000..f83bf6b
--- /dev/null
+++ b/docs/source/lang/unimplemented/tone.rst
@@ -0,0 +1,81 @@
+.. _lang-tone:
+
+tone()
+======
+
+Description
+-----------
+
+Generates a square wave of the specified frequency (and 50% duty
+cycle) on a pin. A duration can be specified, otherwise the wave
+continues until a call to
+`noTone <http://arduino.cc/en/Reference/NoTone>`_\ (). The pin can be
+connected to a piezo buzzer or other speaker to play tones.
+
+
+
+Only one tone can be generated at a time. If a tone is already
+playing on a different pin, the call to tone() will have no effect.
+If the tone is playing on the same pin, the call will set its
+frequency.
+
+
+
+Use of the tone() function will interfere with PWM output on pins 3
+and 11 (on boards other than the Mega).
+
+
+
+**NOTE:** if you want to play different pitches on multiple pins,
+you need to call noTone() on one pin before calling tone() on the
+next pin.
+
+
+
+Syntax
+------
+
+tone(pin, frequency)
+tone(pin, frequency, duration)
+
+
+
+Parameters
+----------
+
+pin: the pin on which to generate the tone
+
+
+
+frequency: the frequency of the tone in hertz
+
+
+
+duration: the duration of the tone in milliseconds (optional)
+
+
+
+Returns
+-------
+
+nothing
+
+
+
+See also
+--------
+
+
+- `noTone <http://arduino.cc/en/Reference/NoTone>`_\ ()
+- `analogWrite <http://arduino.cc/en/Reference/AnalogWrite>`_\ ()
+- `Tutorial:Tone <http://arduino.cc/en/Tutorial/Tone>`_
+- `Tutorial:Pitch follower <http://arduino.cc/en/Tutorial/Tone2>`_
+- `Tutorial:Simple Keyboard <http://arduino.cc/en/Tutorial/Tone3>`_
+- `Tutorial: multiple tones <http://arduino.cc/en/Tutorial/Tone4>`_
+
+
+- `Tutorial: PWM <http://arduino.cc/en/Tutorial/PWM>`_
+
+
+
+.. include:: /lang/cc-attribution.txt
diff --git a/docs/source/language-index.rst b/docs/source/language-index.rst
new file mode 100644
index 0000000..e160e2b
--- /dev/null
+++ b/docs/source/language-index.rst
@@ -0,0 +1,40 @@
+.. _language-index:
+
+=======================
+Complete Language Index
+=======================
+
+This is the index of Maple's :ref:`language reference
+<language-lang-docs>` documentation. The "Maple API" column provides
+API references for documented libmaple functionality. The "C++ for
+Maple".. pages are adaptations of the Arduino C++ documentation to the
+.. Maple, and are intended as a minimal reference/refresher for
+.. programmers familiar with the Arduino language.
+
+.. _index-language-index-cpp:
+.. _index-language-index-api:
+
++----------------------------------+------------------------------------+
+| Maple API | C++ for Maple |
+| | |
++==================================+====================================+
+| | |
+| .. toctree:: | .. toctree:: |
+| :maxdepth: 1 | :maxdepth: 1 |
+| :glob: | :glob: |
+| | |
+| lang/api/* | lang/cpp/* |
+| | |
++----------------------------------+------------------------------------+
+
+.. Unimplemented in libmaple or not part of current release:
+
+.. toctree::
+ :hidden:
+
+ lang/unimplemented/notone.rst
+ lang/unimplemented/pulsein.rst
+ lang/unimplemented/shiftout.rst
+ lang/unimplemented/stringclass.rst
+ lang/unimplemented/stringobject.rst
+ lang/unimplemented/tone.rst
diff --git a/docs/source/language.rst b/docs/source/language.rst
new file mode 100644
index 0000000..2ebe03c
--- /dev/null
+++ b/docs/source/language.rst
@@ -0,0 +1,444 @@
+.. highlight:: c++
+
+.. _language:
+
+==========================
+ Maple Language Reference
+==========================
+
+The Maple can be programmed in the `Wiring
+<http://www.wiring.org.co/reference/>`_ language, which is the same
+language used to program the `Arduino <http://arduino.cc/>`_ boards.
+
+C or C++ programmers curious about the differences between the Wiring
+language and C++ may wish to skip to the
+:ref:`arduino_c_for_c_hackers`.
+
+.. contents:: Contents
+ :local:
+
+Unique Maple Additions
+----------------------
+
+.. _language-assert:
+
+``ASSERT(...)``
+ The ``ASSERT()`` function can be very useful for basic program
+ debugging. The function accepts a boolean; for example::
+
+ ASSERT(state == WAIT);
+
+ zero is false and any other number is true. If the boolean is true
+ the assertion passes and the program continues as usual. If it is
+ false, the assertion fails: the program is halted, debug
+ information is printed to USART2, and the status LED begins to
+ throb in intensity (it's noticeably different from blinking). The
+ debug information is printed at 9600 baud and consists of the
+ filename and line number where the particular assertion failed.
+
+ Including assertions in a program increases the program size. When
+ using libmaple **from the command line only**, they can be
+ disabled by making the definition ::
+
+ #define DEBUG_LEVEL DEBUG_NONE
+
+ before including either wirish.h or libmaple.h. In this case, all
+ assertions will pass without any lost clock cycles. Note that
+ this will **not work in the IDE**; even with this definition,
+ assertions will still be enabled.
+
+.. _language-lang-docs:
+
+Maple Language Reference
+------------------------
+
+The following table summarizes the available core language features.
+A more exhaustive index is available at the :ref:`language-index`.
+
++--------------------------------------------+----------------------------------------------+---------------------------------------------------+
+| Structure | Variables | Functions |
+| | | |
++============================================+==============================================+===================================================+
+|* :ref:`setup() <lang-setup>` |**Constants** |**Digital I/O** |
+| | | |
+|* :ref:`loop() <lang-loop>` |* :ref:`HIGH <lang-constants-high>` | |* :ref:`pinMode() <lang-pinmode>` |
+| | :ref:`LOW <lang-constants-low>` | |
+| | |* :ref:`digitalWrite() <lang-digitalwrite>` |
+|**Control Structures** |* :ref:`INPUT <lang-constants-input>` | | |
+| | :ref:`OUTPUT <lang-constants-output>` |* :ref:`digitalRead() <lang-digitalread>` |
+|* :ref:`if/else <lang-if>` | | |
+| |* :ref:`true <lang-constants-true>` | |* :ref:`togglePin() <lang-togglepin>` |
+|* :ref:`for <lang-for>` | :ref:`false <lang-constants-false>` | |
+| | |* :ref:`toggleLED() <lang-toggleled>` |
+|* :ref:`switch/case <lang-switchcase>` |* :ref:`BOARD_LED_PIN <lang-constants-led>` | | |
+| | :ref:`BOARD_BUTTON_PIN <lang-constants-but>`|* :ref:`isButtonPressed() <lang-isbuttonpressed>` |
+|* :ref:`while <lang-while>` | | |
+| |* :ref:`Constants |* :ref:`waitForButtonPress() |
+|* :ref:`do...while <lang-dowhile>` | <lang-constants>` (:ref:`integers | <lang-waitforbuttonpress>` |
+| | <lang-constants-integers>`, :ref:`floating | |
+|* :ref:`break <lang-break>` | point <lang-constants-fp>`) |**Analog I/O** |
+| | | |
+|* :ref:`continue <lang-continue>` |**Data Types** |* :ref:`analogRead() <lang-analogread>` |
+| | | |
+|* :ref:`return <lang-return>` | The size of each datatype, in bytes, is |* :ref:`pwmWrite() <lang-pwmwrite>` |
+| | given in parentheses where appropriate. | (:ref:`analogWrite() <lang-analogwrite>` is |
+|* :ref:`goto <lang-goto>` | | also available, though its use is discouraged) |
+| | *Note*: The ``word`` type is (deliberately) | |
+| | :ref:`not supported <language-no-word>`. | |
+|**Further syntax** | |**Advanced I/O** |
+| |* :ref:`void <lang-void>` | |
+|* :ref:`; (semicolon) <lang-semicolon>` | |* tone(): TODO |
+| |* :ref:`boolean <lang-boolean>` (1 byte) | |
+|* :ref:`{} (curly braces) | |* noTone(): TODO |
+| <lang-curly-braces>` |* :ref:`char <lang-char>` (1 byte) | |
+| | |* shiftOut(): TODO |
+|* :ref:`// (single-line comment) |* :ref:`unsigned char | |
+| <lang-comments-singleline>` | <lang-unsignedchar>` (1 byte) |* pulseIn(): TODO |
+| | | |
+|* :ref:`/\* \*/ (multi-line comment) |* :ref:`byte <lang-byte>` (1 byte) | |
+| <lang-comments-multiline>` | |**Time** |
+| |* :ref:`int <lang-int>` (4 bytes) | |
+|* :ref:`#define <lang-define>` | |* :ref:`millis() <lang-millis>` |
+| |* :ref:`unsigned int <lang-unsignedint>` | |
+|* :ref:`#include <lang-include>` | (4 bytes) |* :ref:`micros() <lang-micros>` |
+| | | |
+| |* ``long`` (4 bytes), synonym for :ref:`int |* :ref:`delay() <lang-delay>` |
+|**Arithmetic Operators** | <lang-int>` | |
+| | |* :ref:`delayMicroseconds() |
+|* :ref:`= <lang-assignment>` |* ``unsigned long`` (4 bytes), synonym for | <lang-delaymicroseconds>` |
+| (assignment operator) | :ref:`unsigned int <lang-unsignedint>` | |
+| | | |
+|* :ref:`+ <lang-arithmetic>` (addition) |* :ref:`long long <lang-longlong>` (8 bytes) |**Math** |
+| | | |
+|* :ref:`- <lang-arithmetic>` |* :ref:`unsigned long |* :ref:`min() <lang-min>` |
+| (subtraction) | long <lang-unsignedlonglong>` (8 bytes) | |
+| | |* :ref:`max() <lang-max>` |
+|* :ref:`* <lang-arithmetic>` |* :ref:`float <lang-float>` (4 bytes) | |
+| (multiplication) | |* :ref:`abs() <lang-abs>` |
+| |* :ref:`double <lang-double>` (8 bytes) | |
+|* :ref:`/ <lang-arithmetic>` (division) | |* :ref:`constrain() <lang-constrain>` |
+| |* :ref:`strings <lang-string>` | |
+|* :ref:`% <lang-modulo>` (modulo) | |* :ref:`map() <lang-map>` |
+| |* :ref:`arrays <lang-array>` | |
+| | |* :ref:`pow() <lang-pow>` |
+|**Comparison Operators** |* :ref:`enum <lang-enum>` | |
+| | |* :ref:`sqrt() <lang-sqrt>` |
+|* :ref:`== <lang-comparison>` (equal to) |* :ref:`numeric types <lang-built-in-types>` | |
+| | | |
+|* :ref:`\!= <lang-comparison>` |**Conversion** |**Trigonometry** |
+| (not equal to) | | |
+| |* :ref:`char() <lang-charcast>` |* :ref:`sin() <lang-sin>` |
+|* :ref:`< <lang-comparison>` (less than) | | |
+| |* :ref:`byte() <lang-bytecast>` |* :ref:`cos() <lang-cos>` |
+|* :ref:`> <lang-comparison>` | | |
+| (greater than) |* :ref:`int() <lang-intcast>` |* :ref:`tan() <lang-tan>` |
+| | | |
+|* :ref:`<= <lang-comparison>` |* :ref:`long() <lang-longcast>` | |
+| (less than or equal to) | |**Random Numbers** |
+| |* :ref:`float() <lang-floatcast>` | |
+|* :ref:`>= <lang-comparison>` | |* :ref:`randomSeed() <lang-randomseed>` |
+| (greater than or equal to) |* :ref:`double() <lang-doublecast>` | |
+| | |* :ref:`random() <lang-random>` |
+| | | |
+|**Boolean Operators** |**Variable Scope & Qualifiers** | |
+| | |**Bits and Bytes** |
+|* :ref:`&& <lang-boolean-and>` (and) |* :ref:`variables <lang-variables>`, | |
+| | :ref:`scope <lang-variables-scope>` |* :ref:`lowByte() <lang-lowbyte>` |
+|* :ref:`|| <lang-boolean-or>` (or) | | |
+| |* :ref:`static <lang-static>` |* :ref:`highByte() <lang-highbyte>` is |
+|* :ref:`\! <lang-boolean-not>` (not) | | provided, though its use is discouraged. |
+| |* :ref:`volatile <lang-volatile>` | |
+| | |* :ref:`bitRead() <lang-bitread>` |
+|**Pointer Operators** |* :ref:`const <lang-const>` | |
+| | |* :ref:`bitWrite() <lang-bitwrite>` |
+|* :ref:`* dereference operator | | |
+| <lang-pointer>` |**Utilities** |* :ref:`bitSet() <lang-bitset>` |
+| | | |
+|* :ref:`& reference operator |* :ref:`sizeof() <lang-sizeof>` |* :ref:`bitClear() <lang-bitclear>` |
+| <lang-pointer>` | | |
+| | |* :ref:`bit() <lang-bit>` |
+| | | |
+|**Bitwise Operators** | | |
+| | |**External Interrupts** |
+|* :ref:`& <lang-bitwisemath-and>` | | |
+| (bitwise and) | |* :ref:`Reference Page <external-interrupts>` |
+| | | |
+|* :ref:`| <lang-bitwisemath-or>` | |* :ref:`attachInterrupt() |
+| (bitwise or) | | <lang-attachinterrupt>` |
+| | | |
+|* :ref:`^ <lang-bitwisemath-xor>` | |* :ref:`detachInterrupt() |
+| (bitwise xor) | | <lang-detachinterrupt>` |
+| | | |
+|* :ref:`~ <lang-bitwisemath-not>` | | |
+| (bitwise not) | |**Interrupts** |
+| | | |
+|* :ref:`\<\< <lang-bitshift>` | |* :ref:`interrupts() <lang-interrupts>` |
+| (shift left) | | |
+| | |* :ref:`noInterrupts() <lang-nointerrupts>` |
+|* :ref:`>> <lang-bitshift>` | | |
+| (shift right) | | |
+| | |**Communication** |
+| | | |
+|**Compound Operators** | |* :ref:`SerialUSB <lang-serialusb>` |
+| | | |
+|* :ref:`++ <lang-increment>` | |* :ref:`Serial <lang-serial>` |
+| (increment) | | |
+| | |**Looking for something else?** |
+|* :ref:`- - <lang-increment>` | | |
+| (decrement) | | See the :ref:`libraries` page for interfacing with|
+| | | particular types of hardware. Maple links |
+|* :ref:`+= <lang-compoundarithmetic>` | | against `newlib <http://sourceware.org/newlib/>`_ |
+| (compound add) | | and allows the use of any of its functions; see |
+| | | its documentation for more details. |
+|* :ref:`-= | | |
+| <lang-compoundarithmetic>` (compound | | |
+| subtract) | | |
+| | | |
+|* :ref:`*= | | |
+| <lang-compoundarithmetic>` (compound | | |
+| multiply) | | |
+| | | |
+|* :ref:`/= | | |
+| <lang-compoundarithmetic>` (compound | | |
+| divide) | | |
+| | | |
+|* :ref:`&= | | |
+| <lang-compoundbitwise>` (compound | | |
+| bitwise and) | | |
+| | | |
+|* :ref:`|= | | |
+| <lang-compoundbitwise>` (compound | | |
+| bitwise or) | | |
+| | | |
+|**Keywords** | | |
+| | | |
+|* :ref:`C++ Keywords <lang-keywords>` | | |
+| | | |
+| | | |
++--------------------------------------------+----------------------------------------------+---------------------------------------------------+
+
+.. _language-missing-features:
+
+Missing Arduino Features
+------------------------
+
+.. _langage-missing-analogreference:
+
+**analogReference()**
+
+ It is not possible to implement this function on the Maple
+ hardware. It will be possible on the upcoming Maple Native.
+
+.. _language-no-word:
+
+**word**
+
+ Readers familiar with the Arduino environment may notice that the
+ ``word`` datatype is missing from the above table's list of data
+ types. We chose **not to provide** the ``word`` data type on the
+ Maple. If you want a 16-bit unsigned integer, use the ``uint16``
+ type instead.
+
+ While the Maple has 32-bit words, the word size on an Arduino
+ board is only 16 bits, and code that uses the ``word`` type is
+ likely to rely on that fact.
+
+ By not supporting ``word``, you'll get a compile error when
+ porting Arduino code to the Maple instead of potentially weird,
+ hard-to-debug runtime behavior.
+
+ If you really must have ``word``, you can include the following
+ ``typedef`` in your program::
+
+ typedef uint16 word;
+
+Unimplemented Arduino Features
+------------------------------
+
+The following Wiring/Arduino features are currently unimplemented on
+the Maple. However, they will be present in future versions:
+
+- `noTone() <http://www.arduino.cc/en/Reference/NoTone>`_
+- `pulseIn() <http://www.arduino.cc/en/Reference/PulseIn>`_
+- `shiftOut() <http://www.arduino.cc/en/Reference/ShiftOut>`_
+- `String <http://arduino.cc/en/Reference/StringObject>`_
+- `tone() <http://www.arduino.cc/en/Reference/Tone>`_
+
+.. _our reference page: http://leaflabs.com/docs/external-interrupts/
+
+.. _newlib: http://sourceware.org/newlib/
+
+.. _cpp-for-maple:
+
+C++ for Maple
+--------------
+
+If you haven't programmed in C++, or if you just need to jog your
+memory, you may want to check out our :ref:`Language Index
+<language-index>`. It provides some introductory coverage of
+programming ideas and C++.
+
+.. _arduino_c_for_c_hackers:
+
+Note for C/C++ Hackers
+----------------------
+
+This is a note for programmers comfortable with C or C++ (although,
+you C programmers should remember that `C++ is not a superset of C
+<http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B>`_) who
+want a better understanding of the differences between C++ and the
+Wiring language. The good news is that the differences are relatively
+few; Wiring is just a thin wrapper around C++.
+
+Some potentially better news is that the Maple can be programmed using
+a :ref:`standard Unix toolchain <unix-toolchain>`, so if you'd rather
+stick with :command:`gcc`, :command:`make`, and friends, you can.
+
+A *sketch* is the IDE's notion of a project; it consists of one or
+more files written in the Wiring language, which is mostly the same as
+C++. The major difference between the two is that in Wiring, it's not
+necessary to declare global functions before they are used. That is,
+the following is valid Wiring, and ``f()`` returns ``5``::
+
+ int f() {
+ return g();
+ }
+
+ int g() {
+ return 5;
+ }
+
+All of the files in a sketch share the same (global) namespace. That
+is, the behavior is as if all of a sketch's files were part of the
+same translation unit, so they don't have to include one another in
+order to access each other's definitions. The only other major
+difference between Wiring and C++ is that Wiring doesn't support
+dynamically allocated memory -- that is, ``new`` and ``delete`` won't
+work. As of |today|, Maple only has 20 KB RAM, anyway, so it's
+doubtful that static allocation is not what you want.
+
+The Wiring language also does not require you to define your own
+``main`` method (in fact, it forbids you from doing so). Instead, you
+are required to define two functions, ``setup`` and ``loop``, with
+type signatures ::
+
+ void setup(void);
+ void loop(void);
+
+Once a sketch is uploaded to a Maple and begins to run, ``setup()`` is
+called once, and then ``loop()`` is called repeatedly. The IDE
+compilation process proceeds via a source-to-source translation from
+the files in a sketch to C++.
+
+This translation process first concatenates the sketch files, then
+parses the result to produce a list of all functions defined in the
+global scope. (We borrow this stage from the Arduino IDE, which in
+turn borrows it from Wiring. It uses regular expressions to parse
+C++, which is, of course, `Bad and Wrong
+<http://www.retrologic.com/jargon/B/Bad-and-Wrong.html>`_. An
+upcoming rewrite of the IDE performs this preprocessing step
+correctly, using a real parser. Until then, you have our apologies.)
+The order in which the individual sketch files are concatenated is not
+defined; it is unwise to write code that depends on a particular
+ordering.
+
+The concatenated sketch files are then appended onto a file which
+includes `WProgram.h
+<http://github.com/leaflabs/libmaple/blob/master/wirish/WProgram.h>`_
+(which includes the wirish and libmaple libraries, and declares
+``setup()`` and ``loop()``), and then provides declarations for all
+the function definitions found in the previous step. At this point,
+we have a file that is a valid C++ translation unit, but lacks a
+``main()`` method. The final step of compilation provides this
+method, which behaves roughly like::
+
+ int main(void) {
+ setup();
+ while (true) loop();
+ }
+
+(The truth is a little bit more complicated, but not by much).
+
+As an example, consider a sketch with two files. The first file
+contains ``setup()`` and ``loop()``::
+
+ int the_pin;
+
+ void setup() {
+ the_pin = choose_a_pin();
+ pinMode(the_pin, OUTPUT);
+ }
+
+ void loop() {
+ togglePin(the_pin);
+ }
+
+The second file contains the (not very useful) implementation for
+``choose_a_pin()``::
+
+ int choose_a_pin() {
+ return random(5, 15);
+ }
+
+Then the results of the concatenation process might be ::
+
+ int the_pin;
+
+ void setup() {
+ the_pin = choose_a_pin();
+ pinMode(the_pin, OUTPUT);
+ }
+
+ void loop() {
+ togglePin(the_pin);
+ }
+
+ int choose_a_pin(void);
+
+ int choose_a_pin() {
+ return random(5, 15);
+ }
+
+Which could plausibly be turned into the final source file ::
+
+ #include "WProgram.h"
+
+ void setup(void);
+ void loop(void);
+ int choose_a_pin(void);
+
+ int the_pin;
+
+ void setup() {
+ the_pin = choose_a_pin();
+ pinMode(the_pin, OUTPUT);
+ }
+
+ void loop() {
+ togglePin(the_pin);
+ }
+
+ int choose_a_pin(void);
+
+ int choose_a_pin() {
+ return random(5, 15);
+ }
+
+ int main() {
+ setup();
+ while (true) loop();
+ }
+
+(Recall that it's legal C++ for a function to be declared multiple
+times, as long as it's defined exactly once).
+
+
+Recommended Reading
+-------------------
+
+* `newlib Documentation <http://sourceware.org/newlib/>`_
+* STMicro documentation for STM32F103RB microcontroller:
+
+ * `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>`_ (assembly language and register reference)
diff --git a/docs/source/libmaple.rst b/docs/source/libmaple.rst
new file mode 100644
index 0000000..8cc39a3
--- /dev/null
+++ b/docs/source/libmaple.rst
@@ -0,0 +1,41 @@
+.. highlight:: sh
+
+.. _libmaple:
+
+``libmaple``
+============
+
+.. image:: /_static/img/libmaple-screenshot-small.png
+ :align: center
+ :alt: libmaple screenshot
+
+`LeafLabs libmaple <libmaple-libmaple>`_ is the low level library we
+have developed for for the ARM Cortex-M3 chips manufactured by
+STMicroelectronics used in the Maple boards (the `STM32F103x`_
+series). We found the generic peripheral libraries too painful to
+build on top of, and reimplemented the functionality we needed in a
+simpler (and less general) form.
+
+.. _libmaple-libmaple: http://github.com/leaflabs/libmaple
+.. _STM32F103x: http://www.st.com/stonline/stappl/productcatalog/app?path=/pages/stcom/PcStComPartNumberSearch.searchPartNumber&search=stm32f103
+
+This library is transparently included in the `Maple IDE
+<http://leaflabs.com/docs/maple-ide/>`_, but we develop it separately
+using good old Unix command line tools and release it for advanced
+users who might chafe at the "sketch" programming model of the
+IDE. Included are some examples, a Makefile, and the compatibility
+wrappers and code to imitate the Arduino programming library.
+
+**Check out the latest source**::
+
+ git clone git://github.com/leaflabs/libmaple.git
+
+**Table of contents:**
+
+.. toctree::
+ :maxdepth: 2
+
+ Guide to using GCC's ARM target <arm-gcc>
+
+.. TODO LATER create, style, and host a pure Doxygen libmaple
+.. reference docs. This implies determining a stable API.
diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst
new file mode 100644
index 0000000..7623963
--- /dev/null
+++ b/docs/source/libraries.rst
@@ -0,0 +1,194 @@
+.. highlight:: c++
+.. default-domain:: cpp
+
+.. _libraries:
+
+=========================
+ Maple Library Reference
+=========================
+
+.. Note: if you port an Arduino library and document it here, be sure
+.. to update compatibility.rst to reflect that fact.
+
+This page briefly summarizes the Arduino libraries that have been
+ported to Maple. You can use a library from within a sketch by going
+to Sketch > Import Library... from within the IDE, then choosing the
+library you want.
+
+Any incompatibilities between the Maple and Arduino versions are noted
+in the description of the library.
+
+.. contents:: Contents
+ :local:
+
+.. toctree::
+ :hidden:
+
+ libs/servo.rst
+
+.. _libraries-servo:
+
+Servo
+-----
+
+The Servo library is provided for convenient control of RC
+servomotors. For more information, see the :ref:`Servo <libs-servo>`
+reference.
+
+**Compatibility Note**
+
+The Servo class provides a public interface identical to the Arduino
+version's documented functionality (as of Arduino 0021), so in most
+cases, this library will be a drop-in replacement.
+
+However, there are some differences, essentially at the level of
+implementation details.
+
+The major difference is that while the Arduino implementation drives
+the servos with "bit-banged" :ref:`PWM <pwm>`, the Maple
+implementation uses :ref:`timers <timers>` to drive the PWM directly.
+
+Consequently, **the Maple implementation only allows Servo instances
+to** :ref:`attach <libs-servo-attach>` **to pins that support PWM**.
+
+To determine if a pin supports PWM (15 Maple pins do), you can either
+check if "PWM" appears next to its number on the Maple silkscreen, or
+consult the :ref:`pwmWrite() <lang-pwmwrite>` documentation.
+
+RC Servos expect a pulse approximately every 20ms. In the Maple
+implementation, :ref:`periods <lang-hardwaretimer-setperiod>` are set
+for entire timers, rather than individual channels. Thus,
+``attach()``\ ing a Servo to a pin can interfere with other pins
+associated with the same timer\ [#fard-servo]_.
+
+Because of this, we recommend connecting multiple servomotors to pins
+which share a timer, in order to keep as many timers free for other
+purposes as possible. Consult the :ref:`table provided in the timers
+reference <timers-pin-channel-map>` to match up pins and timer
+channels.
+
+Another difference: although it is not publicly documented to do so,
+the Arduino implementation of `attach()
+<http://arduino.cc/en/Reference/ServoAttach>`_ returns the timer
+channel associated with the newly-attached pin, or 0 on failure (as of
+Arduino 0021). The Maple implementation returns true on success, and
+false on failure (and this is its documented behavior).
+
+.. _libraries-liquid-crystal:
+
+LiquidCrystal
+-------------
+
+.. TODO 0.0.10 make our own LiquidCrystal docs
+
+The LiquidCrystal library allows Maple to control LCD screens. For
+more information, see the `Arduino LiquidCrystal documentation
+<http://www.arduino.cc/en/Reference/LiquidCrystal>`_.
+
+**Compatibility Note**
+
+At this time, no incompatibilities between the Maple and Arduino
+versions are known. Any observed differences should be considered
+bugs, and reported on the forums.
+
+.. _libraries-wire:
+
+Wire
+----
+
+We provide a soft (bit-banged) implementation of the `Wire I2C library
+<http://arduino.cc/en/Reference/WireBegin>`_.
+
+**Compatibility Note**
+
+This implementation is synchronous, and thus supports only a subset of
+the full Wire interface (however, the functionality which is supported
+is fully compatible with Arduino). For now, please use the function
+reference which follows when developing projects using our
+implementation.
+
+Please note that the current implementation only supports master mode
+using a bit-banged (software) protocol. Future enhancements will use
+the hardware i2c peripheral on the stm32 as well as the DMA for
+performance. Support for slave, smBUS, and multimaster modes are also
+slated for inclusion in the enhanced Wire port.
+
+.. TODO 0.0.10 Wire docs in the cpp domain in own page under /libs/
+
+Wire Function Reference
+^^^^^^^^^^^^^^^^^^^^^^^
+
+``Wire.begin()``
+ Joins the i2c bus as master, using pin 20 as SDA and pin 21 as SCL
+ (this is compatible with the pin settings on the Arduino Mega).
+
+``Wire.begin(sda, scl)``
+ Like ``Wire.begin()``, but with the given pins as SDA and
+ SCL.
+
+``Wire.beginTransmission(slave_address)``
+ Set up a transmission to a slave device with the given (7-bit)
+ address. Bytes subsequently queued for transmission (using
+ ``Wire.send``) will be sent to ``slave_address`` when ``void
+ Wire.endTransmission()`` is called.
+
+``void Wire.send(byte)``
+ Queues the given byte (``uint8`` or ``int``) to the slave address
+ previously specified by a call to ``Wire.beginTransmission``. At
+ most 32 bytes may be queued in a single transmission.
+
+``Wire.send(string)``
+ Queues a given string (``char*``) for transmission. The characters
+ of the string are individually queued for transmission as
+ bytes. At most 32 bytes may be queued in a single transmission.
+
+``Wire.send(buffer, length)``
+ Queues a byte buffer ``buffer`` (``uint8*`` or ``int*``), with
+ ``length`` elements, for transmission. At most 32 bytes may be
+ queued in a single transmission.
+
+``Wire.endTransmission()``
+ Ends a transmission (begun by ``Wire.beginTransmission(uint8)``),
+ and actually sends the bytes queued by calls to Wire.send.
+
+ The return value is one of the following status codes:
+
+ * ``SUCCESS``: All bytes were transmitted successfully.
+
+ * ``EDATA``: More than 32 bytes were queued for transmission. No
+ bytes are actually sent when this happens.
+
+ * ``ENACKADDR``: Did not receive ACK on transmit of address. No
+ bytes are actually sent when this happens.
+
+ * ``ENACKTRNS``: Did not receive ACK during transmit of data. Some
+ bytes may have been sent when this happens; however, the
+ transmission is aborted after the first byte of data which is
+ not ACKed by the slave device.
+
+ * ``EOTHER``: Other error occurred.
+
+``Wire.requestFrom(address, num_bytes)``
+ Requests ``num_bytes`` bytes from 7-bit slave address
+ address. Returns the actual number of bytes read. These bytes may
+ subsequently be read one at a time using ``Wire.receive()``.
+
+ Note: if ``num_bytes`` exceeds the size of the transmit/receive
+ buffer (currently 32), it will be truncated to 32.
+
+``Wire.receive()``
+ Get and return the next byte read during the previous call to
+ ``Wire.requestFrom(uint8, int)``. You can check how many bytes are
+ left to read using ``uint8 Wire.available()``.
+
+``Wire.available()``
+ Returns the number of bytes which are still available for reading
+ (with ``Wire.receive()``) from the last call to
+ ``Wire.requestFrom(uint8, int)``.
+
+.. rubric:: Footnotes
+
+.. [#fard-servo] The Arduino implementation also captures timer
+ channels in groups as more Servo objects are attached, but the
+ details of which channels have their periods reset when are
+ slightly different.
diff --git a/docs/source/libs/servo.rst b/docs/source/libs/servo.rst
new file mode 100644
index 0000000..f92fd91
--- /dev/null
+++ b/docs/source/libs/servo.rst
@@ -0,0 +1,108 @@
+.. highlight:: cpp
+
+.. _libs-servo:
+
+=======
+ Servo
+=======
+
+This documents the Servo library for controlling RC servomotors. It
+is implemented as a thin layer over the built-in :ref:`timer
+peripherals <timers>`.
+
+You can use this library in the :ref:`IDE <ide>` by choosing the Servo
+item under the Sketch > Import Library... menu.
+
+If you are using the :ref:`Unix toolchain <unix-toolchain>`, the
+library is located in ``$LIB_MAPLE_HOME/libraries/Servo/``.
+
+Servo Class Reference
+---------------------
+
+You can construct a Servo object by including the declaration ::
+
+ Servo servo;
+
+in your sketch. This will create a Servo object called ``servo``.
+You can then use any of its methods; for instance, to control a
+servomotor attached to pin 9, you could write ::
+
+ servo.attach(9);
+
+.. cpp:class:: Servo
+
+ Class for controlling RC servomotors via :ref:`timers <timers>`.
+
+.. _libs-servo-attach:
+
+.. cpp:function:: bool Servo::attach(uint8 pin, uint16 min, uint16 max)
+
+ Attach this Servo object to the given ``pin``. The pin must be
+ capable of PWM. You can check this by seeing if "PWM" is written
+ next to its number on the Maple silkscreen, or by consulting the
+ :ref:`pwmWrite() <lang-pwmwrite>` documentation.
+
+ Sets this pin's :ref:`mode <lang-pinmode>` to :ref:`PWM
+ <lang-pinmode-wiringpinmode>`, and returns true if successful.
+ Does nothing and returns false if the pin doesn't support PWM.
+
+ Parameter ``min`` is the pulse width corresponding to 0 degrees;
+ ``max`` is the pulse width corresponding to 180 degrees (both are
+ in microseconds).
+
+.. cpp:function:: bool Servo::attach(uint8 pin)
+
+ Equivalent to :ref:`attach(pin, 544, 2400) <libs-servo-attach>`.
+
+.. _libs-servo-attached:
+
+.. cpp:function:: int Servo::attached() const
+
+ If currently attached (via :ref:`attach() <libs-servo-attach>`) to
+ a pin, returns that pin's number. Returns ``NOT_ATTACHED``
+ otherwise.
+
+.. cpp:function:: bool Servo::detach()
+
+ If this Servo object is currently attached to pin, stops driving
+ the servo by setting a zero pulse width (this is accomplished by
+ setting the associated :ref:`channel mode
+ <lang-hardwaretimer-setchannelmode>` to ``TIMER_DISABLED``).
+
+ Subsequently, calling :ref:`attached() <libs-servo-attached>` will
+ return ``NOT_ATTACHED``.
+
+.. cpp:function:: void Servo::write(unsigned int value)
+
+ If ``value`` is less than ``SERVO_MAX_WRITE_ANGLE`` (which, for
+ Arduino compatibility, is 200), it's interpreted as an angle in
+ degrees. Otherwise, it's treated as a pulse width in microseconds.
+
+ Drives the servo to target the given angle, based on a linear
+ interpolation of the ``min`` and ``max`` pulse widths determined
+ when :ref:`attach() <libs-servo-attach>` was called.
+
+ Be aware that some (especially lower-cost) servos have fairly
+ non-linear maps between pulse width and target angle. Make sure to
+ test your motor before relying on this method.
+
+.. cpp:function:: void Servo::writeMicroseconds(uint16 pulseWidth)
+
+ Drives the servo using a ``pulseWidth``-microsecond pulse.
+
+ If ``pulseWidth`` is outside of the [``min``, ``max``\ ] pulse
+ width range set during :ref:`attach() <libs-servo-attach>`, it will
+ be clamped to lie in this range.
+
+.. cpp:function:: int Servo::read() const
+
+ Returns the servo's target angle, in degrees. This will be clamped
+ to lie between 0 (when the pulse width is at most ``min``) and 180
+ (when the pulse width is at least ``max``).
+
+.. cpp:function:: uint16 Servo::readMicroseconds() const
+
+ Returns the pulse width of the wave currently driving the servo, in
+ microseconds. This will be clamped to lie in the [``min``,
+ ``max``\ ] pulse width range set during :ref:`attach()
+ <libs-servo-attach>`.
diff --git a/docs/source/maple-ide-install.rst b/docs/source/maple-ide-install.rst
new file mode 100644
index 0000000..92d1a96
--- /dev/null
+++ b/docs/source/maple-ide-install.rst
@@ -0,0 +1,162 @@
+.. highlight:: c++
+
+.. _maple-ide-install:
+
+========================
+ Maple IDE Installation
+========================
+
+If you still can't get the IDE installed after reading this page,
+check the :ref:`troubleshooting page <troubleshooting>` for help with
+some common problems. If all else fails, try our `forum`_, or `contact
+us directly`_\ !
+
+.. contents:: Contents
+ :local:
+
+Download
+--------
+
+Choose the correct version for your operating system:
+
+.. list-table::
+ :widths: 15 30 50
+ :header-rows: 1
+
+ * - Platform
+ - Status
+ - IDE Package
+ * - Windows
+ - Tested on 32bit Windows XP
+ - `maple-ide-LATEST-windowsxp32.zip <http://static.leaflabs.com/pub/leaflabs/maple-ide/maple-ide-LATEST-windowsxp32.zip>`_ (about 75mb)
+ * - Linux
+ - Tested on Ubuntu 9.10 (64bit) and 10.04 (32bit)
+ - `maple-ide-LATEST-linux32.tgz <http://static.leaflabs.com/pub/leaflabs/maple-ide/maple-ide-LATEST-linux32.tgz>`_ (about 30mb)
+
+ `maple-ide-LATEST-linux64.tgz <http://static.leaflabs.com/pub/leaflabs/maple-ide/maple-ide-LATEST-linux64.tgz>`_ (about 30mb)
+ * - Mac OSX
+ - Tested on Snow Leopard 10.6 (64bit and 32bit)
+ - `maple-ide-LATEST-macosx-10_6.dmg <http://static.leaflabs.com/pub/leaflabs/maple-ide/maple-ide-LATEST-macosx-10_6.dmg>`_ (about 40mb)
+
+The package bundles together a compiler, an upload utility, a software
+library, and a simple GUI text editor. All this software is `free and
+open <http://fsf.org/>`_; we are grateful to the `Arduino
+<http://arduino.cc/>`_, `CodeSourcery
+<http://www.codesourcery.com/>`_, `GNU <http://gnu.org/>`_, and
+`OpenMoko <http://openmoko.com/>`_ developers, as well as many others,
+who allow us to reuse their software.
+
+Installation
+------------
+
+* :ref:`Windows <maple-ide-install-windows>`
+* :ref:`Linux <maple-ide-install-linux>`
+* :ref:`OS X <maple-ide-install-osx>`
+
+.. _maple-ide-install-windows:
+
+Windows
+^^^^^^^
+First, extract all the files in the ZIP file to a suitable location on
+your system (like your Desktop folder). Next, you have to install
+some drivers. Sorry!
+
+.. note:: Note that while these instructions work on Windows XP,
+ changes in Windows 7 mean that you won't be able to install the IDE
+ without disabling driver signing on your computer. We're working
+ on resolving this situation. For now, `users on the forum have
+ reported some workarounds
+ <http://forums.leaflabs.com/topic.php?id=73>`_.
+
+First, install DFU drivers (for uploading code to your Maple) using
+the following steps.
+
+1. Plug your Maple into the USB port.
+
+2. Hit the reset button on your Maple (it's the small button at the
+ bottom left, labeled RESET). Notice that it blinks quickly 6 times,
+ then blinks slowly a few more times.
+
+3. Hit reset again, and this time push and hold the other button
+ during the 6 fast blinks (the button is on the top right; it is
+ labeled BUT). You can release it once the slow blinks start.
+
+4. Your Maple is now in :ref:`perpetual bootloader mode
+ <troubleshooting-perpetual-bootloader>`. This should give you a
+ chance to install the DFU drivers.
+
+5. Windows should now prompt you for some drivers. In the top level
+ directory of the Maple IDE, point Windows to
+ :file:`drivers/mapleDrv/dfu/`.
+
+Next, install serial drivers (for communicating with your Maple using
+serial over USB).
+
+1. Reset your Maple and allow it to exit the bootloader (wait for the
+ slow blinking to stop). The Maple will next start running whatever
+ program was uploaded to it last. (New Maples will start running the
+ test program we upload to them before shipping them to you).
+
+2. Once Maple is running some user code, Windows should prompt you for
+ more drivers. Point windows to :file:`driver/mapleDrv/serial`.
+
+You can now run the Maple IDE by double-clicking on the
+:command:`maple-ide` program from within the extracted IDE directory.
+
+.. _maple-ide-install-linux:
+
+Linux
+^^^^^
+
+.. _maple-ide-install-java:
+.. note::
+
+ The IDE is written in Java and requires a compatible runtime (JRE).
+
+ If you don't have one, they're usually pretty easy to install. Sun
+ Java 1.6 and OpenJDK 1.6 are known to work, and runtimes mostly
+ compatible with Sun Java 1.5+ should probably get the job done.
+
+ To install Java, try using your distribution's software packaging
+ tool and search for "JRE" or "java". On Debian-based systems
+ (including Ubuntu) you can try to install the OpenJDK 1.6 JRE
+ with::
+
+ $ sudo aptitude install openjdk-6-jre
+
+Extract the tarball to an appropriate location (like your home
+directory or desktop).
+
+Make sure you have a Java runtime (JRE) installed; if you can run
+:command:`java` from the shell, you should be fine.
+
+Next, run the script :file:`install-udev-rules.sh` in the extracted
+IDE directory. It will ask for root permissions. You now need to
+restart udev::
+
+ sudo /etc/init.d/udev restart
+
+This will grant members of the group ``plugdev`` read/write access to
+Maple devices over USB. Make sure that you are in that group. (For
+more information on why this is part of the install process, see the
+:ref:`Unix toolchain quickstart <toolchain-udev>`).
+
+To run the Maple IDE, run :command:`maple-ide` from the shell, or
+double-click on it if your window system supports it.
+
+Feel free to put the IDE directory wherever you want. As long as you
+leave its internal structure unchanged, things should be fine.
+
+.. _maple-ide-install-osx:
+
+OS X
+^^^^
+
+Double-click on the :file:`.dmg` file you downloaded to mount the disk
+image. From the mounted image, drag and drop the Maple IDE icon into
+your computer's Applications folder.
+
+To run the Maple IDE, double-click the :command:`Maple IDE`
+application you dragged into your computer's :file:`Applications`
+folder.
+
diff --git a/docs/source/maple-quickstart.rst b/docs/source/maple-quickstart.rst
new file mode 100644
index 0000000..08fa5c1
--- /dev/null
+++ b/docs/source/maple-quickstart.rst
@@ -0,0 +1,200 @@
+.. highlight:: sh
+
+.. _maple-quickstart:
+
+========================
+ Maple Quickstart Guide
+========================
+
+You'll need a `Maple board <http://leaflabs.com/store/>`_, a `Mini-B
+USB cable <http://www.google.com/products?q=mini-b+usb+cable>`_, a
+functional computer, and possibly root (or "administrator") access to
+that computer.
+
+If you have trouble along the way, try the :ref:`troubleshooting page
+<troubleshooting>` for help with some common problems. If all else
+fails, try our `forum`_, or `contact`_ us directly!
+
+.. contents:: Contents
+ :local:
+
+.. _maple-quickstart-get-ide:
+
+Install and run the IDE
+-----------------------
+
+See the :ref:`IDE installation page <maple-ide-install>` for instructions.
+
+.. _maple-quickstart-compile-blinky:
+
+Compile a program!
+------------------
+
+Let's load up a simple example program that blinks the status LED.
+From the File menu, select Examples > Digital > Blink:
+
+.. image:: /_static/img/blinky.png
+ :align: center
+ :alt: Click "Blink"
+
+Next, select Tools > Board > "LeafLabs Maple ... to FLASH":
+
+.. image:: /_static/img/blinky-to-flash.png
+ :align: center
+ :alt: Upload to FLASH
+
+.. note::
+
+ You have the option between RAM and FLASH programming: FLASH saves
+ the program into permanent memory so the program will be run every
+ time the Maple is reset, while RAM simply injects the compiled
+ program into the processor's memory.
+
+ Programming to RAM is faster to upload and a buggy program can be
+ wiped away with a simple reset, while FLASH memory is larger and is
+ the only option for permanently uploading a program.
+
+.. image:: /_static/img/verify_button.png
+ :align: left
+ :alt: Verify button
+
+Now press the "verify" button (furthest to the left with a "play"
+arrow) to compile the code. Some output should scroll by in the
+bottom window, and then a confirmation message will appear:
+
+.. image:: /_static/img/verify-success.png
+ :align: center
+ :alt: Code verified successfully.
+
+.. _maple-quickstart-upload:
+
+Upload that program!
+--------------------
+
+Now it's (finally!) time to plug in your Maple. Use a mini-b cable,
+making sure that the power source jumper is on the USB header first.
+We ship Maples with the power source jumper configured that way, so
+you shouldn't have to do anything. For reference, it should look like
+this:
+
+.. image:: /_static/img/plugged-in-maple.png
+ :align: center
+ :alt: Correctly plugged in Maple
+
+.. note::
+
+ On OS X, a network interface dialog will pop up every time you plug in
+ the Maple.
+
+ .. image:: /_static/img/osx-unconfigured-popup.png
+ :align: center
+ :alt: Unconfigured modem popup
+
+ If you click "Network Preferences..." and accept the default ("Not
+ Configured"), the dialog won't pop up and everything will work fine.
+ That is, from this window, click "Apply":
+
+ .. image:: /_static/img/osx-network-prefs-unconfigured.png
+ :align: center
+ :scale: 75%
+ :alt: Click "Apply"
+
+The Maple should blink a short pattern on the blue status LED every
+time it is plugged in, reset, or reprogrammed, just to let you know
+it's there. If it ever starts throbbing in a slow, smooth pattern,
+then you've got a problem: see the :ref:`troubleshooting
+<troubleshooting>` page for help.
+
+If all systems are go, select the Board type and Serial Port
+(something like :file:`COM3`, :file:`/dev/ttyACM0`, or
+:file:`/dev/tty.usbmodemfa221`, depending on your platform, from the
+Tools menu:
+
+Windows XP:
+
+.. image:: /_static/img/serial-port-win.png
+ :align: center
+ :alt: Board type and serial port for Windows XP
+
+Linux:
+
+.. image:: /_static/img/serial-port-ubuntu.png
+ :align: center
+ :alt: Board type and serial port for Linux
+
+OS X:
+
+.. image:: /_static/img/serial-port-mac.png
+ :align: center
+ :alt: Board type and serial port for the OS X
+
+Then press the "Upload" button to upload your program to the
+Maple.
+
+.. image:: /_static/img/upload-button.png
+ :align: center
+ :alt: Click the "Upload" button
+
+You should see some text and a progress bar flash by in the status
+window of the IDE, then some blinky patterns on the Maple, and then a
+constant blinking on and off.
+
+Go ahead and modify the file a little bit: if you change the
+'delay(1000);' numbers to a different value the speed of the blink
+will change. The value is a time in milliseconds to pause before
+continuing with the program, so by default the LED will be on for 1
+second, then off for 1 second, etc. Any time you make any changes, go
+through the same Verify and Upload process to upload the new version
+of your program to your Maple.
+
+.. warning::
+
+ The uploading step is the most common source of problems,
+ especially on Windows.
+
+ The situation is much improved over the past, but if you have
+ trouble, try doing things again, unplugging your Maple and plugging
+ it back in, using :ref:`perpetual bootloader mode
+ <troubleshooting-perpetual-bootloader>`, or restarting the
+ IDE.
+
+ If nothing works, please report the problem in the `forum`_.
+
+.. _maple-quickstart-serial-port:
+
+Use the serial port monitor!
+----------------------------
+
+As a last step to make sure everything has been configured correctly,
+let's upload a hello world program that will send text from the Maple
+back to the IDE over the USB connection. From the File menu, select
+Examples > Stubs > HelloWorld (similarly to when you selected the
+Blink program), and make sure the correct board and serial port
+targets are selected from the Tools pull-down.
+
+Open the serial monitor window (button on the far right) and make sure
+the 9600 baud speed is selected. Then go back to the code editing
+window and upload your program (Upload will recompile your code
+automatically if there's been any change since the last Verify). You
+should get text spit at you over the serial monitor right after the
+program is uploaded. Shout back! We can hear you!
+
+Go forth exuberantly!
+---------------------
+
+We really hope you got this far and didn't frown or make a bitter
+lemon face getting here. Where you go now is up to you: perhaps you've
+got some crazy project cooking, or a longer tutorial to work through,
+or maybe now is a good time for a trip to the kitchen for a delicious
+`sandwich <http://everything2.com/title/Velvet+Elvis>`_.
+
+If you blew through this guide and are the kind of person who drinks
+their coffee straight, has more than a 100 lines of vim or emacs
+customization, and doesn't even have a mouse plugged into their
+computer, you may want to look at the :ref:`Unix Toolchain quickstart
+<unix-toolchain>` guide. It's the tutorial for getting working with
+your old friends :command:`make`, :command:`jtag`, and :command:`gcc`.
+
+Let us know what you come up with! Tag us with #leaflabs on Twitter,
+post in the `forum`_, track us down in the real world, whatever. We
+love projects!
diff --git a/docs/source/prolog.rst b/docs/source/prolog.rst
new file mode 100644
index 0000000..2823947
--- /dev/null
+++ b/docs/source/prolog.rst
@@ -0,0 +1,7 @@
+.. Additions to this file will be included at the beginning of every
+.. .rst file. DO NOT USE IT to insert a header; this is not
+.. recommended by the Sphinx people, who have other ways of doing it.
+
+.. Common substitutions
+.. |vcc| replace:: V\ :sub:`cc`
+.. |i2c| replace:: I\ :sup:`2`\ C
diff --git a/docs/source/pwm.rst b/docs/source/pwm.rst
new file mode 100644
index 0000000..1a8f4df
--- /dev/null
+++ b/docs/source/pwm.rst
@@ -0,0 +1,118 @@
+.. _pwm:
+
+PWM
+===
+
+Pulse Width Modulation (PWM) 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 timer can generate 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
+<lang-hardwaretimer-setprescalefactor>` (clock divider) in front of
+the counter can increase this maximum period. Setting the
+:ref:`period <lang-hardwaretimer-setperiod>` 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
+------------------
+
+- :ref:`lang-pinmode`
+- :ref:`lang-pwmwrite`
+- :ref:`Timer API<lang-hardwaretimer>` (especially :ref:`setOverflow()
+ <lang-hardwaretimer-setoverflow>`, :ref:`setPrescaleFactor()
+ <lang-hardwaretimer-setprescalefactor>`, and :ref:`setPeriod()
+ <lang-hardwaretimer-setperiod>`).
+- :ref:`Timers reference <timers>`.
+
+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:
+
+ * `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/docs/source/specs.rst b/docs/source/specs.rst
new file mode 100644
index 0000000..4972a83
--- /dev/null
+++ b/docs/source/specs.rst
@@ -0,0 +1,29 @@
+.. _specs:
+
+.. _specs-Technical-Specifications:
+
+================================
+Maple's Technical Specifications
+================================
+
+ * STM32 F103RB: a **32-bit** ARM Cortex M3 microprocessor
+ * Clock Speed: **72 MHz**
+ * Operating Voltage: 3.3V
+ * Input Voltage (recommended): 3.0V-12V
+ * 39 Digital I/O Pins (:ref:`GPIO <gpio>`)
+ * 16 Analog Input Pins
+ * 12-bit **ADC** resolution (:ref:`ADC <adc>`)
+ * 15 **PWM** pins at 16-bit resolution (:ref:`PWM <pwm>`)
+ * Dedicated **USB** port for programming and communications (:ref:`USB<usb>`)
+ * External **JTAG** interface (:ref:`USB <jtag>`)
+ * **128 Flash** and **20KB SRAM**
+ * 64 Channel nested vector interrupt handler (including external interrupt on GPIO’s)
+ * Integrated **SPI** (:ref:`SPI<spi>`)
+ * Integrated **I2C** (:ref:`I2C<i2c>`)
+ * 7 Channels of Direct Memory Access (DMA)
+ * 3 **USART** divices (:ref:`USART <usart>`)
+ * Four 4-channel Timers (:ref:`Timers <timers>`)
+ * Supplies up to 800mA @ 3.3v
+ * Support for low power and sleep modes (<500uA)
+ * Dimensions are 2.05″x2.1″
+
diff --git a/docs/source/spi.rst b/docs/source/spi.rst
new file mode 100644
index 0000000..ba43eef
--- /dev/null
+++ b/docs/source/spi.rst
@@ -0,0 +1,30 @@
+.. _spi:
+
+=====
+ SPI
+=====
+
+The Serial Peripheral Interface Bus (SPI) is a serial data transfer
+protocol useful for interacting with a wide variety of hardware
+peripherals.
+
+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.
+
+The public libmaple API for managing the SPI ports is the
+:ref:`HardwareSpi <lang-hardwarespi>` class.
+
+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:
+
+ * `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/docs/source/timers.rst b/docs/source/timers.rst
new file mode 100644
index 0000000..56dd686
--- /dev/null
+++ b/docs/source/timers.rst
@@ -0,0 +1,206 @@
+.. highlight:: cpp
+
+.. _timers:
+
+Timers
+======
+
+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 can generate regular square-wave signals on specific
+output pins without consuming extra clock cycles. By attaching
+interrupt handlers to these channels (instead of just changing the
+voltage on an external pin), more complex events can be scheduled.
+
+.. contents:: Contents
+ :local:
+
+Introduction
+------------
+
+.. _timers-prescale:
+
+The four timers each have four separate compare channels. Each channel
+has an associated 16-bit counter that can be configured with a 16-bit
+prescaler and a 16-bit overflow value. The prescaler determines how
+fast the counter changes, while the overflow value determines when it
+gets reset.
+
+The prescaler acts as a divider of the 72MHz system clock. That is,
+with a prescaler of 1, the channel's counter increments with a
+frequency of 72MHz, rolling over (passing the maximum 16-bit unsigned
+integer value of 65,535) more than a thousand times a second. With a
+prescaler of 7200, it has a frequency of (72/7200) MHz = 10 KHz,
+rolling over approximately every 6.55 seconds.
+
+The overflow value is the maximum value the counter will go up to. It
+defaults to the full 65,535; smaller values will cause the counter to
+reset to zero more frequently.
+
+Whenever a channel's counter reaches its overflow value, an "update
+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.
+
+libmaple Reference
+------------------
+
+The libmaple API for interacting with timers is documented at the
+:ref:`HardwareTimer reference <lang-hardwaretimer>`.
+
+Caveats
+-------
+
+.. _timers-pwm-conflicts:
+
+**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 following table to match up timer
+channels and Maple header pin numbers:
+
+.. _timers-pin-channel-map:
+
+.. csv-table::
+ :header: Timer, Ch. 1 pin, Ch. 2 pin, Ch. 3 pin, Ch. 4 pin
+
+ ``Timer1``, 6, 7, 8, --
+ ``Timer2``, 2, 3, 1, 0
+ ``Timer3``, 12, 11, 27, 28
+ ``Timer4``, 5, 9, 14, 24
+
+**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 pseudorandom 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 (or somehow causing your program to re-enable serial
+ over USB using :ref:`SerialUSB.begin() <lang-serialusb-begin>`).
+
+ 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.
+
+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()``.
+
+Code Examples
+-------------
+
+LED blink
+^^^^^^^^^
+
+::
+
+ #define LED_RATE 500000 // in microseconds; should give 0.5Hz toggles
+
+ void handler_led(void);
+
+ void setup()
+ {
+ // Set up the LED to blink
+ pinMode(BOARD_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) {
+ toggleLED();
+ }
+
+Racing Counters
+^^^^^^^^^^^^^^^
+
+::
+
+ void handler_count1(void);
+ void handler_count2(void);
+
+ int count1 = 0;
+ int count2 = 0;
+
+ void setup()
+ {
+ // Set up BUT for input
+ pinMode(BOARD_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(BOARD_BUTTON_PIN)) {
+ Timer4.pause();
+ } else {
+ Timer4.resume();
+ }
+ delay(1);
+ }
+ }
+
+ void handler1(void) {
+ count1++;
+ }
+ void handler2(void) {
+ count2++;
+ }
diff --git a/docs/source/troubleshooting.rst b/docs/source/troubleshooting.rst
new file mode 100644
index 0000000..f3052d9
--- /dev/null
+++ b/docs/source/troubleshooting.rst
@@ -0,0 +1,236 @@
+.. highlight:: sh
+
+.. _troubleshooting:
+
+Troubleshooting
+===============
+
+This page documents common problems and their solutions.
+
+.. contents:: Contents
+ :local:
+
+===================
+ Hardware problems
+===================
+
+The status LED is throbbing and I can't upload my program!
+----------------------------------------------------------
+
+The LED throbs when there has been a failed software :ref:`assertion
+<language-assert>`.
+
+You can still reprogram by resetting the board and uploading during
+the short window when the bootloader waits for a program.
+
+To make this window longer (it can be hard to get the timing right),
+use :ref:`perpetual bootloader mode
+<troubleshooting-perpetual-bootloader>`.
+
+My board is bricked! I can't upload via the bootloader no matter what!
+----------------------------------------------------------------------
+
+Use the hardcoded serial STM32 serial bootloader to :ref:`re-flash the
+bootloader <bootloader-reflashing>`.
+
+If it really is bricked, and you think it's our fault, `contact us
+<http://leaflabs.com/contact>`_\ !
+
+My 5v peripheral doesn't work! (I2C, SPI, USART, etc)
+-----------------------------------------------------
+
+Yup, the Maple is a 3.3v board. You may need to use a level
+converter. See the :ref:`compatibility <compatibility>`, :ref:`GPIO
+<gpio>`, or other :ref:`hardware specific documentation
+<index-hardware>` for more information.
+
+The reset and D38/serial buttons don't seem to work reliably!
+-------------------------------------------------------------
+
+A few rev3 boards shipped in May-June 2010 may have had unreliable
+buttons; see the :ref:`errata page <errata>` for details. `We're
+happy to replace these for you <http://leaflabs.com/contact>`_\ !
+
+
+.. _troubleshooting-ide-install:
+
+=======================
+ Installation problems
+=======================
+
+I don't have root/administrator access!
+---------------------------------------
+
+There are probably hacks or work-arounds to getting programs uploaded
+without higher level system permissions. If you can access USB
+character devices (ACM or ttyUSB style), you should be able to
+communicate with the Maple and reprogram using an FTDI converter and
+the serial bootloader, but we haven't tried.
+
+.. TODO: be more helpful
+
+[Linux] I don't use udev!
+-------------------------
+
+There is probably a simple way to get autoconfiguration working with
+devfs; in the meantime, you could try running the entire IDE as root.
+
+.. TODO: be more helpful
+
+.. _troubleshooting-ide-usage:
+
+==============
+ IDE problems
+==============
+
+[Mac OS X] The "Board" and "Serial Port" menu items are missing!
+----------------------------------------------------------------
+
+Sometimes this happens if you try to compile or upload without having
+a board selected. The work-around is to restart the IDE. Mysterious!
+
+.. _troubleshooting-compilation:
+
+==========================
+ Common compiler problems
+==========================
+
+``NullPointerException``
+------------------------
+
+A classic! Make sure you have selected a board from the pulldown menu.
+
+.. TODO: remove when Python version is released
+
+``undefined reference to setup()/loop()``
+-----------------------------------------
+
+Your sketch/program either does not include one of the :ref:`setup()
+<lang-setup>` or `loop() <lang-loop>` functions, or it was not found
+by the compiler. Your program must include both ``void setup()`` and
+``void loop()`` functions; they don't have to do anything, but they
+**must** be there.
+
+You can start with an example program (to see one in the IDE, click on
+File > Examples > Stubs > BareMinimum) to get the basic structure.
+See also the :ref:`language <language>` documentation.
+
+This is a common error when your entire sketch is blank.
+
+``error: 'Serial' was not declared in this scope``
+--------------------------------------------------
+
+The classic Arduino has only one USART device and uses the unique name
+"Serial" to control it. Larger devices like the Arduino Mega and the
+Maple have multiple USARTS referred to as ``Serial1``, ``Serial2``,
+etc. You probably want ``Serial2`` on the Maple; that's the one
+connected to pins D0 and D1. See also the :ref:`USART docs <usart>`.
+
+``File(s) not found``
+---------------------
+
+There is an intermittent bug with the temporary directory build system
+that on occasion will lose many of the ``#include``\ d libmaple
+files. If you recompile everything, it should be fine.
+
+.. TODO remove when the Python version is released
+
+.. _troubleshooting-upload:
+
+========================
+ Common upload problems
+========================
+
+My program is too large!
+------------------------
+
+First, make sure you're using the FLASH target instead of RAM; there
+is several times more FLASH memory available for user programs.
+
+``No DFU capable USB device found``
+-----------------------------------
+
+This probably means you don't have a Maple plugged in or powered on.
+Try unplugging and plugging your Maple or pressing the RESET button.
+
+This can also happen if you disable the USB peripheral, e.g. using
+:ref:`SerialUSB.end() <lang-serialusb-end>`.
+
+I have multiple Maples installed; how do I know which one will get flashed?
+---------------------------------------------------------------------------
+
+Because the Maple IDE uses DFU to upload programs, you can't select a
+particular Maple from the Serial Port menu to upload to a particular
+board. There's no solution to this problem for now: you'll have to
+just plug in the Maples one at a time. If this is a real problem let
+us know and we'll see if we can come up with a better solution.
+
+My flash programs don't seem to stick; they behave like they are RAM!
+---------------------------------------------------------------------
+
+If you have uploaded a program to RAM, this will take priority over
+any program subsequently uploaded to flash. We'll be removing this
+bug in a later version of the bootloader. For now, you can fix this
+by unplugging your Maple to clear the contents of RAM, then plugging
+it back in.
+
+If you are using the :ref:`Unix toolchain <unix-toolchain>`, Make sure
+you :command:`make clean` when switching between FLASH and RAM
+targets; :command:`make` isn't smart enough to rebuild everything that
+needs to be for the new target.
+
+.. _troubleshooting-shell:
+
+=====================
+ Command-line issues
+=====================
+
+[Linux] ``cdc_acm 3-1:1.0: no more free acm devices``
+-----------------------------------------------------
+
+This is a nasty one! It means that all 32 possible CDC_ACM serial
+devices (:file:`/dev/ttyACM25`, etc.) have been used up.
+
+The usual cause is using a serial port monitor and not closing it
+before restarting the Maple or uploading a new program. The operating
+system doesn't like that, and locks up that device. After reset the
+Maple comes back up as a new device. If you develop heavily and don't
+restart you'll blow right through all 32 devices.
+
+The lazy solution is to always close the monitor before restarting,
+and if you get this error in :file:`dmesg` after a dfu-util "Not
+Found" error, restart you machine.
+
+The hacker solution is to restart your cdc_acm kernel module. On
+Ubuntu 09.10, this goes a little something like::
+
+ $ sudo rmmod cdc-acm
+ $ sudo insmod /lib/modules/2.6.31-20-generic/kernel/drivers/usb/class/cdc-acm.ko
+
+.. _troubleshooting-tips-tricks:
+
+=================
+ Tips and Tricks
+=================
+
+.. _troubleshooting-perpetual-bootloader:
+
+Perpetual Bootloader Mode
+-------------------------
+
+In this mode, Maple stays a DFU device and does not jump to user code
+until the next reset. This is useful for guaranteeing that your Maple
+will be available for reprogramming.
+
+To put your Maple into perpetual bootloader mode:
+
+#. Plug your Maple into the USB port.
+
+#. Hit the reset button on your Maple (it's the small button at the
+ bottom left, labeled RESET). Notice that it blinks quickly 6
+ times, then blinks slowly a few more times.
+
+#. Hit reset again, and this time push and hold the other button
+ during the 6 fast blinks (the button is on the top right; it is
+ labeled BUT). You can release it once the slow blinks start.
+
diff --git a/docs/source/unix-toolchain.rst b/docs/source/unix-toolchain.rst
new file mode 100644
index 0000000..836f777
--- /dev/null
+++ b/docs/source/unix-toolchain.rst
@@ -0,0 +1,423 @@
+.. highlight:: sh
+
+.. _unix-toolchain:
+
+===========================
+ Unix Toolchain Quickstart
+===========================
+
+This is a tutorial for using the Maple with a standard Unix toolchain.
+It's not necessary to do this in order to program the Maple; you can
+always :ref:`install the Maple IDE <maple-ide-install>` instead.
+
+You'll need a Maple board, a mini-b USB cable, a functional computer,
+and root access to that computer. This guide assumes you've had
+success with the IDE on your machine and that you are fairly
+comfortable with the Unix command line; some previous experience with
+editing your shell startup script (.bashrc, .tcshrc, etc.) and using
+`make <http://www.gnu.org/software/make/>`_ is recommended. For
+generic installation/setup issues, the :ref:`IDE installation
+<maple-ide-install>` and :ref:`troubleshooting` pages may be
+helpful. If all else fails, try our `forum`_, or `contact us
+directly`_\ !
+
+We currently have instructions for 32- and 64-bit Linux and OS X Snow
+Leopard. If you're on another Unix platform, Windows, or an earlier
+version of OS X, we're guessing that you can translate/port these
+directions on your own. As a jumping off point, you might want to
+begin with these `stripped down distributions
+<http://static.leaflabs.com/pub/codesourcery/>`_ of the `CodeSourcery
+GCC compiler tools <http://www.codesourcery.com/sgpp/features.html>`_
+(including Win32 versions). If you do have success on other platforms,
+please post in the forums, so we can fold your tips into this
+document!
+
+.. contents:: Contents
+ :local:
+
+.. _toolchain-linux-setup:
+
+Setup
+-----
+
+Linux
+^^^^^
+
+These instructions are oriented towards Linux users using a
+contemporary Debian-based distribution.
+
+**1. Collect and Install Tools**
+
+First I'll give the commands to run, then explain::
+
+ $ sudo aptitude install build-essential git-core wget screen dfu-util \
+ openocd python python-serial
+
+You'll want to install a bunch of developer "basics" like
+:command:`make`, :command:`tar`, etc. A good catch-all for these
+tools is the "build-essential" meta-package on most Debian platforms:
+installing this fake package will pull in dozens of useful tools
+without bogging your system down too much. ``git-core`` is the name of
+the git package; `Git <http://git-scm.com/>`_ is a distributed code
+versioning system we use to track changes in our source
+code. :command:`wget` is a simple tool to download files over http
+from the command line, and is optional (you could pull in the required
+downloads using a browser). :command:`screen` is a really cool virtual
+terminal program; in the context of Maple, we use it to connect to
+serial port devices.
+
+:command:`dfu-util` is a tool from the `OpenMoko`_ project that we use
+to upload programs to the Maple over USB.
+
+.. _OpenMoko: http://openmoko.com/
+
+:command:`openocd` is a `JTAG
+<http://en.wikipedia.org/wiki/Joint_Test_Action_Group>`_ control
+program used in conjunction with an ARM JTAG device to do in circuit
+debugging (pause/resume program execution, upload and download code,
+read out register status, etc). (optional)
+
+Lastly, our reset script (which sends control signals over the
+USB-serial connection to restart and enter the bootloader) is written
+in Python and requires the `PySerial
+<http://pyserial.sourceforge.net/>`_ library (the ``python-serial``
+package; this could also be installed with `easy_install
+<http://peak.telecommunity.com/DevCenter/EasyInstall>`_).
+
+**2. Fetch libmaple and Compiler Toolchain** ::
+
+ $ cd ~
+ $ git clone git://github.com/leaflabs/libmaple.git libmaple
+ $ cd libmaple
+ $ wget http://static.leaflabs.com/pub/codesourcery/gcc-arm-none-eabi-latest-linux32.tar.gz
+ $ tar xvf gcc-arm-none-eabi-latest-linux32.tar.gz
+ $ export PATH=$PATH:~/libmaple/arm/bin # or wherever these tools ended up
+
+This step is fairly straightforward: do a git clone of the `libmaple
+repository <http://github.com/leaflabs/libmaple>`_ to some directory,
+then download and extract the ARM compiler toolchain.
+
+The :file:`arm/bin/` directory will need to be added to ``PATH``; you
+can check that this worked by entering ``arm-none-`` and hitting tab
+to auto-complete (bash should show a bunch of results). Regardless of
+where you put the toolchain, make sure to preserve its internal
+directory layout, as the binaries make relative path calls and
+references.
+
+After you're done, you'll probably want to update your shell startup
+script so :file:`~/libmaple/arm/bin` stays in your ``PATH``.
+
+.. _toolchain-udev:
+
+**3. Install udev Rules**
+
+From the libmaple directory, ::
+
+ $ groups # make sure it includes plugdev; if not add, yourself to it
+ $ sudo cp support/scripts/45-maple.rules /etc/udev/rules.d/45-maple.rules
+ $ sudo /etc/init.d/udev restart
+
+As a security precaution on linux, unknown USB devices can only be
+accessed by the superuser. This udev script identifies the Maple based
+on its vendor and product IDs, mounts it to :file:`/dev/maple`, and
+grants read/write permissions to the ``plugdev`` group. After
+restarting :command:`udev` you'll need to fully unplug or power cycle
+any Maples connected to the computer.
+
+**So far, so good?**
+
+Great! Test your setup by :ref:`compiling a sample program
+<toolchain-test>`.
+
+.. _toolchain-osx-setup:
+
+OS X
+^^^^
+
+These instructions have been tested successfully on OS X 10.6.4. As
+stated previously, this document assumes a general level of Unix
+aptitude on the part of the reader; if you're uncomfortable using
+Terminal (or if you don't know what that means), then you should
+probably stick with using the `Maple IDE
+<http://leaflabs.com/docs/maple-ide/>`_ to develop programs.
+
+**1. Collect and Install Tools**
+
+You will need the following tools\ [#fmacports]_ to get started:
+
+ 1. `XCode <http://developer.apple.com/technologies/xcode.html>`_: If
+ you're reading this, you've probably already got this. Provides
+ compilers and other basic tools of the trade. It's a free download,
+ but requires registration (gross, we know).
+
+ 2. `Git <http://git-scm.com/>`_: All of our code is tracked by a
+ distributed versioning system called git. A `Mac installer
+ <http://code.google.com/p/git-osx-installer/downloads/list?can=3>`_
+ is available.
+
+ 3. :command:`dfu-util`: A tool from `OpenMoko`_ that we use to upload
+ programs to the Maple over USB. If you're feeling masochistic, there
+ are instructions for `building dfu-util from source
+ <http://wiki.openmoko.org/wiki/Dfu-util#Mac>`_.
+
+ However, if you've got better things to do, you can steal a dfu-util
+ binary from a program called `Openmoko Flasher
+ <http://www.handheld-linux.com/wiki.php?page=Openmoko%20Flasher>`_. To
+ do this, first `download Openmoko Flasher
+ <http://projects.goldelico.com/p/omflasher/downloads/>`_, then copy
+ the .app into your :file:`/Applications` folder (or wherever you
+ like). Let's pretend you saved the .app to the directory
+
+ :file:`/Applications/OpenMoko Flasher.app`
+
+ Then the :command:`dfu-util` binary resides in
+
+ :file:`/Applications/OpenMoko Flasher.app/Contents/Mac OS/dfu-util`
+
+ To get access to it from the command line, just make a symbolic link
+ to the binary from some place on your ``PATH``::
+
+ $ ln -s /Applications/OpenMoko\ Flasher.app/Contents/Mac\ OS/dfu-util \
+ /somewhere/on/your/PATH/dfu-util
+
+ .. note::
+ Just copying the binary somewhere doesn't work, as it relies on
+ dynamically linked libraries found elsewhere in the .app
+ bundle. It's possible to pull just the relevant pieces out of the
+ .app, but you're on your own.
+
+ To make sure this worked, try plugging in your Maple, making sure
+ it's in bootloader mode (you can do this by pressing RESET, then
+ quickly pressing BUT and holding it for several seconds), then
+ running ::
+
+ $ dfu-util -l
+
+ If you see some lines that look like ::
+
+ Found DFU: [0x1eaf:0x0003] devnum=0, cfg=0, intf=0, alt=0, name="DFU Program RAM 0x20000C00"
+ Found DFU: [0x1eaf:0x0003] devnum=0, cfg=0, intf=0, alt=1, name="DFU Program FLASH 0x08005000"
+
+ then you're all set.
+
+ 4. PySerial: our reset script (which sends control signals over the
+ USB-serial connection to restart and enter the bootloader) is written
+ in Python and requires the `PySerial
+ <http://pyserial.sourceforge.net/>`_ library. Download the `latest
+ version <http://pypi.python.org/pypi/pyserial>`_. After you download
+ and untar, install it with ::
+
+ $ cd /path/to/pyserial-x.y
+ $ python setup.py build
+ $ sudo python setup.py install
+
+ The package is also available via :command:`easy_install`, so if
+ you're comfortable using that, you could also install it with ::
+
+ $ easy_install pyserial
+
+**2. Fetch libmaple and Compiler Toolchain**
+
+You first need to clone libmaple::
+
+ $ cd ~
+ $ git clone git://github.com/leaflabs/libmaple.git libmaple
+
+Then you need to get the cross-compilers we use to build a
+project. These are just modified versions of GCC; you can `download
+them for OS X here
+<http://static.leaflabs.com/pub/codesourcery/gcc-arm-none-eabi-latest-osx32.tar.gz>`_. Assuming
+you saved this file to
+
+ :file:`~/Downloads/gcc-blah-blah-osx32.tar.gz`
+
+you can then unpack the archive and let OS X know where the compilers
+live with ::
+
+ $ cd ~/Downloads
+ $ tar -xvzf gcc-blah-blah-macosx32.tar.gz
+ $ mv arm ~/libmaple/arm
+ $ export PATH=$PATH:~/libmaple/arm/bin
+
+After that's done, you'll probably want to update your shell startup
+script so :file:`~/libmaple/arm/bin` stays in your ``PATH``.
+
+**So far, so good?**
+
+Great! Go on to the next section, where you test everything out.
+
+.. _toolchain-test:
+
+Test compilation
+----------------
+
+Get back into the libmaple directory (this tutorial assumes you put it
+in :file:`~/libmaple`) and test that you've installed all the compilation
+tools correctly::
+
+ $ cd ~/libmaple
+ $ cp main.cpp.example main.cpp
+ $ make clean
+ $ make
+
+If it all works out, you should end up seeing something like this::
+
+ find build -iname *.o | xargs arm-none-eabi-size -t
+ text data bss dec hex filename
+ 482 4 24 510 1fe build/wirish/comm/HardwareSerial.o
+ 260 0 0 260 104 build/wirish/comm/HardwareSPI.o
+ 60 0 0 60 3c build/wirish/wirish.o
+
+ [...]
+
+ 2196 0 1 2197 895 build/libmaple/usb/usb_lib/usb_core.o
+ 1904 0 0 1904 770 build/libmaple/usb/usb_lib/usb_regs.o
+ 56 0 0 56 38 build/libmaple/usb/usb_lib/usb_init.o
+ 344 0 0 344 158 build/libmaple/usb/usb_hardware.o
+ 6637 0 58 6695 1a27 build/main.o
+ 21499 201 391 22091 564b (TOTALS)
+
+ Final Size:
+ arm-none-eabi-size build/maple.out
+ text data bss dec hex filename
+ 21824 200 552 22576 5830 build/maple.out
+ Flash build
+
+Woo! It worked. The ``dec`` field at the end gives the total program
+size in bytes. The long listing of object files above the ``Final
+Size`` helps to identify bloated code. As you write larger projects,
+you may find that they use too much space. If that happens, the
+file-by-file listing will help you track down the fatties porking up
+your program.
+
+.. _toolchain-upload:
+
+Upload a program
+----------------
+
+Ok, let's blow away the little example program and upload the
+interactive test session to your Maple. This will let you interact
+textually with the Maple via USB-serial. If you're on Linux, then
+before executing :command:`make install`, you'll want to have the udev
+rules setup :ref:`as described above <toolchain-udev>`. Plug in your Maple
+using the mini-b USB cable; then run ::
+
+ $ cd ~/libmaple
+ $ cp examples/test-session.cpp main.cpp
+ $ make clean
+ $ make
+ $ make install
+
+A number of things can go wrong at this stage. Simple debugging steps
+include using :ref:`perpetual bootloader mode
+<troubleshooting-perpetual-bootloader>`, restarting the Maple a couple
+times, :command:`make clean`, etc. If nothing works, the `forum`_ is
+your friend.
+
+.. _toolchain-serialusb:
+
+Communicate over USB-serial interface
+-------------------------------------
+
+Okay, now that we've flashed the interactive test session to the
+Maple, let's test it out. The device for the maple should look
+something like :file:`/dev/ttyACMXXX` on Linux or
+:file:`/dev/tty.usbmodemXXX` on OS X, but it might have a slightly
+different name on your system. To open up a session, run ::
+
+ $ screen /dev/ttyXXX
+
+If the interactive test program built and uploaded correctly, you
+should be able to connect without any errors reported by
+:command:`screen`. Type ``h`` or hit the space bar to get a response;
+there are a number of commands which demonstrate Maple peripheral
+features. As of October 2010, the HardwareSerial library is blocking,
+so using any commands which would write to the USART Serial ports will
+cause the program to hang. To exit the screen session, type :kbd:`C-a
+C-\\` (control-a, followed by control-backslash) on Mac, or :kbd:`C-a
+k` (control-a k) on Linux, and type ``y`` when prompted if you're
+sure.
+
+.. note::
+
+ Using :command:`screen` in this way sometimes messes up your
+ terminal session on OS X. If your shell starts acting up after you
+ exit screen, you should be able to fix it with ::
+
+ $ reset && clear
+
+.. _toolchain-projects:
+
+Starting your own projects
+--------------------------
+
+.. TODO fix the build-targets.mk mess, note the "library" target
+
+So everything worked, and you want to start your own project? Great!
+It's easy. Just set the environment variable ``LIB_MAPLE_HOME`` in
+your shell startup script to point to the libmaple repository you
+cloned (this tutorial assumes you put it in :file:`~/libmaple`). For
+example, if you use bash as your shell, just put this line in your
+:file:`~/.bashrc` or :file:`~/.bash_profile`::
+
+ export LIB_MAPLE_HOME=~/libmaple
+
+Now, in order to start your own projects, just grab a copy of the
+:file:`Makefile` and skeleton :file:`main.cpp` we provided in the
+libmaple repository, and you're good to go::
+
+ $ cd
+ $ mkdir my-awesome-project
+ $ cp ~/libmaple/Makefile ~/libmaple/build-targets.mk my-awesome-project
+ $ cp ~/libmaple/main.cpp.example my-awesome-project/main.cpp
+
+(TEMPORARY: The file :file:`build-targets.mk` is where the rule to
+build the object file for :file:`main.cpp` lives. If you have multiple
+source files, you'll probably need to look at it and edit as
+appropriate. We're sorry about that and will update the Makefile
+structure later to remove this pain point.) Then hack away! You can
+:command:`make`, :command:`make clean`, and :command:`make install`
+from your new directory :file:`my-awesome-project` just like you did
+in the libmaple repository.
+
+.. note::
+
+ We update the libmaple repository fairly frequently with bugfixes
+ and other improvements. In order get access to these in your local
+ copy of the repository, you should periodically update it with::
+
+ $ cd $LIB_MAPLE_HOME
+ $ git pull
+
+ The `commits page
+ <http://github.com/leaflabs/libmaple/commits/master>`_ for the
+ github repository is a good place to watch for bleeding-edge
+ updates; our `blog <http://leaflabs.com/blog/>`_ is the place to
+ watch for major releases. We keep releases of libmaple and the
+ Maple IDE in lockstep, so any IDE updates will have corresponding
+ library updates.
+
+.. _toolchain-openocd:
+
+Debug with OpenOCD
+------------------
+
+TODO. For now see `this great guide
+<http://fun-tech.se/stm32/OpenOCD/index.php>`_ from fun-tech.se, and
+the ``jtag`` Makefile target.
+
+.. _toolchain-exuberantly:
+
+Go forth exuberantly!
+---------------------
+
+Let us know what you come up with! Use #leaflabs on Twitter, post in
+the `forum`_, track us down in the real world, whatever. We love
+projects!
+
+.. rubric:: Footnotes
+
+.. [#fmacports] Some of these software packages might be available on
+ `MacPorts <http://www.macports.org/>`_. The author had some bad
+ experiences with MacPorts a few years ago, though, and hasn't
+ touched it since. Of course, your mileage may vary.
diff --git a/docs/source/usart.rst b/docs/source/usart.rst
new file mode 100644
index 0000000..3beb3fc
--- /dev/null
+++ b/docs/source/usart.rst
@@ -0,0 +1,34 @@
+.. _usart:
+
+=======
+ USART
+=======
+
+.. contents::
+ :local:
+
+Hardware/Circuit Design
+-----------------------
+
+The Maple has 3 separate USART devices. 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. Their usage is
+documented in the :ref:`Serial Ports <lang-serial>` language reference
+page.
+
+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.
+
+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:
+
+ * `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/docs/source/usb.rst b/docs/source/usb.rst
new file mode 100644
index 0000000..f502f31
--- /dev/null
+++ b/docs/source/usb.rst
@@ -0,0 +1,45 @@
+.. highlight:: cpp
+
+.. _usb:
+
+=====
+ USB
+=====
+
+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). Library
+support for accessing the emulated terminal is available at the
+:ref:`SerialUSB <lang-serialusb>` reference.
+
+The SerialUSB channel is used as part of the auto-reset feature of the
+IDE to program the board on Maple Rev 3 and Rev 5: 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
+:ref:`SerialUSB.end() <lang-serialusb-end>`). A solution to the
+second problem is the use of :ref:`perpetual bootloader mode
+<troubleshooting-perpetual-bootloader>`.
+
+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:
+
+ * `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)
diff --git a/examples/blinky.cpp b/examples/blinky.cpp
index 45c4528..5611987 100644
--- a/examples/blinky.cpp
+++ b/examples/blinky.cpp
@@ -2,16 +2,19 @@
#include "wirish.h"
-#define TEST_PIN 13
+// Use the pin attached to the built-in LED
+#define PIN BOARD_LED_PIN
void setup() {
- pinMode(TEST_PIN, OUTPUT);
+ pinMode(PIN, OUTPUT);
}
int toggle = 1;
void loop() {
- digitalWrite(TEST_PIN, toggle);
+ // You could just use toggleLED() instead, but this illustrates
+ // the use of digitalWrite():
+ digitalWrite(PIN, toggle);
toggle ^= 1;
delay(100);
}
@@ -22,8 +25,7 @@ void loop() {
init();
}
-int main(void)
-{
+int main(void) {
setup();
while (1) {
diff --git a/examples/test-session.cpp b/examples/test-session.cpp
index bfc1e58..845547d 100644
--- a/examples/test-session.cpp
+++ b/examples/test-session.cpp
@@ -7,46 +7,79 @@
#include "wirish.h"
-#define LED_PIN 13
-#define PWM_PIN 2
+#define LED_PIN BOARD_LED_PIN
+#define PWM_PIN 3
// choose your weapon
#define COMM SerialUSB
//#define COMM Serial2
+//#define COMM Serial3
+
+
+#define ESC ((uint8)27)
-uint8 input = 0;
-uint8 tiddle = 0;
-int toggle = 0;
int rate = 0;
-int sample = 0;
-// read these off maple board rev3
-// note that 38 is just a button and 39+ aren't functional as of 04/22/2010
-const uint8 pwm_pins[] = {0,1,2,3,5,6,7,8,9,11,12,14,24,25,27,28};
-const uint8 adc_pins[] = {0,1,2,10,11,12,13,15,16,17,18,19,20,27,28};
-#define NUM_GPIO 44 // 44 is the MAX
-uint8 gpio_state[NUM_GPIO];
+#if defined(BOARD_maple)
+const uint8 pwm_pins[] =
+ {0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 25, 27, 28};
+const uint8 adc_pins[] =
+ {0, 1, 2, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 27, 28};
+
+#elif defined(BOARD_maple_mini)
+const uint8 pwm_pins[] = {3, 4, 5, 8, 9, 10, 11, 15, 16, 25, 26, 27};
+const uint8 adc_pins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 33}; // NB: 33 is LED
+
+#elif defined(BOARD_maple_native)
+const uint8 pwm_pins[] = {12, 13, 14, 15, 22, 23, 24, 25, 37, 38, 45,
+ 46, 47, 48, 49, 50, 53, 54};
+const uint8 adc_pins[] = {6, 7, 8, 9, 10, 11,
+ /* the following are on ADC3, which lacks support:
+ 39, 40, 41, 42, 43, 45, */
+ 46, 47, 48, 49, 50, 51, 52, 53, 54};
+
+#else
+#error "Board type has not been selected correctly"
-#define DUMMY_DAT "qwertyuiopasdfghjklzxcvbnmmmmmm,./1234567890-=qwertyuiopasdfghjklzxcvbnm,./1234567890"
+#endif
-void print_help(void);
-void do_noise(uint8 pin);
-void do_everything(void);
-void do_fast_gpio(void);
+uint8 gpio_state[NR_GPIO_PINS];
+
+const char* const dummy_dat = ("qwertyuiopasdfghjklzxcvbnmmmmmm,./1234567890-="
+ "qwertyuiopasdfghjklzxcvbnm,./1234567890");
+
+void cmd_print_help(void);
+void cmd_adc_stats(void);
+void cmd_stressful_adc_stats(void);
+void cmd_everything(void);
+void cmd_serial1_serial3(void);
+void cmd_gpio_monitoring(void);
+void cmd_sequential_adc_reads(void);
+void cmd_gpio_qa(void);
+void cmd_sequential_gpio_writes(void);
+void cmd_gpio_toggling(void);
+void cmd_sequential_pwm_test(void);
+void cmd_pwm_sweep(void);
+void cmd_servo_sweep(void);
+
+void measure_adc_noise(uint8 pin);
+void fast_gpio(int pin);
+void do_serials(HardwareSerial **serials, int n, unsigned baud);
+void init_all_timers(uint16 prescale);
void setup() {
- /* Set up the LED to blink */
- pinMode(LED_PIN, OUTPUT);
+ // Set up the LED to blink
+ pinMode(BOARD_LED_PIN, OUTPUT);
- /* Start up the serial ports */
+ // Start up the serial ports
Serial1.begin(9600);
Serial2.begin(9600);
Serial3.begin(9600);
- /* Send a message out over COMM interface */
+ // Send a message out over COMM interface
COMM.println(" ");
COMM.println(" __ __ _ _");
- COMM.println(" | \\/ | __ _ _ __ | | ___| |");
+ COMM.println(" | \\/ | __ _ _ __ | | ___| |");
COMM.println(" | |\\/| |/ _` | '_ \\| |/ _ \\ |");
COMM.println(" | | | | (_| | |_) | | __/_|");
COMM.println(" |_| |_|\\__,_| .__/|_|\\___(_)");
@@ -55,409 +88,169 @@ void setup() {
COMM.println("");
COMM.println("");
COMM.println("Maple interactive test program (type '?' for help)");
- COMM.println("------------------------------------------------------------");
+ COMM.println("----------------------------------------------------------");
COMM.print("> ");
}
-void loop() {
- toggle ^= 1;
- digitalWrite(LED_PIN, toggle);
+void loop () {
+ toggleLED();
delay(100);
while(COMM.available()) {
- input = COMM.read();
+ uint8 input = COMM.read();
COMM.println(input);
+
switch(input) {
- case 13: // Carriage Return
- break;
- case 32: // ' '
- COMM.println("spacebar, nice!");
- break;
- case 63: // '?'
- case 104: // 'h'
- print_help();
- break;
- case 117: // 'u'
- SerialUSB.println("Hello World!");
- break;
- case 119: // 'w'
- Serial1.println("Hello World!");
- Serial2.println("Hello World!");
- Serial3.println("Hello World!");
- break;
- case 109: // 'm'
- COMM.println("Testing 57600 baud on USART1 and USART3. Press enter.");
- Serial1.begin(57600);
- Serial3.begin(57600);
- while(!COMM.available()) {
- Serial1.println(DUMMY_DAT);
- Serial3.println(DUMMY_DAT);
- if(Serial1.available()) {
- Serial1.println(Serial1.read());
- delay(1000);
- }
- if(Serial3.available()) {
- Serial3.println(Serial3.read());
- delay(1000);
- }
- }
- COMM.read();
- COMM.println("Testing 115200 baud on USART1 and USART3. Press enter.");
- Serial1.begin(115200);
- Serial3.begin(115200);
- while(!COMM.available()) {
- Serial1.println(DUMMY_DAT);
- Serial3.println(DUMMY_DAT);
- if(Serial1.available()) {
- Serial1.println(Serial1.read());
- delay(1000);
- }
- if(Serial3.available()) {
- Serial3.println(Serial3.read());
- delay(1000);
- }
- }
- COMM.read();
- COMM.println("Testing 9600 baud on USART1 and USART3. Press enter.");
- Serial1.begin(9600);
- Serial3.begin(9600);
- while(!COMM.available()) {
- Serial1.println(DUMMY_DAT);
- Serial3.println(DUMMY_DAT);
- if(Serial1.available()) {
- Serial1.println(Serial1.read());
- delay(1000);
- }
- if(Serial3.available()) {
- Serial3.println(Serial3.read());
- delay(1000);
- }
- }
- COMM.read();
- COMM.println("Resetting USART1 and USART3...");
- Serial1.begin(9600);
- Serial3.begin(9600);
- break;
- case 46: // '.'
- while(!COMM.available()) {
- Serial1.print(".");
- Serial2.print(".");
- Serial3.print(".");
- SerialUSB.print(".");
- }
- break;
- case 110: // 'n'
- COMM.println("Taking ADC noise stats...");
- // turn off LED
- digitalWrite(LED_PIN, 0);
- // make sure to skip the TX/RX headers
- for(uint32 i = 2; i<sizeof(adc_pins); i++) {
- delay(5);
- do_noise(adc_pins[i]);
- }
- break;
- case 78: // 'N'
- COMM.println("Taking ADC noise stats under duress...");
- // turn off LED
- digitalWrite(LED_PIN, 0);
- // make sure to skip the TX/RX headers
- for(uint32 i = 2; i<sizeof(adc_pins); i++) {
- // spool up PWM
- for(uint32 j = 2; j<(uint32)sizeof(pwm_pins); j++) {
- if(adc_pins[i] != pwm_pins[j]) {
- pinMode(pwm_pins[j],PWM);
- pwmWrite(pwm_pins[j], 1000 + i);
- }
- }
- SerialUSB.print(DUMMY_DAT);
- SerialUSB.print(DUMMY_DAT);
- do_noise(adc_pins[i]);
- for(uint32 j = 2; j<(uint32)sizeof(pwm_pins); j++) {
- if(adc_pins[i] != pwm_pins[j]) {
- pinMode(pwm_pins[j],OUTPUT);
- digitalWrite(pwm_pins[j],0);
- }
- }
- }
- break;
- case 101: // 'e'
- do_everything();
- break;
- case 87: // 'W'
- while(!COMM.available()) {
- Serial1.print(DUMMY_DAT);
- Serial2.print(DUMMY_DAT);
- Serial3.print(DUMMY_DAT);
- }
- break;
- case 85: // 'U'
- COMM.println("Dumping data to USB. Press enter.");
- while(!COMM.available()) {
- SerialUSB.print(DUMMY_DAT);
- }
- break;
- case 103: // 'g'
- COMM.print("Sequentially testing GPIO write on all possible headers except D0 and D1.");
- COMM.println("Anything for next, ESC to stop.");
- // turn off LED
- digitalWrite(LED_PIN, 0);
- // make sure to skip the TX/RX headers
- for(uint32 i = 2; i<NUM_GPIO; i++) {
- COMM.print("GPIO write out on header D");
- COMM.print(i, DEC);
- COMM.println("...");
- pinMode(i, OUTPUT);
- digitalWrite(i, tiddle);
- while(!COMM.available()) {
- tiddle ^= 1;
- digitalWrite(i, tiddle);
- }
- digitalWrite(i, 0);
- if((uint8)COMM.read() == (uint8)27) break; // ESC
- }
- break;
- case 71: // 'G'
- COMM.println("Flipping all GPIOs at the same time. Press enter.");
- // turn off LED
- digitalWrite(LED_PIN, 0);
- // make sure to skip the TX/RX headers
- for(uint32 i = 2; i<NUM_GPIO; i++) {
- pinMode(i, OUTPUT);
- }
- while(!COMM.available()) {
- tiddle ^= 1;
- for(uint32 i = 2; i<NUM_GPIO; i++) {
- digitalWrite(i, tiddle);
- }
- }
- for(uint32 i = 2; i<NUM_GPIO; i++) {
- digitalWrite(i, 0);
- }
- if((uint8)COMM.read() == (uint8)27) break; // ESC
- break;
- case 102: // 'f'
- COMM.println("Wiggling GPIO header D4 as fast as possible in bursts. Press enter.");
- pinMode(4,OUTPUT);
- while(!COMM.available()) {
- do_fast_gpio();
- delay(1);
- }
- break;
- case 112: // 'p'
- COMM.println("Sequentially testing PWM on all possible headers except D0 and D1. ");
- COMM.println("Anything for next, ESC to stop.");
- // turn off LED
- digitalWrite(LED_PIN, 0);
- // make sure to skip the TX/RX headers
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- COMM.print("PWM out on header D");
- COMM.print(pwm_pins[i], DEC);
- COMM.println("...");
- pinMode(pwm_pins[i], PWM);
- pwmWrite(pwm_pins[i], 16000);
- while(!COMM.available()) { delay(10); }
- pinMode(pwm_pins[i], OUTPUT);
- digitalWrite(pwm_pins[i], 0);
- if((uint8)COMM.read() == (uint8)27) break; // ESC
- }
- break;
- case 80: // 'P'
- COMM.println("Testing all PWM ports with a sweep. Press enter.");
- // turn off LED
- digitalWrite(LED_PIN, 0);
- // make sure to skip the TX/RX pins
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- pinMode(pwm_pins[i], PWM);
- pwmWrite(pwm_pins[i], 4000);
- }
- while(!COMM.available()) {
- rate += 20;
- if(rate > 65500) rate = 0;
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- pwmWrite(pwm_pins[i], rate);
- }
- delay(1);
- }
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- pinMode(pwm_pins[i], OUTPUT);
- }
- break;
- case 95: // '_'
- COMM.println("Delaying for 5 seconds...");
- delay(5000);
- break;
- case 116: // 't'
- break;
- case 84: // 'T'
- break;
- case 115: // 's'
- COMM.println("Testing all PWM headers with a servo sweep. Press enter.");
- COMM.println("");
- // turn off LED
- digitalWrite(LED_PIN, 0);
- timer_init(1, 21);
- timer_init(2, 21);
- timer_init(3, 21);
- timer_init(4, 21);
- // make sure to skip the TX/RX headers
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- pinMode(pwm_pins[i], PWM);
- pwmWrite(pwm_pins[i], 4000);
- }
- // 1.25ms = 4096counts = 0deg
- // 1.50ms = 4915counts = 90deg
- // 1.75ms = 5734counts = 180deg
- rate = 4096;
- while(!COMM.available()) {
- rate += 20;
- if(rate > 5734) rate = 4096;
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- pwmWrite(pwm_pins[i], rate);
- }
- delay(20);
- }
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- pinMode(pwm_pins[i], OUTPUT);
- }
- timer_init(1, 1);
- timer_init(2, 1);
- timer_init(3, 1);
- timer_init(4, 1);
- Serial2.begin(9600);
- COMM.println("(reset serial port)");
- break;
- case 100: // 'd'
- COMM.println("Pulling down D4, D22");
- pinMode(22,INPUT_PULLDOWN);
- pinMode(4,INPUT_PULLDOWN);
- while(!COMM.available()) {
- delay(1);
- }
- COMM.read();
- COMM.println("Pulling up D4, D22");
- pinMode(22,INPUT_PULLUP);
- pinMode(4,INPUT_PULLUP);
- while(!COMM.available()) {
- delay(1);
- }
- COMM.read();
- pinMode(4,OUTPUT);
- break;
- case 105: // 'i'
- break;
- case 73: // 'I'
- break;
- case 114: // 'r'
- COMM.println("Monitoring GPIO read state changes. Press enter.");
- // turn off LED
- digitalWrite(LED_PIN, 0);
- // make sure to skip the TX/RX headers
- for(int i = 2; i<NUM_GPIO; i++) {
- pinMode(i, INPUT_PULLDOWN);
- gpio_state[i] = (uint8)digitalRead(i);
- }
- while(!COMM.available()) {
- for(int i = 2; i<NUM_GPIO; i++) {
- tiddle = (uint8)digitalRead(i);
- if(tiddle != gpio_state[i]) {
- COMM.print("State change on header D");
- COMM.print(i,DEC);
- if(tiddle) COMM.println(":\tHIGH");
- else COMM.println(":\tLOW");
- gpio_state[i] = tiddle;
- }
- }
- }
- for(int i = 2; i<NUM_GPIO; i++) {
- pinMode(i, OUTPUT);
- }
- break;
- case 97: // 'a'
- COMM.print("Sequentially reading each ADC port.");
- COMM.println("Anything for next, ESC to stop.");
- // turn off LED
- digitalWrite(LED_PIN, 0);
- // make sure to skip the TX/RX headers
- for(uint32 i = 2; i<sizeof(adc_pins); i++) {
- COMM.print("Reading on header D");
- COMM.print(adc_pins[i], DEC);
- COMM.println("...");
- pinMode(adc_pins[i], INPUT_ANALOG);
- while(!COMM.available()) {
- sample = analogRead(adc_pins[i]);
- COMM.print(adc_pins[i],DEC);
- COMM.print("\t");
- COMM.print(sample,DEC);
- COMM.print("\t");
- COMM.print("|");
- for(int j = 0; j<4096; j+= 100) {
- if(sample >= j) COMM.print("#");
- else COMM.print(" ");
- }
- COMM.print("| ");
- for(int j = 0; j<12; j++) {
- if(sample & (1 << (11-j))) COMM.print("1");
- else COMM.print("0");
- }
- COMM.println("");
- }
- pinMode(adc_pins[i], OUTPUT);
- digitalWrite(adc_pins[i], 0);
- if((uint8)COMM.read() == (uint8)27) break; // ESC
- }
- break;
- case 43: // '+'
- COMM.println("Doing QA testing for 37 GPIO pins...");
- // turn off LED
- digitalWrite(LED_PIN, 0);
- for(int i = 0; i<NUM_GPIO; i++) {
- pinMode(i, INPUT);
- gpio_state[i] = 0; //(uint8)digitalRead(i);
- }
- COMM.println("Waiting to start...");
- while(digitalRead(0) != 1 && !COMM.available()) {
- continue;
- }
- for(int i=0; i<38; i++) {
- if(i==13) {
- COMM.println("Not Checking D13 (LED)");
- continue;
- }
- COMM.print("Checking D");
- COMM.print(i,DEC);
- while(digitalRead(i) == 0) continue;
- for(int j=0; j<NUM_GPIO; j++) {
- if(digitalRead(j) && j!=i) {
- COMM.print(": FAIL ########################### D");
- COMM.println(j, DEC);
- break;
- }
- }
- while(digitalRead(i) == 1) continue;
- for(int j=0; j<NUM_GPIO; j++) {
- if(digitalRead(j) && j!=i) {
- COMM.print(": FAIL ########################### D");
- COMM.println(j, DEC);
- break;
- }
- }
- COMM.println(": Ok!");
- }
- for(int i = 0; i<NUM_GPIO; i++) {
- pinMode(i, OUTPUT);
- digitalWrite(i, 0);
- }
- break;
- default:
- COMM.print("Unexpected: ");
- COMM.println(input);
+ case '\r':
+ break;
+
+ case ' ':
+ COMM.println("spacebar, nice!");
+ break;
+
+ case '?':
+ case 'h':
+ cmd_print_help();
+ break;
+
+ case 'u':
+ SerialUSB.println("Hello World!");
+ break;
+
+ case 'w':
+ Serial1.println("Hello World!");
+ Serial2.println("Hello World!");
+ Serial3.println("Hello World!");
+ break;
+
+ case 'm':
+ cmd_serial1_serial3();
+ break;
+
+ case '.':
+ while(!COMM.available()) {
+ Serial1.print(".");
+ Serial2.print(".");
+ Serial3.print(".");
+ SerialUSB.print(".");
+ }
+ break;
+
+ case 'n':
+ cmd_adc_stats();
+ break;
+
+ case 'N':
+ cmd_stressful_adc_stats();
+ break;
+
+ case 'e':
+ cmd_everything();
+ break;
+
+ case 'W':
+ while(!COMM.available()) {
+ Serial1.print(dummy_dat);
+ Serial2.print(dummy_dat);
+ Serial3.print(dummy_dat);
+ }
+ break;
+
+ case 'U':
+ COMM.println("Dumping data to USB. Press any key.");
+ while(!COMM.available()) {
+ SerialUSB.print(dummy_dat);
+ }
+ break;
+
+ case 'g':
+ cmd_sequential_gpio_writes();
+ break;
+
+ case 'G':
+ cmd_gpio_toggling();
+ break;
+
+ case 'f':
+ COMM.println("Wiggling D4 as fast as possible in bursts. "
+ "Press any key.");
+ pinMode(4,OUTPUT);
+ while(!COMM.available()) {
+ fast_gpio(4);
+ delay(1);
+ }
+ break;
+
+ case 'p':
+ cmd_sequential_pwm_test();
+ break;
+
+ case 'P':
+ cmd_pwm_sweep();
+ break;
+
+ case '_':
+ COMM.println("Delaying for 5 seconds...");
+ delay(5000);
+ break;
+
+ case 't': // TODO
+ break;
+
+ case 'T': // TODO
+ break;
+
+ case 's':
+ cmd_servo_sweep();
+ break;
+
+ case 'd':
+ COMM.println("Pulling down D4, D22. Press any key.");
+ pinMode(22,INPUT_PULLDOWN);
+ pinMode(4,INPUT_PULLDOWN);
+ while(!COMM.available()) {
+ continue;
+ }
+ COMM.println("Pulling up D4, D22. Press any key.");
+ pinMode(22,INPUT_PULLUP);
+ pinMode(4,INPUT_PULLUP);
+ while(!COMM.available()) {
+ continue;
+ }
+ COMM.read();
+ pinMode(4,OUTPUT);
+ break;
+
+ case 'i': // TODO
+ break;
+
+ case 'I': // TODO
+ break;
+
+ case 'r':
+ cmd_gpio_monitoring();
+ break;
+
+ case 'a':
+ cmd_sequential_adc_reads();
+ break;
+
+ case '+':
+ cmd_gpio_qa();
+ break;
+
+ default: // -------------------------------
+ COMM.print("Unexpected: ");
+ COMM.print(input);
+ COMM.println(", press h for help.");
}
+
COMM.print("> ");
}
}
-void print_help(void) {
+void cmd_print_help(void) {
COMM.println("");
//COMM.println("Command Listing\t(# means any digit)");
COMM.println("Command Listing");
@@ -469,28 +262,29 @@ void print_help(void) {
COMM.println("\ta: show realtime ADC info");
COMM.println("\t.: echo '.' until new input");
COMM.println("\tu: print Hello World on USB");
- COMM.println("\t_: try to do as little as possible for a couple seconds (delay)");
+ COMM.println("\t_: do as little as possible for a couple seconds (delay)");
COMM.println("\tp: test all PWM channels sequentially");
COMM.println("\tW: dump data as fast as possible on all 3 USARTS");
COMM.println("\tU: dump data as fast as possible on USB");
COMM.println("\tg: toggle all GPIOs sequentialy");
COMM.println("\tG: toggle all GPIOs at the same time");
COMM.println("\tf: toggle GPIO D4 as fast as possible in bursts");
- COMM.println("\tP: test all PWM channels at the same time with different speeds/sweeps");
- COMM.println("\tr: read in GPIO status changes and print them in realtime");
- COMM.println("\ts: output a sweeping SERVO PWM on all PWM channels");
- COMM.println("\tm: output serial data dumps on USART1 and USART3 with various rates");
+ COMM.println("\tP: simultaneously test all PWM channels with different "
+ "speeds/sweeps");
+ COMM.println("\tr: Monitor and print GPIO status changes");
+ COMM.println("\ts: output a sweeping servo PWM on all PWM channels");
+ COMM.println("\tm: output data on USART1 and USART3 with various rates");
COMM.println("\t+: test shield mode (for QA, will disrupt Serial2!)");
COMM.println("Unimplemented:");
COMM.println("\te: do everything all at once until new input");
- COMM.println("\tt: output a 1khz squarewave on all GPIOs as well as possible");
- COMM.println("\tT: output a 1hz squarewave on all GPIOs as well as possible");
+ COMM.println("\tt: output a 1khz squarewave on all GPIOs");
+ COMM.println("\tT: output a 1hz squarewave on all GPIOs");
COMM.println("\ti: print out a bunch of info about system state");
COMM.println("\tI: print out status of all headers");
}
-void do_noise(uint8 pin) { // TODO
+void measure_adc_noise(uint8 pin) { // TODO
uint16 data[100];
float mean = 0;
//float stddev = 0;
@@ -512,12 +306,43 @@ void do_noise(uint8 pin) { // TODO
COMM.print("header: D"); COMM.print(pin,DEC);
COMM.print("\tn: "); COMM.print(100,DEC);
COMM.print("\tmean: "); COMM.print(mean);
- COMM.print("\tvar: "); COMM.println(M2/99.0);
+ COMM.print("\tvariance: "); COMM.println(M2/99.0);
pinMode(pin, OUTPUT);
}
-void do_everything(void) { // TODO
- // TODO
+void cmd_adc_stats(void) {
+ COMM.println("Taking ADC noise stats...");
+ digitalWrite(BOARD_LED_PIN, 0);
+ for(uint32 i = 0; i<sizeof(adc_pins); i++) {
+ delay(5);
+ measure_adc_noise(adc_pins[i]);
+ }
+}
+
+void cmd_stressful_adc_stats(void) {
+ COMM.println("Taking ADC noise stats under duress...");
+ digitalWrite(BOARD_LED_PIN, 0);
+ for(uint32 i = 0; i<sizeof(adc_pins); i++) {
+ // spool up PWM
+ for(uint32 j = 2; j<(uint32)sizeof(pwm_pins); j++) {
+ if(adc_pins[i] != pwm_pins[j]) {
+ pinMode(pwm_pins[j],PWM);
+ pwmWrite(pwm_pins[j], 1000 + i);
+ }
+ }
+ SerialUSB.print(dummy_dat);
+ SerialUSB.print(dummy_dat);
+ measure_adc_noise(adc_pins[i]);
+ for(uint32 j = 2; j<(uint32)sizeof(pwm_pins); j++) {
+ if(adc_pins[i] != pwm_pins[j]) {
+ pinMode(pwm_pins[j],OUTPUT);
+ digitalWrite(pwm_pins[j],0);
+ }
+ }
+ }
+}
+
+void cmd_everything(void) { // TODO
// print to usart
// print to usb
// toggle gpios
@@ -525,26 +350,284 @@ void do_everything(void) { // TODO
COMM.println("(unimplemented)");
}
-void do_fast_gpio(void) {
- // header D4 is on port B and is pin 5 on the uC
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
- gpio_write_bit(GPIOB_BASE, 5, 1); gpio_write_bit(GPIOB_BASE, 5, 0);
+void fast_gpio(int maple_pin) {
+ GPIO_Port *port = PIN_MAP[maple_pin].port;
+ uint32 pin = PIN_MAP[maple_pin].pin;
+
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+}
+
+void cmd_serial1_serial3(void) {
+ HardwareSerial *serial_1_and_3[] = {&Serial1, &Serial3};
+
+ COMM.println("Testing 57600 baud on USART1 and USART3. Press any key.");
+ do_serials(serial_1_and_3, 2, 57600);
+ COMM.read();
+
+ COMM.println("Testing 115200 baud on USART1 and USART3. Press any key.");
+ do_serials(serial_1_and_3, 2, 115200);
+ COMM.read();
+
+ COMM.println("Testing 9600 baud on USART1 and USART3. Press any key.");
+ do_serials(serial_1_and_3, 2, 9600);
+ COMM.read();
+
+ COMM.println("Resetting USART1 and USART3...");
+ Serial1.begin(9600);
+ Serial3.begin(9600);
+}
+
+void do_serials(HardwareSerial **serials, int n, unsigned baud) {
+ for (int i = 0; i < n; i++) {
+ serials[i]->begin(9600);
+ }
+ while (!COMM.available()) {
+ for (int i = 0; i < n; i++) {
+ serials[i]->println(dummy_dat);
+ if (serials[i]->available()) {
+ serials[i]->println(serials[i]->read());
+ delay(1000);
+ }
+ }
+ }
+}
+
+void cmd_gpio_monitoring(void) {
+ COMM.println("Monitoring GPIO read state changes. Press any key.");
+ digitalWrite(BOARD_LED_PIN, 0);
+ // make sure to skip the TX/RX headers
+ for(int i = 2; i<NR_GPIO_PINS; i++) {
+ pinMode(i, INPUT_PULLDOWN);
+ gpio_state[i] = (uint8)digitalRead(i);
+ }
+ while(!COMM.available()) {
+ for(int i = 2; i<NR_GPIO_PINS; i++) {
+ uint8 current_state = (uint8)digitalRead(i);
+ if(current_state != gpio_state[i]) {
+ COMM.print("State change on header D");
+ COMM.print(i,DEC);
+ if(current_state) COMM.println(":\tHIGH");
+ else COMM.println(":\tLOW");
+ gpio_state[i] = current_state;
+ }
+ }
+ }
+ for(int i = 2; i<NR_GPIO_PINS; i++) {
+ pinMode(i, OUTPUT);
+ }
}
+void cmd_sequential_adc_reads(void) {
+ COMM.print("Sequentially reading each ADC port.");
+ COMM.println("Press any key for next port, or ESC to stop.");
+ digitalWrite(LED_PIN, 0);
+ // make sure to skip the TX/RX headers
+ for(uint32 i = 2; i<sizeof(adc_pins); i++) {
+ COMM.print("Reading on header D");
+ COMM.print(adc_pins[i], DEC);
+ COMM.println("...");
+ pinMode(adc_pins[i], INPUT_ANALOG);
+ while(!COMM.available()) {
+ int sample = analogRead(adc_pins[i]);
+ COMM.print(adc_pins[i],DEC);
+ COMM.print("\t");
+ COMM.print(sample,DEC);
+ COMM.print("\t");
+ COMM.print("|");
+ for(int j = 0; j<4096; j+= 100) {
+ if(sample >= j) COMM.print("#");
+ else COMM.print(" ");
+ }
+ COMM.print("| ");
+ for(int j = 0; j<12; j++) {
+ if(sample & (1 << (11-j))) COMM.print("1");
+ else COMM.print("0");
+ }
+ COMM.println("");
+ }
+ pinMode(adc_pins[i], OUTPUT);
+ digitalWrite(adc_pins[i], 0);
+ if((uint8)COMM.read() == ESC) break;
+ }
+}
+
+void cmd_gpio_qa(void) {
+ COMM.println("Doing QA testing for most GPIO pins...");
+ digitalWrite(BOARD_LED_PIN, 0);
+ for(int i = 0; i<NR_GPIO_PINS; i++) {
+ pinMode(i, INPUT);
+ gpio_state[i] = 0;
+ }
+ COMM.println("Waiting to start...");
+ while(digitalRead(0) != 1 && !COMM.available()) {
+ continue;
+ }
+ for(int i=0; i<38; i++) {
+ if(i == BOARD_LED_PIN) {
+ COMM.println("Not checking LED");
+ continue;
+ }
+ COMM.print("Checking D");
+ COMM.print(i,DEC);
+ while(digitalRead(i) == 0) continue;
+ for(int j=0; j<NR_GPIO_PINS; j++) {
+ if(digitalRead(j) && j!=i) {
+ COMM.print(": FAIL ########################### D");
+ COMM.println(j, DEC);
+ break;
+ }
+ }
+ while(digitalRead(i) == 1) continue;
+ for(int j=0; j<NR_GPIO_PINS; j++) {
+ if(digitalRead(j) && j!=i) {
+ COMM.print(": FAIL ########################### D");
+ COMM.println(j, DEC);
+ break;
+ }
+ }
+ COMM.println(": Ok!");
+ }
+ for(int i = 0; i<NR_GPIO_PINS; i++) {
+ pinMode(i, OUTPUT);
+ digitalWrite(i, 0);
+ }
+}
+
+void cmd_sequential_gpio_writes(void) {
+ COMM.print("Sequentially toggling all pins except D0, D1. ");
+ COMM.println("Anything for next, ESC to stop.");
+ digitalWrite(BOARD_LED_PIN, 0);
+ // make sure to skip the TX/RX headers
+ for(uint32 i = 2; i<NR_GPIO_PINS; i++) {
+ COMM.print("GPIO write out on header D");
+ COMM.print(i, DEC);
+ COMM.println("...");
+ pinMode(i, OUTPUT);
+ do {
+ togglePin(i);
+ } while(!COMM.available());
+ digitalWrite(i, 0);
+ if((uint8)COMM.read() == ESC) break;
+ }
+}
+
+void cmd_gpio_toggling(void) {
+ COMM.println("Toggling all GPIOs simultaneously. Press any key.");
+ digitalWrite(BOARD_LED_PIN, 0);
+ // make sure to skip the TX/RX headers
+ for(uint32 i = 2; i<NR_GPIO_PINS; i++) {
+ pinMode(i, OUTPUT);
+ }
+ while(!COMM.available()) {
+ for(uint32 i = 2; i<NR_GPIO_PINS; i++) {
+ togglePin(i);
+ }
+ }
+ for(uint32 i = 2; i<NR_GPIO_PINS; i++) {
+ digitalWrite(i, 0);
+ }
+}
+
+void cmd_sequential_pwm_test(void) {
+ COMM.println("Sequentially testing PWM on all possible headers "
+ "except D0 and D1.");
+ COMM.println("Press any key for next, ESC to stop.");
+ digitalWrite(BOARD_LED_PIN, 0);
+ // make sure to skip the TX/RX headers
+ for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
+ COMM.print("PWM out on header D");
+ COMM.print(pwm_pins[i], DEC);
+ COMM.println("...");
+ pinMode(pwm_pins[i], PWM);
+ pwmWrite(pwm_pins[i], 16000);
+ while(!COMM.available()) { delay(10); }
+ pinMode(pwm_pins[i], OUTPUT);
+ digitalWrite(pwm_pins[i], 0);
+ if((uint8)COMM.read() == ESC) break;
+ }
+}
+
+void cmd_pwm_sweep(void) {
+ COMM.println("Testing all PWM ports with a sweep. Press any key.");
+ digitalWrite(BOARD_LED_PIN, 0);
+ // make sure to skip the TX/RX pins
+ for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
+ pinMode(pwm_pins[i], PWM);
+ pwmWrite(pwm_pins[i], 4000);
+ }
+ while(!COMM.available()) {
+ rate += 20;
+ if(rate > 65500) rate = 0;
+ for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
+ pwmWrite(pwm_pins[i], rate);
+ }
+ delay(1);
+ }
+ for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
+ pinMode(pwm_pins[i], OUTPUT);
+ }
+}
+
+void cmd_servo_sweep(void) {
+ COMM.println("Testing all PWM headers with a servo sweep. Press any key.");
+ COMM.println();
+ digitalWrite(BOARD_LED_PIN, 0);
+ init_all_timers(21);
+ // make sure to skip the TX/RX headers
+ for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
+ pinMode(pwm_pins[i], PWM);
+ pwmWrite(pwm_pins[i], 4000);
+ }
+ // 1.25ms = 4096counts = 0deg
+ // 1.50ms = 4915counts = 90deg
+ // 1.75ms = 5734counts = 180deg
+ rate = 4096;
+ while(!COMM.available()) {
+ rate += 20;
+ if(rate > 5734) rate = 4096;
+ for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
+ pwmWrite(pwm_pins[i], rate);
+ }
+ delay(20);
+ }
+ for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
+ pinMode(pwm_pins[i], OUTPUT);
+ }
+ init_all_timers(1);
+ Serial2.begin(9600);
+ COMM.println("(reset serial port)");
+}
+
+void init_all_timers(uint16 prescale) {
+ timer_init(TIMER1, prescale);
+ timer_init(TIMER2, prescale);
+ timer_init(TIMER3, prescale);
+#if NR_TIMERS >= 4
+ timer_init(TIMER4, prescale);
+#elif NR_TIMERS >= 8 // TODO test this on maple native
+ timer_init(TIMER5, prescale);
+ timer_init(TIMER6, prescale);
+ timer_init(TIMER7, prescale);
+ timer_init(TIMER8, prescale);
+#endif
+}
+
+
// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated object that need libmaple may fail.
- __attribute__(( constructor )) void premain() {
+__attribute__(( constructor )) void premain() {
init();
}
diff --git a/libmaple/adc.c b/libmaple/adc.c
index 9b21b49..b70c8bd 100644
--- a/libmaple/adc.c
+++ b/libmaple/adc.c
@@ -23,8 +23,6 @@
*****************************************************************************/
/**
- * @file adc.c
- *
* @brief Analog to digital converter routines
*/
diff --git a/libmaple/adc.h b/libmaple/adc.h
index 776768e..fe1196f 100644
--- a/libmaple/adc.h
+++ b/libmaple/adc.h
@@ -25,7 +25,7 @@
/**
* @file adc.h
*
- * @brief ADC prototypes and defines
+ * @brief Analog-to-Digital Conversion (ADC) routines.
*/
#ifndef _ADC_H_
@@ -43,7 +43,8 @@ extern "C"{
*
* Need to up the sample time if otherwise... see datasheet */
-/* TODO: We'll only use ADC1 for now... */
+/* TODO: We'll only use ADC1 for now. See page 41 of the manual for
+ ADC2 and ADC3's real addresses. */
#define ADC1_BASE 0x40012400
#define ADC2_BASE 0x40012400
#define ADC3_BASE 0x40012400
@@ -74,17 +75,17 @@ void adc_init(void);
void adc_disable(void);
/**
- * Perform a single conversion on ADC[0-16],
+ * Perform a single conversion on ADC[0-15].
* PRECONDITIONS:
* adc initialized */
static inline int adc_read(int channel) {
- /* Set channel */
+ /* Set channel */
ADC_SQR3 = channel;
- /* Start the conversion */
+ /* Start the conversion */
CR2_SWSTART_BIT = 1;
- /* Wait for it to finish */
+ /* Wait for it to finish */
while(SR_EOC_BIT == 0)
;
diff --git a/libmaple/dac.c b/libmaple/dac.c
index 4c00edb..7f6101d 100644
--- a/libmaple/dac.c
+++ b/libmaple/dac.c
@@ -27,6 +27,10 @@
#include "gpio.h"
#include "dac.h"
+/**
+ * @brief DAC peripheral routines.
+ */
+
/* Only one, so global to this file */
DAC_Map *dac = (DAC_Map*)(DAC_BASE);
diff --git a/libmaple/dac.h b/libmaple/dac.h
index 17b67b7..9c84f2e 100644
--- a/libmaple/dac.h
+++ b/libmaple/dac.h
@@ -26,6 +26,10 @@
* See ../notes/dac.txt for more info
*/
+/**
+ * @file dac.h
+ */
+
#ifndef _DAC_H_
#define _DAC_H_
diff --git a/libmaple/dma.c b/libmaple/dma.c
index 1de9b60..15c96e1 100644
--- a/libmaple/dma.c
+++ b/libmaple/dma.c
@@ -64,7 +64,7 @@ static dma_regs *dma_get_regs(uint8 channel) {
if (channel >= 1 && channel <= 7) {
return (dma_regs *)(DMA1_CCR1 + DMA_CHANNEL_STRIDE * (channel-1));
} else {
- ASSERT(false);
+ ASSERT(0);
return NULL;
}
}
diff --git a/libmaple/exti.h b/libmaple/exti.h
index 1765045..806578f 100644
--- a/libmaple/exti.h
+++ b/libmaple/exti.h
@@ -141,10 +141,10 @@
#define EXTI14 14
#define EXTI15 15
-#define EXTI_CONFIG_PORTA 0
-#define EXTI_CONFIG_PORTB 1
-#define EXTI_CONFIG_PORTC 2
-#define EXTI_CONFIG_PORTD 3
+#define EXTI_CONFIG_PORTA 0 // Maple, Maple Native, Maple Mini
+#define EXTI_CONFIG_PORTB 1 // Maple, Maple Native, Maple Mini
+#define EXTI_CONFIG_PORTC 2 // Maple, Maple Native, Maple Mini
+#define EXTI_CONFIG_PORTD 3 // Maple and Maple Native only
#define EXTI_CONFIG_PORTE 4 // Native only
#define EXTI_CONFIG_PORTF 5 // Native only
#define EXTI_CONFIG_PORTG 6 // Native only
diff --git a/libmaple/flash.h b/libmaple/flash.h
index 54bda0e..7b74c83 100644
--- a/libmaple/flash.h
+++ b/libmaple/flash.h
@@ -24,7 +24,8 @@
/**
- * @brief basic stm32 flash setup routines
+ * @file flash.h
+ * @brief basic stm32 flash setup routines
*/
#ifndef _FLASH_H_
diff --git a/libmaple/fsmc.c b/libmaple/fsmc.c
index 301a90d..49526f4 100644
--- a/libmaple/fsmc.c
+++ b/libmaple/fsmc.c
@@ -22,6 +22,10 @@
* THE SOFTWARE.
*****************************************************************************/
+/**
+ * @brief
+ */
+
#include "libmaple.h"
#include "rcc.h"
#include "gpio.h"
diff --git a/libmaple/fsmc.h b/libmaple/fsmc.h
index 471cad1..e83b529 100644
--- a/libmaple/fsmc.h
+++ b/libmaple/fsmc.h
@@ -26,6 +26,10 @@
* See ../notes/fsmc.txt for more info
*/
+/**
+ * @file fsmc.h
+ */
+
#ifndef _FSMC_H_
#define _FSMC_H_
diff --git a/libmaple/gpio.c b/libmaple/gpio.c
index f7aee2b..71e5230 100644
--- a/libmaple/gpio.c
+++ b/libmaple/gpio.c
@@ -23,8 +23,6 @@
*****************************************************************************/
/**
- * @file gpio.c
- *
* @brief GPIO initialization routine
*/
@@ -36,8 +34,9 @@ void gpio_init(void) {
rcc_clk_enable(RCC_GPIOA);
rcc_clk_enable(RCC_GPIOB);
rcc_clk_enable(RCC_GPIOC);
+#if NR_GPIO_PORTS >= 4 /* Maple, but not Maple Mini */
rcc_clk_enable(RCC_GPIOD);
-#if NR_GPIO_PORTS >= 7
+#elif NR_GPIO_PORTS >= 7 /* Maple Native (high density only) */
rcc_clk_enable(RCC_GPIOE);
rcc_clk_enable(RCC_GPIOF);
rcc_clk_enable(RCC_GPIOG);
diff --git a/libmaple/gpio.h b/libmaple/gpio.h
index 49360ee..53f77c4 100644
--- a/libmaple/gpio.h
+++ b/libmaple/gpio.h
@@ -42,15 +42,18 @@
* Alternate function open-drain
*
* - After reset, the alternate functions are not active and IO prts
- * are set to Input Floating mode */
+ * are set to Input Floating mode, EXCEPT for the Serial Wire and JTAG
+ * ports, which are in alternate function mode by default. */
-#define GPIOA_BASE (GPIO_Port*)0x40010800
-#define GPIOB_BASE (GPIO_Port*)0x40010C00
-#define GPIOC_BASE (GPIO_Port*)0x40011000
-#define GPIOD_BASE (GPIO_Port*)0x40011400
-#define GPIOE_BASE (GPIO_Port*)0x40011800 // High-density devices only
-#define GPIOF_BASE (GPIO_Port*)0x40011C00 // High-density devices only
-#define GPIOG_BASE (GPIO_Port*)0x40012000 // High-density devices only
+#define AFIO_MAPR ((volatile uint32*)0x40010004)
+
+#define GPIOA_BASE ((GPIO_Port*)0x40010800)
+#define GPIOB_BASE ((GPIO_Port*)0x40010C00)
+#define GPIOC_BASE ((GPIO_Port*)0x40011000)
+#define GPIOD_BASE ((GPIO_Port*)0x40011400)
+#define GPIOE_BASE ((GPIO_Port*)0x40011800) // High-density devices only
+#define GPIOF_BASE ((GPIO_Port*)0x40011C00) // High-density devices only
+#define GPIOG_BASE ((GPIO_Port*)0x40012000) // High-density devices only
#define GPIO_SPEED_50MHZ (0x3)
@@ -109,6 +112,13 @@ static inline uint32 gpio_read_bit(GPIO_Port *port, uint8 gpio_pin) {
return (port->IDR & BIT(gpio_pin) ? 1 : 0);
}
+/* For pins configured as output push-pull, reading the ODR returns
+ * the last value written in push-pull mode.
+ */
+static inline void gpio_toggle_pin(GPIO_Port *port, uint8 gpio_pin) {
+ port->ODR = port->ODR ^ BIT(gpio_pin);
+}
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h
index 664568f..dbc77a4 100644
--- a/libmaple/libmaple.h
+++ b/libmaple/libmaple.h
@@ -33,36 +33,43 @@
#include "libmaple_types.h"
-// General configuration
-#define MAPLE_DEBUG 1
+/* General configuration */
+#define DEBUG_NONE 0
+#define DEBUG_FAULT 1
+#define DEBUG_ALL 2
-// MCU-specific configuration
-#ifdef MCU_STM32F103RB
- // eg, LeafLabs Maple
+#ifndef DEBUG_LEVEL
+#define DEBUG_LEVEL DEBUG_ALL
+#endif
- // Number of 16-bit backup registers
- #define NR_BKP_REGS 10
+/* MCU-specific configuration */
+#if defined(MCU_STM32F103RB)
+ /* e.g., LeafLabs Maple */
- // Number of GPIO ports (GPIOA, GPIOB, etc), definately used
+ /* Number of GPIO ports (GPIOA, GPIOB, etc.) */
#define NR_GPIO_PORTS 4
- // Total number of GPIO pins
+ /* Total number of GPIO pins */
#define NR_GPIO_PINS 39
- // Number of timer devices ports, definately used
+ /* Number of 16-bit backup registers */
+ #define NR_BKP_REGS 10
+
+ /* Number of timer devices ports, definitely used */
#define NR_TIMERS 4
- // Number of USART ports
+ /* Number of USART ports */
#define NR_USART 3
- // Has an FSMC bus?
+ /* Has an FSMC bus? */
#define NR_FSMC 0
- // Has an FSMC bus?
+ /* Has an FSMC bus? */
#define NR_DAC_PINS 0
- // USB Identifier numbers
- // Descriptor strings must be modified by hand in usb/descriptors.c for now
+ /* USB Identifier numbers */
+ /* Descriptor strings must be modified by hand in
+ usb/descriptors.c for now */
#define VCOM_ID_VENDOR 0x1EAF
#define VCOM_ID_PRODUCT 0x0004
#define USB_DISC_BANK GPIOC_BASE
@@ -70,39 +77,38 @@
#define USB_CONFIG_MAX_POWER (100 >> 1)
#define RESET_DELAY (100)
- // Where to put usercode (based on space reserved for bootloader)
+ /* Where to put usercode (based on space reserved for bootloader) */
#define USER_ADDR_ROM 0x08005000
#define USER_ADDR_RAM 0x20000C00
#define STACK_TOP 0x20000800
- // Debug port settings (from ASSERT)
- #define ERROR_LED_PORT GPIOA_BASE
- #define ERROR_LED_PIN 5
+ /* Debug port settings (from ASSERT) */
+ #define ERROR_LED_PORT GPIOB_BASE
+ #define ERROR_LED_PIN 12
#define ERROR_USART_NUM USART2
#define ERROR_USART_BAUD 9600
- #define ERROR_TX_PIN 2
#define ERROR_TX_PORT GPIOA_BASE
+ #define ERROR_TX_PIN 2
- // Just in case, most boards have at least some memory
+ /* Just in case, most boards have at least some memory */
#ifndef RAMSIZE
# define RAMSIZE (caddr_t)0x50000
#endif
- // Bitbanded Memory sections
+ /* Bitbanded Memory sections */
#define BITBAND_SRAM_REF 0x20000000
#define BITBAND_SRAM_BASE 0x22000000
#define BITBAND_PERI_REF 0x40000000
#define BITBAND_PERI_BASE 0x42000000
-#endif
-#ifdef MCU_STM32F103ZE
- // eg, LeafLabs Maple Native
- #define NR_BKP_REGS 42
+#elif defined(MCU_STM32F103ZE)
+ /* e.g., LeafLabs Maple Native */
+
#define NR_GPIO_PORTS 7
- #define NR_GPIO_PINS 63
+ #define NR_GPIO_PINS 100
+ #define NR_BKP_REGS 42 /* TODO test on Native */
#define NR_TIMERS 8
- // 3 USART, plus UART4 and UART5
- #define NR_USART 5
+ #define NR_USART 5 /* NB: 4 and 5 are UART only */
#define NR_FSMC 1
#define NR_DAC_PINS 2
@@ -121,8 +127,8 @@
#define ERROR_LED_PIN 15
#define ERROR_USART_NUM USART1
#define ERROR_USART_BAUD 9600
- #define ERROR_TX_PIN 10
#define ERROR_TX_PORT GPIOA_BASE
+ #define ERROR_TX_PIN 10
#ifndef RAMSIZE
# define RAMSIZE (caddr_t)0x50000
@@ -132,15 +138,54 @@
#define BITBAND_SRAM_BASE 0x22000000
#define BITBAND_PERI_REF 0x40000000
#define BITBAND_PERI_BASE 0x42000000
-#endif
-// Make sure MCU-specific settings were defined
-#ifndef NR_GPIO_PORTS
-#error "No MCU type specified. Add something like -DMCU_STM32F103RB " \
+#elif defined(MCU_STM32F103CB)
+ /* e.g., LeafLabs Maple Mini */
+
+ #define NR_GPIO_PORTS 3
+ #define NR_GPIO_PINS 34
+ #define NR_BKP_REGS 10 /* TODO test on Mini */
+ #define NR_TIMERS 4
+ #define NR_USART 3
+ #define NR_FSMC 0
+ #define NR_DAC_PINS 0
+
+ #define VCOM_ID_VENDOR 0x1EAF
+ #define VCOM_ID_PRODUCT 0x0005
+ #define USB_DISC_BANK GPIOB_BASE
+ #define USB_DISC_PIN 9
+ #define USB_CONFIG_MAX_POWER (100 >> 1)
+ #define RESET_DELAY 100
+
+ #define USER_ADDR_ROM 0x08005000
+ #define USER_ADDR_RAM 0x20000C00
+ #define STACK_TOP 0x20000800
+
+ #define ERROR_LED_PORT GPIOB_BASE
+ #define ERROR_LED_PIN 12
+ #define ERROR_USART_NUM USART2
+ #define ERROR_USART_BAUD 9600
+ #define ERROR_TX_PORT GPIOA_BASE
+ #define ERROR_TX_PIN 2
+
+ #ifndef RAMSIZE
+ # define RAMSIZE (caddr_t)0x50000
+ #endif
+
+ /* Bitbanded Memory sections */
+ #define BITBAND_SRAM_REF 0x20000000
+ #define BITBAND_SRAM_BASE 0x22000000
+ #define BITBAND_PERI_REF 0x40000000
+ #define BITBAND_PERI_BASE 0x42000000
+
+#else
+
+#error "No MCU type specified. Add something like -DMCU_STM32F103RB " \
"to your compiler arguments (probably in a Makefile)."
+
#endif
-// Requires board configuration info
+/* Requires board configuration info */
#include "util.h"
#endif
diff --git a/libmaple/libmaple_types.h b/libmaple/libmaple_types.h
index a976a9e..8d216a8 100644
--- a/libmaple/libmaple_types.h
+++ b/libmaple/libmaple_types.h
@@ -45,6 +45,8 @@ typedef void (*voidFuncPtr)(void);
#define __io volatile
+#define ALWAYS_INLINE inline __attribute__((always_inline))
+
#ifndef NULL
#define NULL 0
#endif
diff --git a/libmaple/rcc.h b/libmaple/rcc.h
index a7c4c53..4b1f35d 100644
--- a/libmaple/rcc.h
+++ b/libmaple/rcc.h
@@ -23,7 +23,8 @@
*****************************************************************************/
/**
- * @brief reset and clock control definitions and prototypes
+ * @file rcc.h
+ * @brief reset and clock control definitions and prototypes
*/
#ifndef _RCC_H_
diff --git a/libmaple/spi.h b/libmaple/spi.h
index d1973c5..db8aa9c 100644
--- a/libmaple/spi.h
+++ b/libmaple/spi.h
@@ -23,6 +23,7 @@
*****************************************************************************/
/**
+ * @file spi.h
* @brief libmaple serial peripheral interface (SPI) prototypes and
* declarations
*/
diff --git a/libmaple/systick.c b/libmaple/systick.c
index 961d42b..b056001 100644
--- a/libmaple/systick.c
+++ b/libmaple/systick.c
@@ -23,8 +23,6 @@
*****************************************************************************/
/**
- * @file systick.c
- *
* @brief System timer interrupt handler and initialization routines
*/
diff --git a/libmaple/timers.c b/libmaple/timers.c
index 04bfa9f..29aeeba 100644
--- a/libmaple/timers.c
+++ b/libmaple/timers.c
@@ -23,8 +23,6 @@
*****************************************************************************/
/**
- * @file timers.c
- *
* @brief General timer routines
*/
@@ -75,16 +73,20 @@ struct timer_dev timer_dev_table[] = {
/* This function should probably be rewriten to take (timer_num, mode)
* and have prescaler set elsewhere. The mode can be passed through to
* set_mode at the end */
-void timer_init(uint8 timer_num, uint16 prescale) {
+void timer_init(timer_dev_num timer_num, uint16 prescale) {
/* TODO: doesn't catch 6+7 */
- ASSERT((timer_num != TIMER6) && (timer_num != TIMER7));
timer_port *timer = timer_dev_table[timer_num].base;
uint8 is_advanced = 0;
- if((timer_num == TIMER1) || (timer_num == TIMER8)) {
+ if (timer_num == TIMER1) {
is_advanced = 1;
}
+#if NR_TIMERS >= 8
+ if (timer_num == TIMER8) {
+ is_advanced = 1;
+ }
+#endif
rcc_clk_enable(timer_dev_table[timer_num].rcc_dev_num);
@@ -105,19 +107,15 @@ void timer_init(uint8 timer_num, uint16 prescale) {
* we'll worry about that later. */
timer->CCR1 = 0x8FFF; // PWM start value
timer->CCMR1 |= 0x68; // PWM mode 1, enable preload register.
- timer->CCER |= 0x001; // enable ch
timer->CCR2 = 0x8FFF; // PWM start value
timer->CCMR1 |= (0x68 << 8);// PWM mode 1, enable preload register.
- timer->CCER |= 0x010; // enable ch
timer->CCR3 = 0x8FFF; // PWM start value
timer->CCMR2 |= 0x68; // PWM mode 1, enable preload register.
- timer->CCER |= 0x100; // enable ch
timer->CCR4 = 0x8FFF; // PWM start value
timer->CCMR2 |= (0x68 << 8);// PWM mode 1, enable preload register.
- timer->CCER |= 0x1000; // enable ch
/* Advanced timer? */
if (is_advanced) {
@@ -131,48 +129,61 @@ void timer_init(uint8 timer_num, uint16 prescale) {
}
/* Stops the counter; the mode and settings are not modified */
-void timer_pause(uint8 timer_num) {
+void timer_pause(timer_dev_num timer_num) {
timer_port *timer = timer_dev_table[timer_num].base;
timer->CR1 &= ~(0x0001); // CEN
}
/* Starts the counter; the mode and settings are not modified */
-void timer_resume(uint8 timer_num) {
+void timer_resume(timer_dev_num timer_num) {
timer_port *timer = timer_dev_table[timer_num].base;
timer->CR1 |= 0x0001; // CEN
}
+/* Returns the current timer counter value. Probably very inaccurate
+ * if the counter is running with a low prescaler. */
+uint16 timer_get_count(timer_dev_num timer_num) {
+ timer_port *timer = timer_dev_table[timer_num].base;
+
+ return timer->CNT;
+}
+
/* This function sets the counter value via register for the specified
* timer. Can't think of specific usecases except for resetting to
* zero but it's easy to implement and allows for "creative"
* programming */
-void timer_set_count(uint8 timer_num, uint16 value) {
+void timer_set_count(timer_dev_num timer_num, uint16 value) {
timer_port *timer = timer_dev_table[timer_num].base;
timer->CNT = value;
}
-/* Returns the current timer counter value. Probably very inaccurate
- * if the counter is running with a low prescaler. */
-uint16 timer_get_count(uint8 timer_num) {
+/* Get the prescaler buffer value (remember, the actual prescaler
+ * doesn't get set until an update event). */
+uint16 timer_get_prescaler(timer_dev_num timer_num) {
timer_port *timer = timer_dev_table[timer_num].base;
-
- return timer->CNT;
+ return timer->PSC;
}
/* Sets the prescaler */
-void timer_set_prescaler(uint8 timer_num, uint16 prescale) {
+void timer_set_prescaler(timer_dev_num timer_num, uint16 prescale) {
timer_port *timer = timer_dev_table[timer_num].base;
timer->PSC = prescale;
}
+/* Get the reload value for the entire timer. */
+uint16 timer_get_reload(timer_dev_num timer_num) {
+ timer_port *timer = timer_dev_table[timer_num].base;
+ return timer->ARR;
+}
+
/* This sets the "reload" or "overflow" value for the entire timer. We
* should probably settle on either "reload" or "overflow" to prevent
* confusion? */
-void timer_set_reload(uint8 timer_num, uint16 max_reload) {
+void timer_set_reload(timer_dev_num timer_num, uint16 max_reload) {
timer_port *timer = timer_dev_table[timer_num].base;
timer->ARR = max_reload;
@@ -217,7 +228,7 @@ void timer_disable_all(void) {
}
/* Sets the mode of individual timer channels, including a DISABLE mode */
-void timer_set_mode(uint8 timer_num, uint8 channel, uint8 mode) {
+void timer_set_mode(timer_dev_num timer_num, uint8 channel, TimerMode mode) {
timer_port *timer = timer_dev_table[timer_num].base;
ASSERT(channel >= 1);
@@ -292,18 +303,36 @@ void timer_set_mode(uint8 timer_num, uint8 channel, uint8 mode) {
}
}
+uint16 timer_get_compare_value(timer_dev_num timer_num, uint8 channel_num) {
+ /* faster: just read TIMERx_CHy_CCR (see timers.h) */
+ ASSERT(channel_num > 0 && channel_num <= 4);
+ timer_port *timer = timer_dev_table[timer_num].base;
+ switch(channel_num) {
+ case 1:
+ return timer->CCR1;
+ case 2:
+ return timer->CCR2;
+ case 3:
+ return timer->CCR3;
+ case 4:
+ return timer->CCR4;
+ default: /* in case ASSERT is disabled */
+ return 0;
+ }
+}
+
/* This sets the compare value (aka the trigger) for a given timer
* channel */
-void timer_set_compare_value(uint8 timer_num,
- uint8 compare_num,
+void timer_set_compare_value(timer_dev_num timer_num,
+ uint8 channel_num,
uint16 value) {
+ ASSERT(channel_num > 0 && channel_num <= 4);
+
/* The faster version of this function is the inline
timer_pwm_write_ccr */
timer_port *timer = timer_dev_table[timer_num].base;
- ASSERT(compare_num > 0 && compare_num <= 4);
-
- switch(compare_num) {
+ switch(channel_num) {
case 1:
timer->CCR1 = value;
break;
@@ -321,7 +350,7 @@ void timer_set_compare_value(uint8 timer_num,
/* Stores a pointer to the passed usercode interrupt function and configures
* the actual ISR so that it will actually be called */
-void timer_attach_interrupt(uint8 timer_num,
+void timer_attach_interrupt(timer_dev_num timer_num,
uint8 compare_num,
voidFuncPtr handler) {
ASSERT(compare_num > 0 && compare_num <= 4);
@@ -333,7 +362,7 @@ void timer_attach_interrupt(uint8 timer_num,
nvic_irq_enable(timer_dev_table[timer_num].nvic_dev_num);
}
-void timer_detach_interrupt(uint8 timer_num, uint8 compare_num) {
+void timer_detach_interrupt(timer_dev_num timer_num, uint8 compare_num) {
ASSERT(compare_num > 0 && compare_num <= 4);
timer_port *timer = timer_dev_table[timer_num].base;
@@ -342,6 +371,13 @@ void timer_detach_interrupt(uint8 timer_num, uint8 compare_num) {
timer->DIER &= ~(1 << compare_num); // 1-indexed compare nums
}
+void timer_generate_update(timer_dev_num timer_num) {
+ /* cause update event by setting UG bit in EGR. updates prescaler
+ ratio etc. */
+ timer_port *timer = timer_dev_table[timer_num].base;
+ timer->EGR |= 0x1;
+}
+
/* The following are the actual interrupt handlers; 1 for each timer which must
* determine which actual compare value (aka channel) was triggered.
*
diff --git a/libmaple/timers.h b/libmaple/timers.h
index cbdf088..99bcab6 100644
--- a/libmaple/timers.h
+++ b/libmaple/timers.h
@@ -82,7 +82,7 @@
extern "C"{
#endif
-typedef volatile uint32* TimerCCR;
+typedef volatile uint16* TimerCCR;
#define TIMER1_BASE 0x40012C00
#define TIMER2_BASE 0x40000000
@@ -96,47 +96,63 @@ typedef volatile uint32* TimerCCR;
#define ARPE BIT(7) // Auto-reload preload enable
#define NOT_A_TIMER 0
-#define TIMER_CCR(NUM,CHAN) TIMER ## NUM ## _CH ## CHAN ## _CRR
+#define TIMER_CCR(NUM,CHAN) (TIMER ## NUM ## _CH ## CHAN ## _CRR)
-#define TIMER1_CH1_CCR (TimerCCR)(TIMER1_BASE + 0x34)
-#define TIMER1_CH2_CCR (TimerCCR)(TIMER1_BASE + 0x38)
-#define TIMER1_CH3_CCR (TimerCCR)(TIMER1_BASE + 0x3C)
-#define TIMER1_CH4_CCR (TimerCCR)(TIMER1_BASE + 0x40)
+/* Timers 1-4 are present on the entire STM32 line. */
-#define TIMER2_CH1_CCR (TimerCCR)(TIMER2_BASE + 0x34)
-#define TIMER2_CH2_CCR (TimerCCR)(TIMER2_BASE + 0x38)
-#define TIMER2_CH3_CCR (TimerCCR)(TIMER2_BASE + 0x3C)
-#define TIMER2_CH4_CCR (TimerCCR)(TIMER2_BASE + 0x40)
+#define TIMER1_CH1_CCR ((TimerCCR)(TIMER1_BASE + 0x34))
+#define TIMER1_CH2_CCR ((TimerCCR)(TIMER1_BASE + 0x38))
+#define TIMER1_CH3_CCR ((TimerCCR)(TIMER1_BASE + 0x3C))
+#define TIMER1_CH4_CCR ((TimerCCR)(TIMER1_BASE + 0x40))
-#define TIMER3_CH1_CCR (TimerCCR)(TIMER3_BASE + 0x34)
-#define TIMER3_CH2_CCR (TimerCCR)(TIMER3_BASE + 0x38)
-#define TIMER3_CH3_CCR (TimerCCR)(TIMER3_BASE + 0x3C)
-#define TIMER3_CH4_CCR (TimerCCR)(TIMER3_BASE + 0x40)
+#define TIMER2_CH1_CCR ((TimerCCR)(TIMER2_BASE + 0x34))
+#define TIMER2_CH2_CCR ((TimerCCR)(TIMER2_BASE + 0x38))
+#define TIMER2_CH3_CCR ((TimerCCR)(TIMER2_BASE + 0x3C))
+#define TIMER2_CH4_CCR ((TimerCCR)(TIMER2_BASE + 0x40))
-#define TIMER4_CH1_CCR (TimerCCR)(TIMER4_BASE + 0x34)
-#define TIMER4_CH2_CCR (TimerCCR)(TIMER4_BASE + 0x38)
-#define TIMER4_CH3_CCR (TimerCCR)(TIMER4_BASE + 0x3C)
-#define TIMER4_CH4_CCR (TimerCCR)(TIMER4_BASE + 0x40)
+#define TIMER3_CH1_CCR ((TimerCCR)(TIMER3_BASE + 0x34))
+#define TIMER3_CH2_CCR ((TimerCCR)(TIMER3_BASE + 0x38))
+#define TIMER3_CH3_CCR ((TimerCCR)(TIMER3_BASE + 0x3C))
+#define TIMER3_CH4_CCR ((TimerCCR)(TIMER3_BASE + 0x40))
-/* Timer5 and Timer8 are in high-density devices only (such as Maple
- Native). Timer6 and Timer7 in these devices have no output compare
+#define TIMER4_CH1_CCR ((TimerCCR)(TIMER4_BASE + 0x34))
+#define TIMER4_CH2_CCR ((TimerCCR)(TIMER4_BASE + 0x38))
+#define TIMER4_CH3_CCR ((TimerCCR)(TIMER4_BASE + 0x3C))
+#define TIMER4_CH4_CCR ((TimerCCR)(TIMER4_BASE + 0x40))
+
+/* Timers 5 and 8 are in high-density devices only (such as Maple
+ Native). Timers 6 and 7 in these devices have no output compare
pins. */
-#define TIMER5_CH1_CCR (TimerCCR)(TIMER5_BASE + 0x34)
-#define TIMER5_CH2_CCR (TimerCCR)(TIMER5_BASE + 0x38)
-#define TIMER5_CH3_CCR (TimerCCR)(TIMER5_BASE + 0x3C)
-#define TIMER5_CH4_CCR (TimerCCR)(TIMER5_BASE + 0x40)
+#define TIMER5_CH1_CCR ((TimerCCR)(TIMER5_BASE + 0x34))
+#define TIMER5_CH2_CCR ((TimerCCR)(TIMER5_BASE + 0x38))
+#define TIMER5_CH3_CCR ((TimerCCR)(TIMER5_BASE + 0x3C))
+#define TIMER5_CH4_CCR ((TimerCCR)(TIMER5_BASE + 0x40))
-#define TIMER8_CH1_CCR (TimerCCR)(TIMER8_BASE + 0x34)
-#define TIMER8_CH2_CCR (TimerCCR)(TIMER8_BASE + 0x38)
-#define TIMER8_CH3_CCR (TimerCCR)(TIMER8_BASE + 0x3C)
-#define TIMER8_CH4_CCR (TimerCCR)(TIMER8_BASE + 0x40)
+#define TIMER8_CH1_CCR ((TimerCCR)(TIMER8_BASE + 0x34))
+#define TIMER8_CH2_CCR ((TimerCCR)(TIMER8_BASE + 0x38))
+#define TIMER8_CH3_CCR ((TimerCCR)(TIMER8_BASE + 0x3C))
+#define TIMER8_CH4_CCR ((TimerCCR)(TIMER8_BASE + 0x40))
-#define TIMER_DISABLED 0
-#define TIMER_PWM 1
-#define TIMER_OUTPUTCOMPARE 2
+/**
+ * Used to configure the behavior of a timer.
+ */
+typedef enum TimerMode {
+ TIMER_DISABLED, /**< In this mode, 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. */
+ TIMER_OUTPUTCOMPARE, /**< In this mode, the timer counts from 0 to
+ its reload value repeatedly; every time
+ the counter value reaches one of the
+ channel compare values, the corresponding
+ interrupt is fired. */
+} TimerMode;
typedef struct {
+ /* Fields up to ARR common to general purpose (2,3,4,5), advanced
+ control (1,8) and basic (6, 7) timers: */
volatile uint16 CR1;
uint16 RESERVED0;
volatile uint16 CR2;
@@ -161,8 +177,9 @@ typedef struct {
uint16 RESERVED10;
volatile uint16 ARR;
uint16 RESERVED11;
- volatile uint16 RCR;
- uint16 RESERVED12;
+ /* Basic timers have none of the following: */
+ volatile uint16 RCR; /* Advanced control timers only */
+ uint16 RESERVED12; /* Advanced control timers only */
volatile uint16 CCR1;
uint16 RESERVED13;
volatile uint16 CCR2;
@@ -171,25 +188,34 @@ typedef struct {
uint16 RESERVED15;
volatile uint16 CCR4;
uint16 RESERVED16;
- volatile uint16 BDTR; // Not used in general purpose timers
- uint16 RESERVED17; // Not used in general purpose timers
+ volatile uint16 BDTR; /* Advanced control timers only */
+ uint16 RESERVED17; /* Advanced control timers only */
volatile uint16 DCR;
uint16 RESERVED18;
volatile uint16 DMAR;
uint16 RESERVED19;
} timer_port;
-/* timer device numbers */
-enum {
- TIMER1,
- TIMER2,
- TIMER3,
- TIMER4,
- TIMER5, // High density only
- TIMER6, // High density only; no compare
- TIMER7, // High density only; no compare
- TIMER8, // High density only
-};
+/**
+ * Timer device numbers. See STM32 reference manual, chapters 13-15.
+ */
+/* several locations depend on TIMER1=0, etc.; don't change the
+ enumerator values to start at 1. */
+typedef enum {
+ TIMER1, /*< Advanced control timer TIM1 */
+ TIMER2, /*< General purpose timer TIM2 */
+ TIMER3, /*< General purpose timer TIM3 */
+ TIMER4, /*< General purpose timer TIM4 */
+#if NR_TIMERS >= 8
+ TIMER5, /*< General purpose timer TIM5; high density only */
+ /* FIXME maple native: put timers 6 and 7 back in and make the
+ corresponding changes to timers.c */
+ /* TIMER6, /\*< Basic timer TIM6; high density only *\/ */
+ /* TIMER7, /\*< Basic timer TIM7; high density only *\/ */
+ TIMER8, /*< Advanced control timer TIM8; high density only */
+#endif
+ TIMER_INVALID /* FIXME: this is starting to seem like a bad idea */
+} timer_dev_num;
/* timer descriptor */
struct timer_dev {
@@ -201,40 +227,203 @@ struct timer_dev {
extern struct timer_dev timer_dev_table[];
-/* Turn on timer with prescale as the divisor
- * void timer_init(uint32 timer, uint16 prescale)
- * timer -> {1-4}
- * prescale -> {1-65535}
+/**
+ * Initializes timer with prescale as the clock divisor.
+ *
+ * @param timer_num Timer number.
+ *
+ * @param prescale value in the range 1--65535 to use as a prescaler
+ * for timer counter increment frequency.
+ *
+ * @see timer_dev_num
+ * @see timer_set_prescaler()
+ * @see timer_set_mode()
+ */
+void timer_init(timer_dev_num timer_num, uint16 prescale);
+
+/**
+ * Quickly disable all timers. Calling this function is faster than,
+ * e.g., calling timer_set_mode() for all available timers/channels.
*/
-void timer_init(uint8, uint16);
void timer_disable_all(void);
-uint16 timer_get_count(uint8);
-void timer_set_count(uint8,uint16);
-void timer_pause(uint8);
-void timer_resume(uint8);
-void timer_set_prescaler(uint8 timer_num, uint16 prescale);
-void timer_set_reload(uint8 timer_num, uint16 max_reload);
-void timer_set_mode(uint8 timer_num, uint8 compare_num, uint8 mode);
-void timer_set_compare_value(uint8 timer_num, uint8 compare_num, uint16 value);
-void timer_attach_interrupt(uint8 timer_num, uint8 compare_num,
+
+/**
+ * Returns the timer's counter value. Due to function call overhead,
+ * this value is likely to be inaccurate if the counter is running
+ * with a low prescaler.
+ *
+ * @param timer_num the timer whose counter to return.
+ *
+ * @pre Timer has been initialized.
+ */
+uint16 timer_get_count(timer_dev_num timer_num);
+
+/**
+ * Sets the counter value for the given timer.
+ *
+ * @param timer_num the timer whose counter to set.
+ *
+ * @param value the new counter value.
+ *
+ * @pre Timer has been initialized.
+ */
+void timer_set_count(timer_dev_num timer_num, uint16 value);
+
+/**
+ * Stops the timer's counter from incrementing. Does not modify the
+ * timer's mode or settings.
+ *
+ * @param timer_num the timer to pause.
+ *
+ * @see timer_resume()
+ *
+ * @pre Timer has been initialized.
+ */
+void timer_pause(timer_dev_num timer_num);
+
+/**
+ * Starts the counter for the given timer. Does not modify the
+ * timer's mode or settings. The timer will begin counting on the
+ * first rising clock cycle after it has been re-enabled using this
+ * function.
+ *
+ * @param timer_num the timer to resume.
+ *
+ * @see timer_pause()
+ *
+ * @pre Timer has been initialized.
+ */
+void timer_resume(timer_dev_num timer_num);
+
+/**
+ * Returns the prescaler for the given timer.
+ *
+ * @param timer_num the timer whose prescaler to return.
+ *
+ * @see timer_set_prescaler()
+ *
+ * @pre Timer has been initialized.
+ */
+uint16 timer_get_prescaler(timer_dev_num timer_num);
+
+/**
+ * Sets the prescaler for the given timer. This value goes into the
+ * PSC register, so it's 0-based (i.e., a prescale of 0 counts 1 tick
+ * per clock cycle). This prescale does not take effect until the
+ * next update event.
+ *
+ * @param timer_num the timer whose prescaler to set.
+ *
+ * @param prescale the new prescaler.
+ *
+ * @pre Timer has been initialized.
+ */
+void timer_set_prescaler(timer_dev_num timer_num, uint16 prescale);
+
+/**
+ * Gets the reload value for the timer.
+ *
+ * @see timer_set_reload()
+ *
+ * @pre Timer has been initialized.
+ */
+uint16 timer_get_reload(timer_dev_num timer_num);
+
+/**
+ * Sets the reload value for the timer.
+ *
+ * After this function returns, the timer's counter will reset to 0
+ * after it has reached the value max_reload.
+ *
+ * @pre Timer has been initialized.
+ */
+void timer_set_reload(timer_dev_num timer_num, uint16 max_reload);
+
+/* TODO: timer_get_mode */
+
+/**
+ * Set the mode of an individual timer channel.
+ *
+ * @see timer_disable_all()
+ * @see TimerMode
+ * @see timer_dev_num
+ * @pre Timer has been initialized.
+ */
+void timer_set_mode(timer_dev_num timer_num, uint8 channel, TimerMode mode);
+
+/**
+ * Get the compare value for the given timer channel.
+ * @see timer_set_compare_value()
+ * @see timer_dev_num
+ * @pre Timer has been initialized.
+ */
+uint16 timer_get_compare_value(timer_dev_num timer_num, uint8 channel);
+
+/**
+ * Sets the compare value for a given timer channel. Useful for
+ * scheduling when interrupt handlers will be called.
+ *
+ * @see timer_attach_interrupt()
+ * @see timer_detach_interrupt()
+ * @see timer_set_reload()
+ * @see timer_dev_num
+ * @pre Timer has been initialized.
+ */
+void timer_set_compare_value(timer_dev_num timer_num, uint8 channel,
+ uint16 value);
+
+/**
+ * Detach the interrupt handler for the given timer channel, if any.
+ * After this function returns, any handler attached to the given
+ * channel will no longer be called.
+ *
+ * @see timer_attach_interrupt()
+ * @pre Timer has been initialized.
+ * @see timer_dev_num
+ */
+void timer_detach_interrupt(timer_dev_num timer_num, uint8 channel);
+
+/**
+ * Attach an interrupt handler for the given timer and channel. The
+ * given ISR, handler, will be called whenever the timer's counter
+ * reaches the compare value for the given timer and channel.
+ *
+ * @see timer_set_compare_value()
+ * @see timer_detach_interrupt()
+ * @see timer_set_mode()
+ * @see timer_dev_num
+ * @see voidFuncPtr
+ * @pre Timer has been initialized.
+ * @pre The channel's mode must be set to TIMER_OUTPUTCOMPARE, or the
+ * interrupt handler will not get called.
+ */
+void timer_attach_interrupt(timer_dev_num timer_num, uint8 channel,
voidFuncPtr handler);
-void timer_detach_interrupt(uint8 timer_num, uint8 compare_num);
-/* Turn on PWM with duty_cycle on the specified channel in timer.
- * This function takes in a pointer to the corresponding CCR
- * register for the pin cause it saves pwmWrite() a couple of
- * cycles.
+/**
+ * Programmatically generate an update event on the given timer. This
+ * updates the prescaler, reloads the compare value (in upcounting
+ * mode, etc.).
+ *
+ * @pre Timer has been initialized.
+ */
+void timer_generate_update(timer_dev_num timer_num);
+
+/**
+ * Turn on PWM with duty_cycle.
+ *
+ * @param ccr TIMERx_CHn_CCR, where x goes from 1 to NR_TIMERS,
+ * and n goes from 1 to 4.
+ *
+ * @param duty_cycle: A number between 0 and
+ * timer_get_compare_value(TIMERx, y), where x and y are as above.
*
- * void timer_pwm(uint8 channel, uint8 duty_cycle);
- * channel -> {TIMERx_CHn_CCR}
- * duty_cycle -> {0-65535}
+ * @pre Pin has been set to alternate function output.
*
- * PRECONDITIONS:
- * pin has been set to alternate function output
- * timer has been initialized
+ * @pre Timer has been initialized.
*/
-static inline void timer_pwm_write_ccr(TimerCCR CCR, uint16 duty_cycle) {
- *CCR = duty_cycle;
+static inline void timer_pwm_write_ccr(TimerCCR ccr, uint16 duty_cycle) {
+ *ccr = duty_cycle;
}
#ifdef __cplusplus
diff --git a/libmaple/usart.c b/libmaple/usart.c
index 27aab49..44a5c92 100644
--- a/libmaple/usart.c
+++ b/libmaple/usart.c
@@ -23,8 +23,6 @@
*****************************************************************************/
/**
- * @file usart.c
- *
* @brief USART control routines
*/
@@ -78,22 +76,25 @@ struct usart_dev usart_dev_table[] = {
#endif
};
-/* usart interrupt handlers.
+/*
+ * Usart interrupt handlers.
+ */
- Use of rb_safe_insert() implies that a full buffer ignores new
- bytes. */
-__attribute__((always_inline)) static inline void usart_irq(int usart_num) {
- /* TODO: use attributes to let GCC know it's always called with
- constants, just to force the inliner to do its thing */
+static inline void usart_irq(int usart_num) {
#ifdef USART_SAFE_INSERT
+ /* Ignore old bytes if the user defines USART_SAFE_INSERT. */
rb_safe_insert(&(usart_dev_table[usart_num].rb),
(uint8)((usart_dev_table[usart_num].base)->DR));
#else
+ /* By default, push bytes around in the ring buffer. */
rb_push_insert(&(usart_dev_table[usart_num].rb),
(uint8)((usart_dev_table[usart_num].base)->DR));
#endif
}
+/* TODO: Check the disassembly for the following functions to make
+ sure GCC inlined properly. */
+
void USART1_IRQHandler(void) {
usart_irq(USART1);
}
diff --git a/libmaple/usart.h b/libmaple/usart.h
index cbc7bde..0ca3f55 100644
--- a/libmaple/usart.h
+++ b/libmaple/usart.h
@@ -23,6 +23,7 @@
*****************************************************************************/
/**
+ * @file usart.h
* @brief USART definitions and prototypes
*/
diff --git a/libmaple/usb/README b/libmaple/usb/README
index f3970b6..540b1ea 100644
--- a/libmaple/usb/README
+++ b/libmaple/usb/README
@@ -5,16 +5,19 @@ The USB submodule of libmaple is responsible for:
the USB isr, resetting the USB disc pin (used to tell the host
were alive). Additionally, the USB submodule defines the virtual
com port USB applications that is available to all user sketches
- via Usb.print() and others.
+ via SerialUSB.print() and others.
To use it:
- Call Usb.init() to enable the IRQ channel, configure the clocks,
- pull down usb_disc, and setup the vcom buffers
- Usb.print/ln, available(), read(), write() implement the same
+
+ [This section is out of date. Does SerialUSB.begin() do the same
+ thing as the old Usb.init()?]
+
+ SerialUSB.print/ln, available(), read(), write() implement the same
interface as Serial1/2/3
-
-
+
+
Current Status:
+
Currently, the USB submodule relies on the low level core library
provided by ST to access the USB peripheral registers and
implement the USB transfer protocol for control endpoint
@@ -22,23 +25,27 @@ Current Status:
unfortunately hard to untangle from this low level dependence, and
when a new USB core library is written (to nix ST dependence)
changes will likely have to be made to virtual com application
- code. Ideally, the new core library should mimick the form of
- MyUSB (LUFA), since this library (USB for AVR) is growing in
- popularity and in example applications. Additionally, the USB lib
- here relies on low level hardware functions that were just ripped
- out of the bootloader code (for simplicity) but clearly this
- should be replaced with direct accesses to functions provided
- elsewhere in libmaple.
-
- The virtual com port serves two important purposes. 1) is allows
- serial data transfers between user sketches an a host computer. 2)
- is allows the host machine to issue a system reset by asserting
- the DTR signal. After reset, Maple will run the DFU bootloader for
- a few seconds, during which the user can begin a DFU download
- operation ('downloads' application binary into RAM/FLASH). This
- without this virtual com port, it would be necessary to find an
- alternative means to reset the chip in order to enable the
- bootloader.
+ code. Ideally, the new core library should mimic the form of MyUSB
+ (LUFA), since this library (USB for AVR) is growing in popularity
+ and in example applications. Additionally, the USB lib here relies
+ on low level hardware functions that were just ripped out of the
+ bootloader code (for simplicity) but clearly this should be
+ replaced with direct accesses to functions provided elsewhere in
+ libmaple.
+
+ The virtual com port serves two important purposes.
+
+ 1) It allows serial data transfers between user sketches an a
+ host computer.
+
+ 2) It allows the host machine to issue a system reset by
+ asserting the DTR signal.
+
+ After reset, Maple will run the DFU bootloader for a few seconds,
+ during which the user can begin a DFU upload operation (uploads
+ application binary into RAM/FLASH). Thus, without this virtual com
+ port, it would be necessary to find an alternative means to reset
+ the chip in order to enable the bootloader.
If you would like to develop your own USB application for whatever
reason (uses faster isochronous enpoints for streaming audio, or
@@ -51,19 +58,19 @@ Current Status:
It would be possible to build a compound USB device, that
implements endpoints for both the virtual COM port as well as some
- other components (mass sotrage etc.) however this turns out to be
- a burden from the host driver side, as windows and *nix handle
+ other components (mass storage etc.). However, this turns out to
+ be a burden from the host driver side, as Windows and *nix handle
compound USB devices quite differently.
- Be mindful that running the USB application isnt "free." The
+ Be mindful that enabling the USB peripheral isnt "free." The
device must respond to periodic bus activity (every few
- milliseconds) by servicing an ISR. Therefore the USB application
+ milliseconds) by servicing an ISR. Therefore, the USB application
should be disabled inside of timing critical applications. In
order to disconnect the device from the host, the USB_DISC pin can
- be asserted (on Maple v1,2,3 this is GPIOC,12). Alternatively, the
- NVIC can be directly configured to disable the USB LP/HP IRQ's
+ be asserted (on Maple this is GPIO C12). Alternatively, the NVIC
+ can be directly configured to disable the USB LP/HP IRQ's.
- This library should exposed through usb.h, do not include any
+ This library should exposed through usb.h; do not include any
other files direcly in your application.
The files inside of usb_lib were provided by ST and are subject to
@@ -72,21 +79,22 @@ Current Status:
Integration with libmaple:
- The current USB lib is ported directly from the maple bootloader
- code, adapted to be a virtual com rather than a DFU device. That
- means several functions are redefined locally that could have been
- pulled from elsewhere in libmaple. Thus, ths USB module depends
- absolutely zero on libmaple, it even ensures that clocks are
- configured correctly for its operation.
+ The current USB lib is ported from the Maple bootloader code,
+ adapted to be a virtual com rather than a DFU device. That means
+ several functions are redefined locally that could have been
+ pulled from elsewhere in libmaple. Thus, ths USB module doesn't
+ have too many dependencies on libmaple. It even ensures that
+ clocks are configured correctly for its operation. However, over
+ time, some libmaple dependencies have crept in.
Todo:
- write custom low level USB stack to strip out any remaining
dependence on ST code
- remove dependence on hardware.c, since any functions here really
- should have their own analogues elsewhere inside libmaple
+ should have their own analogs elsewhere inside libmaple
- add a high level USB application library that would allow users
to make their own HID/Mass Storage/Audio/Video devices.
- - implement a Usb.link(SerialX) that forces a passthrough
+ - implement a SerialUSB.link(SerialX) that forces a passthrough
the host computer virtual com to SerialX, and utilizes the
line_config commands correctly (sets baud etc)
diff --git a/libmaple/usb/descriptors.c b/libmaple/usb/descriptors.c
index 5038709..360e6dd 100644
--- a/libmaple/usb/descriptors.c
+++ b/libmaple/usb/descriptors.c
@@ -1,12 +1,35 @@
-/* insert license */
-
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 LeafLabs LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
#include "descriptors.h"
#include "libmaple.h"
#include "usb_config.h"
const USB_Descriptor_Device usbVcomDescriptor_Device = {
- bLength: sizeof(USB_Descriptor_Device),
+ bLength: sizeof(USB_Descriptor_Device),
bDescriptorType: USB_DESCRIPTOR_TYPE_DEVICE,
bcdUSB: 0x0200,
bDeviceClass: USB_DEVICE_CLASS_CDC,
@@ -29,7 +52,8 @@ const USB_Descriptor_Config usbVcomDescriptor_Config = {
bNumInterfaces: 0x02,
bConfigurationValue: 0x01,
iConfiguration: 0x00,
- bmAttributes: (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED),
+ bmAttributes: (USB_CONFIG_ATTR_BUSPOWERED |
+ USB_CONFIG_ATTR_SELF_POWERED),
bMaxPower: USB_CONFIG_MAX_POWER,
CCI_Interface:
@@ -77,7 +101,7 @@ const USB_Descriptor_Config usbVcomDescriptor_Config = {
Data: {0x00, 0x01}
},
- // ManagementEndpoint:
+ // ManagementEndpoint:
// {
EP1_bLength: 0x07,//sizeof(USB_Descriptor_Endpoint),
EP1_bDescriptorType: USB_DESCRIPTOR_TYPE_ENDPOINT,
@@ -126,12 +150,12 @@ const USB_Descriptor_Config usbVcomDescriptor_Config = {
// }
};
-/*
+/*
String Identifiers:
we may choose to specify any or none of the following string
identifiers:
-
+
iManufacturer: LeafLabs
iProduct: Maple R3
iSerialNumber: NONE
@@ -143,7 +167,7 @@ const USB_Descriptor_Config usbVcomDescriptor_Config = {
which is 0x0409 for US English
*/
-const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] =
+const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] =
{
USB_DESCRIPTOR_STRING_LEN(1),
USB_DESCRIPTOR_TYPE_STRING,
@@ -151,18 +175,18 @@ const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] =
0x04
};
-const uint8 usbVcomDescriptor_iManufacturer[USB_DESCRIPTOR_STRING_LEN(8)] =
+const uint8 usbVcomDescriptor_iManufacturer[USB_DESCRIPTOR_STRING_LEN(8)] =
{
USB_DESCRIPTOR_STRING_LEN(8),
USB_DESCRIPTOR_TYPE_STRING,
- 'L', 0, 'e', 0, 'a', 0, 'f', 0,
+ 'L', 0, 'e', 0, 'a', 0, 'f', 0,
'L', 0, 'a', 0, 'b', 0, 's', 0
};
-const uint8 usbVcomDescriptor_iProduct[USB_DESCRIPTOR_STRING_LEN(8)] =
+const uint8 usbVcomDescriptor_iProduct[USB_DESCRIPTOR_STRING_LEN(8)] =
{
USB_DESCRIPTOR_STRING_LEN(8),
USB_DESCRIPTOR_TYPE_STRING,
- 'M', 0, 'a', 0, 'p', 0, 'l', 0,
+ 'M', 0, 'a', 0, 'p', 0, 'l', 0,
'e', 0, ' ', 0, 'R', 0, '3', 0
};
diff --git a/libmaple/usb/descriptors.h b/libmaple/usb/descriptors.h
index 6652942..6f7d08b 100644
--- a/libmaple/usb/descriptors.h
+++ b/libmaple/usb/descriptors.h
@@ -1,4 +1,27 @@
-/* insert license */
+/* *****************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 LeafLabs LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * ****************************************************************************/
+
#ifndef __DESCRIPTORS_H
#define __DESCRIPTORS_H
diff --git a/libmaple/usb/usb.c b/libmaple/usb/usb.c
index 026d7f0..d875785 100644
--- a/libmaple/usb/usb.c
+++ b/libmaple/usb/usb.c
@@ -1,30 +1,30 @@
-/* *****************************************************************************
+/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- * ****************************************************************************/
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
/**
- * @file usb.c
- *
* @brief usb-specific hardware setup, NVIC, clocks, and usb activities
* in the pre-attached state. includes some of the lower level callbacks
* needed by the usb library, like suspend,resume,init,etc
@@ -47,87 +47,75 @@ volatile uint16 wIstr = 0;
volatile bIntPackSOF = 0;
DEVICE Device_Table =
- {
- NUM_ENDPTS,
- 1
- };
+ {NUM_ENDPTS,
+ 1};
DEVICE_PROP Device_Property =
- {
- usbInit,
- usbReset,
- usbStatusIn,
- usbStatusOut,
- usbDataSetup,
- usbNoDataSetup,
- usbGetInterfaceSetting,
- usbGetDeviceDescriptor,
- usbGetConfigDescriptor,
- usbGetStringDescriptor,
- 0,
- bMaxPacketSize
- };
+ {usbInit,
+ usbReset,
+ usbStatusIn,
+ usbStatusOut,
+ usbDataSetup,
+ usbNoDataSetup,
+ usbGetInterfaceSetting,
+ usbGetDeviceDescriptor,
+ usbGetConfigDescriptor,
+ usbGetStringDescriptor,
+ 0,
+ bMaxPacketSize};
USER_STANDARD_REQUESTS User_Standard_Requests =
- {
- NOP_Process,
- usbSetConfiguration,
- NOP_Process,
- NOP_Process,
- NOP_Process,
- NOP_Process,
- NOP_Process,
- NOP_Process,
- usbSetDeviceAddress
- };
+ {NOP_Process,
+ usbSetConfiguration,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ usbSetDeviceAddress};
void (*pEpInt_IN[7])(void) =
-{
- vcomDataTxCb,
- vcomManagementCb,
- NOP_Process,
- NOP_Process,
- NOP_Process,
- NOP_Process,
- NOP_Process,
-};
+ {vcomDataTxCb,
+ vcomManagementCb,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process};
void (*pEpInt_OUT[7])(void) =
-{
- NOP_Process,
- NOP_Process,
- vcomDataRxCb,
- NOP_Process,
- NOP_Process,
- NOP_Process,
- NOP_Process,
-};
-
-struct
-{
+ {NOP_Process,
+ NOP_Process,
+ vcomDataRxCb,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process};
+
+struct {
volatile RESUME_STATE eState;
volatile uint8 bESOFcnt;
} ResumeS;
void setupUSB (void) {
gpio_set_mode(USB_DISC_BANK,
- USB_DISC_PIN,
- GPIO_MODE_OUTPUT_PP);
+ USB_DISC_PIN,
+ GPIO_MODE_OUTPUT_PP);
/* setup the apb1 clock for USB */
pRCC->APB1ENR |= 0x00800000;
/* initialize the usb application */
- gpio_write_bit(USB_DISC_BANK, USB_DISC_PIN, 0); /* present ourselves to the host */
-
- USB_Init(); /* low level init routine provided by st lib */
+ gpio_write_bit(USB_DISC_BANK, USB_DISC_PIN, 0); // presents us to the host
+ USB_Init(); // low level init routine provided by the ST library
}
void disableUSB (void) {
// These are just guesses about how to do this
// TODO: real disable function
usbDsbISR();
- gpio_write_bit(USB_DISC_BANK,USB_DISC_PIN,1);
+ gpio_write_bit(USB_DISC_BANK,USB_DISC_PIN,1);
}
void usbSuspend(void) {
@@ -188,13 +176,12 @@ void usbResume(RESUME_STATE eResumeSetVal) {
break;
case RESUME_ON:
ResumeS.bESOFcnt--;
- if (ResumeS.bESOFcnt == 0)
- {
- wCNTR = _GetCNTR();
- wCNTR &= (~CNTR_RESUME);
- _SetCNTR(wCNTR);
- ResumeS.eState = RESUME_OFF;
- }
+ if (ResumeS.bESOFcnt == 0) {
+ wCNTR = _GetCNTR();
+ wCNTR &= (~CNTR_RESUME);
+ _SetCNTR(wCNTR);
+ ResumeS.eState = RESUME_OFF;
+ }
break;
case RESUME_OFF:
case RESUME_ESOF:
@@ -213,7 +200,7 @@ RESULT usbPowerOn(void) {
wInterrupt_Mask = 0;
_SetCNTR(wInterrupt_Mask);
_SetISTR(0);
- wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; /* the bare minimum */
+ wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; // the bare minimum
_SetCNTR(wInterrupt_Mask);
return USB_SUCCESS;
@@ -284,60 +271,51 @@ if (wIstr & ISTR_ERR & wInterrupt_Mask)
#if (ISR_MSK & ISTR_WKUP)
-if (wIstr & ISTR_WKUP & wInterrupt_Mask)
- {
+if (wIstr & ISTR_WKUP & wInterrupt_Mask) {
_SetISTR((u16)CLR_WKUP);
usbResume(RESUME_EXTERNAL);
- }
+}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (ISR_MSK & ISTR_SUSP)
-if (wIstr & ISTR_SUSP & wInterrupt_Mask)
- {
-
+if (wIstr & ISTR_SUSP & wInterrupt_Mask) {
/* check if SUSPEND is possible */
- if (F_SUSPEND_ENABLED)
- {
- usbSuspend();
- }
- else
- {
- /* if not possible then resume after xx ms */
- usbResume(RESUME_LATER);
- }
+ if (F_SUSPEND_ENABLED) {
+ usbSuspend();
+ } else {
+ /* if not possible then resume after xx ms */
+ usbResume(RESUME_LATER);
+ }
/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
_SetISTR((u16)CLR_SUSP);
- }
+}
#endif
#if (ISR_MSK & ISTR_SOF)
-if (wIstr & ISTR_SOF & wInterrupt_Mask)
- {
+if (wIstr & ISTR_SOF & wInterrupt_Mask) {
_SetISTR((u16)CLR_SOF);
bIntPackSOF++;
- }
+ }
#endif
#if (ISR_MSK & ISTR_ESOF)
-if (wIstr & ISTR_ESOF & wInterrupt_Mask)
- {
+if (wIstr & ISTR_ESOF & wInterrupt_Mask) {
_SetISTR((u16)CLR_ESOF);
/* resume handling timing is made with ESOFs */
usbResume(RESUME_ESOF); /* request without change of the machine state */
- }
+ }
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (ISR_MSK & ISTR_CTR)
-if (wIstr & ISTR_CTR & wInterrupt_Mask)
- {
+if (wIstr & ISTR_CTR & wInterrupt_Mask) {
/* servicing of the endpoint correct transfer interrupt */
/* clear of the CTR flag into the sub */
CTR_LP(); /* low priority ISR defined in the usb core lib */
- }
+ }
#endif
}
@@ -349,87 +327,73 @@ void usbWaitReset(void) {
/* This low-level send bytes function is NON-BLOCKING; blocking behavior, with
* a timeout, is implemented in usercode (or in the Wirish C++ high level
- * implementation).
+ * implementation).
*
* This function will quickly copy up to 64 bytes of data (out of an
* arbitrarily large buffer) into the USB peripheral TX buffer and return the
* number placed in that buffer. It is up to usercode to divide larger packets
- * into 64-byte chunks to guarantee delivery. Use usbGetCountTx() to determine
- * whether the bytes were ACTUALLY recieved by the host or just transfered to
- * the buffer.
+ * into 64-byte chunks to guarantee delivery.
*
- * The function will return -1 if it doesn't think that the USB host is
- * "connected", but it can't detect this state robustly. "Connected" in this
- * context means that an actual program on the Host operating system is
- * connected to the virtual COM/ttyACM device and is recieving the bytes; the
- * Host operating system is almost always configured and keeping this endpoint
- * alive, but the bytes never get read out of the endpoint buffer.
*
- * The behavior of this function is subtle and frustrating; it has gone through
- * many simpler and cleaner implementation that frustratingly don't work cross
- * platform.
- *
- * */
-uint16 usbSendBytes(uint8* sendBuf, uint16 len) {
-
- uint16 loaded = 0;
-
- if (bDeviceState != CONFIGURED || (!usbGetDTR() && !usbGetRTS())) {
- // Indicates to caller to stop trying, were not configured/connected
- // The DTR and RTS lines are handled differently on major platforms, so
- // the above logic is unreliable
- return 0;
- }
+ */
+void usbBlockingSendByte(char ch) {
+ while (countTx);
+ UserToPMABufferCopy(&ch,VCOM_TX_ADDR,1);
+ _SetEPTxCount(VCOM_TX_ENDP,1);
+ _SetEPTxValid(VCOM_TX_ENDP);
+ countTx = 1;
+ while (countTx);
+}
+uint32 usbSendBytes(uint8* sendBuf, uint32 len) {
+ /* any checks on connection (via dtr/rts) done upstream in wirish or
+ by user */
- // Due to a variety of shit this is how we roll; all buffering etc is pushed
- // upstream
- if (countTx) {
- return 0;
+ /* last xmit hasnt finished, abort */
+ if (countTx) {
+ return 0;
}
// We can only put VCOM_TX_EPSIZE bytes in the buffer
- if(len > VCOM_TX_EPSIZE) {
- loaded = VCOM_TX_EPSIZE;
- } else {
- loaded = len;
+ if(len > VCOM_TX_EPSIZE/2) {
+ len = VCOM_TX_EPSIZE/2;
}
// Try to load some bytes if we can
- if (loaded) {
- UserToPMABufferCopy(sendBuf,VCOM_TX_ADDR + countTx, loaded);
- _SetEPTxCount(VCOM_TX_ENDP, countTx+loaded);
+ if (len) {
+ UserToPMABufferCopy(sendBuf,VCOM_TX_ADDR, len);
+ _SetEPTxCount(VCOM_TX_ENDP, len);
+ countTx += len;
_SetEPTxValid(VCOM_TX_ENDP);
- countTx += loaded;
}
- return loaded;
+ return len;
}
/* returns the number of available bytes are in the recv FIFO */
-uint8 usbBytesAvailable(void) {
- return VCOM_RX_EPSIZE - maxNewBytes;
+uint32 usbBytesAvailable(void) {
+ return newBytes;
}
/* copies len bytes from the local recieve FIFO (not
usb packet buffer) into recvBuf and deq's the fifo.
will only copy the minimum of len or the available
bytes. returns the number of bytes copied */
-uint8 usbReceiveBytes(uint8* recvBuf, uint8 len) {
- if (len > VCOM_RX_EPSIZE - maxNewBytes) {
- len = VCOM_RX_EPSIZE - maxNewBytes;
+uint32 usbReceiveBytes(uint8* recvBuf, uint32 len) {
+ if (len > newBytes) {
+ len = newBytes;
}
int i;
for (i=0;i<len;i++) {
- recvBuf[i] = (uint8)(vcomBufferRx[recvBufOut]);
- recvBufOut = (recvBufOut + 1) % VCOM_RX_EPSIZE;
+ recvBuf[i] = (uint8)(vcomBufferRx[i]);
}
- maxNewBytes += len;
+ newBytes -= len;
/* re-enable the rx endpoint which we had set to receive 0 bytes */
- if (maxNewBytes - len == 0) {
- SetEPRxCount(VCOM_RX_ENDP,maxNewBytes);
+ if (newBytes == 0) {
+ SetEPRxCount(VCOM_RX_ENDP,VCOM_RX_EPSIZE);
+ SetEPRxStatus(VCOM_RX_ENDP,EP_RX_VALID);
}
return len;
@@ -466,7 +430,7 @@ uint8 usbIsConfigured() {
uint8 usbIsConnected() {
return (bDeviceState != UNCONNECTED);
-}
+}
uint16 usbGetPending() {
return countTx;
diff --git a/libmaple/usb/usb.h b/libmaple/usb/usb.h
index ec179b1..0ed02e5 100644
--- a/libmaple/usb/usb.h
+++ b/libmaple/usb/usb.h
@@ -1,8 +1,31 @@
-/* insert license */
-
-#ifndef __USB_H
-#define __USB_H
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 LeafLabs LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+#ifndef _USB_H_
+#define _USB_H_
#include "usb_lib.h"
#include "libmaple.h"
@@ -11,8 +34,7 @@
extern "C" {
#endif
-typedef enum
- {
+typedef enum {
RESUME_EXTERNAL,
RESUME_INTERNAL,
RESUME_LATER,
@@ -21,51 +43,50 @@ typedef enum
RESUME_ON,
RESUME_OFF,
RESUME_ESOF
- } RESUME_STATE;
+} RESUME_STATE;
-typedef enum
- {
+typedef enum {
UNCONNECTED,
ATTACHED,
POWERED,
SUSPENDED,
ADDRESSED,
CONFIGURED
- } DEVICE_STATE;
+} DEVICE_STATE;
+
+extern volatile uint32 bDeviceState;
- extern volatile uint32 bDeviceState;
+void setupUSB(void);
+void disableUSB(void);
+void usbSuspend(void);
+void usbResumeInit(void);
+void usbResume(RESUME_STATE);
- void setupUSB(void);
- void disableUSB(void);
- void usbSuspend(void);
- void usbResumeInit(void);
- void usbResume(RESUME_STATE);
-
- RESULT usbPowerOn(void);
- RESULT usbPowerOff(void);
-
- void usbDsbISR(void);
- void usbEnbISR(void);
+RESULT usbPowerOn(void);
+RESULT usbPowerOff(void);
- /* overloaded ISR routine, this is the main usb ISR */
- void usb_lpIRQHandler(void);
- void usbWaitReset(void);
+void usbDsbISR(void);
+void usbEnbISR(void);
- /* blocking functions for send/receive */
- uint16 usbSendBytes(uint8* sendBuf,uint16 len);
- uint8 usbBytesAvailable(void);
- uint8 usbReceiveBytes(uint8* recvBuf, uint8 len);
- uint8 usbGetDTR(void);
- uint8 usbGetRTS(void);
- uint8 usbIsConnected(void);
- uint8 usbIsConfigured(void);
- uint16 usbGetPending(void);
+/* overloaded ISR routine, this is the main usb ISR */
+void usb_lpIRQHandler(void);
+void usbWaitReset(void);
- void usbSendHello(void);
+/* blocking functions for send/receive */
+void usbBlockingSendByte(char ch);
+uint32 usbSendBytes(uint8* sendBuf,uint32 len);
+uint32 usbBytesAvailable(void);
+uint32 usbReceiveBytes(uint8* recvBuf, uint32 len);
+uint8 usbGetDTR(void);
+uint8 usbGetRTS(void);
+uint8 usbIsConnected(void);
+uint8 usbIsConfigured(void);
+uint16 usbGetPending(void);
+void usbSendHello(void);
#ifdef __cplusplus
} // extern "C"
#endif
-#endif //_USB_H
+#endif // _USB_H_
diff --git a/libmaple/usb/usb_callbacks.c b/libmaple/usb/usb_callbacks.c
index 4cdaf73..ccb0fdd 100644
--- a/libmaple/usb/usb_callbacks.c
+++ b/libmaple/usb/usb_callbacks.c
@@ -8,19 +8,19 @@
#include "usb_hardware.h"
ONE_DESCRIPTOR Device_Descriptor = {
- (uint8*)&usbVcomDescriptor_Device,
- sizeof(USB_Descriptor_Device)
+ (uint8*)&usbVcomDescriptor_Device,
+ sizeof(USB_Descriptor_Device)
};
ONE_DESCRIPTOR Config_Descriptor = {
- (uint8*)&usbVcomDescriptor_Config,
- 0x43//sizeof(USB_Descriptor_Config)
+ (uint8*)&usbVcomDescriptor_Config,
+ 0x43//sizeof(USB_Descriptor_Config)
};
ONE_DESCRIPTOR String_Descriptor[3] = {
- {(uint8*)&usbVcomDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)},
- {(uint8*)&usbVcomDescriptor_iManufacturer,USB_DESCRIPTOR_STRING_LEN(8)},
- {(uint8*)&usbVcomDescriptor_iProduct, USB_DESCRIPTOR_STRING_LEN(8)}
+ {(uint8*)&usbVcomDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)},
+ {(uint8*)&usbVcomDescriptor_iManufacturer,USB_DESCRIPTOR_STRING_LEN(8)},
+ {(uint8*)&usbVcomDescriptor_iProduct, USB_DESCRIPTOR_STRING_LEN(8)}
};
uint8 last_request = 0;
@@ -32,22 +32,22 @@ USB_Line_Coding line_coding = {
datatype: 0x08
};
-uint8 vcomBufferRx[VCOM_RX_EPSIZE];
-volatile uint8 countTx = 0;
-volatile uint8 recvBufIn = 0;
-volatile uint8 recvBufOut = 0;
-volatile uint8 maxNewBytes = VCOM_RX_EPSIZE;
-
+uint8 vcomBufferRx[VCOM_RX_BUFLEN];
+volatile uint32 countTx = 0;
+volatile uint32 recvBufIn = 0;
+volatile uint32 recvBufOut = 0;
+volatile uint32 maxNewBytes = VCOM_RX_BUFLEN;
+volatile uint32 newBytes = 0;
RESET_STATE reset_state = DTR_UNSET;
uint8 line_dtr_rts = 0;
void vcomDataTxCb(void) {
- /* do whatever after data has been sent to host */
-
- /* allows usbSendBytes to stop blocking */
+ /* do whatever after data has been sent to host */
+ /* allows usbSendBytes to stop blocking */
- countTx = 0;
+ /* assumes tx transactions are atomic 64 bytes (nearly certain they are) */
+ countTx = 0;
}
/* we could get arbitrarily complicated here for speed purposes
@@ -60,11 +60,11 @@ void vcomDataRxCb(void) {
/* setEPRxCount on the previous cycle should garuntee
we havnt received more bytes than we can fit */
- uint8 newBytes = GetEPRxCount(VCOM_RX_ENDP);
- /* assert (newBytes <= maxNewBytes); */
+ newBytes = GetEPRxCount(VCOM_RX_ENDP);
+ SetEPRxStatus(VCOM_RX_ENDP,EP_RX_NAK);
/* todo, not checking very carefully for edge cases. USUALLY,
- if we emit the reset pulse and send 4 bytes, then newBytes
+ if we emit the reset pulse and send 4 bytes, then newBytes
should be 4. But its POSSIBLE that this would be violated
in some cases */
@@ -82,270 +82,251 @@ void vcomDataRxCb(void) {
int i;
USB_Bool cmpMatch = TRUE;
for (i=0; i<4; i++) {
- if (chkBuf[i] != cmpBuf[i]) {
- cmpMatch = FALSE;
- }
+ if (chkBuf[i] != cmpBuf[i]) {
+ cmpMatch = FALSE;
+ }
}
if (cmpMatch) {
- asm volatile("mov r0, %[stack_top] \n\t" // Reset the stack
- "mov sp, r0 \n\t"
- "mov r0, #1 \n\t"
- "mov r1, %[target_addr] \n\t"
- "mov r2, %[cpsr] \n\t"
- "push {r2} \n\t" // Fake xPSR
- "push {r1} \n\t" // Target address for PC
- "push {r0} \n\t" // Fake LR
- "push {r0} \n\t" // Fake R12
- "push {r0} \n\t" // Fake R3
- "push {r0} \n\t" // Fake R2
- "push {r0} \n\t" // Fake R1
- "push {r0} \n\t" // Fake R0
- "mov lr, %[exc_return] \n\t"
- "bx lr"
- :
- : [stack_top] "r" (STACK_TOP),
- [target_addr] "r" (target),
- [exc_return] "r" (EXC_RETURN),
- [cpsr] "r" (DEFAULT_CPSR)
- : "r0", "r1", "r2");
- /* should never get here */
+ asm volatile("mov r0, %[stack_top] \n\t" // Reset the stack
+ "mov sp, r0 \n\t"
+ "mov r0, #1 \n\t"
+ "mov r1, %[target_addr] \n\t"
+ "mov r2, %[cpsr] \n\t"
+ "push {r2} \n\t" // Fake xPSR
+ "push {r1} \n\t" // Target address for PC
+ "push {r0} \n\t" // Fake LR
+ "push {r0} \n\t" // Fake R12
+ "push {r0} \n\t" // Fake R3
+ "push {r0} \n\t" // Fake R2
+ "push {r0} \n\t" // Fake R1
+ "push {r0} \n\t" // Fake R0
+ "mov lr, %[exc_return] \n\t"
+ "bx lr"
+ :
+ : [stack_top] "r" (STACK_TOP),
+ [target_addr] "r" (target),
+ [exc_return] "r" (EXC_RETURN),
+ [cpsr] "r" (DEFAULT_CPSR)
+ : "r0", "r1", "r2");
+ /* should never get here */
}
}
}
-
-
- if (recvBufIn + newBytes < VCOM_RX_EPSIZE) {
- PMAToUserBufferCopy(&vcomBufferRx[recvBufIn],VCOM_RX_ADDR,newBytes);
- recvBufIn += newBytes;
- } else {
- /* we have to copy the data in two chunks because we roll over
- the edge of the circular buffer */
- uint8 tailBytes = VCOM_RX_EPSIZE - recvBufIn;
- uint8 remaining = newBytes - tailBytes;
-
- PMAToUserBufferCopy(&vcomBufferRx[recvBufIn],VCOM_RX_ADDR,tailBytes);
- PMAToUserBufferCopy(&vcomBufferRx[0], VCOM_RX_ADDR,remaining);
-
- recvBufIn = (recvBufIn + newBytes ) % VCOM_RX_EPSIZE;
- }
-
- maxNewBytes -= newBytes;
- SetEPRxCount(VCOM_RX_ENDP,maxNewBytes);
- SetEPRxValid(VCOM_RX_ENDP);
+ PMAToUserBufferCopy(&vcomBufferRx[0],VCOM_RX_ADDR,newBytes);
}
void vcomManagementCb(void) {
-/* unused. This enpoint would callback if we had sent a linestate
- changed notification */
+ /* unused. This enpoint would callback if we had sent a linestate
+ changed notification */
}
u8* vcomGetSetLineCoding(uint16 length) {
- if (length == 0) {
- pInformation->Ctrl_Info.Usb_wLength = sizeof(USB_Line_Coding);
- }
- return (uint8*)&line_coding;
+ if (length == 0) {
+ pInformation->Ctrl_Info.Usb_wLength = sizeof(USB_Line_Coding);
+ }
+ return (uint8*)&line_coding;
}
vcomSetLineState(void) {
}
void usbInit(void) {
- pInformation->Current_Configuration = 0;
- usbPowerOn();
+ pInformation->Current_Configuration = 0;
+ usbPowerOn();
- _SetISTR(0);
- wInterrupt_Mask = ISR_MSK;
- _SetCNTR(wInterrupt_Mask);
+ _SetISTR(0);
+ wInterrupt_Mask = ISR_MSK;
+ _SetCNTR(wInterrupt_Mask);
- usbEnbISR();
- bDeviceState = UNCONNECTED;
+ usbEnbISR();
+ bDeviceState = UNCONNECTED;
}
void usbReset(void) {
- pInformation->Current_Configuration = 0;
-
- /* current feature is current bmAttributes */
- pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED);
-
- _SetBTABLE(USB_BTABLE_ADDRESS);
-
- /* setup control endpoint 0 */
- _SetEPType(ENDP0, EP_CONTROL);
- _SetEPTxStatus(ENDP0, EP_TX_STALL);
- _SetEPRxAddr(ENDP0,VCOM_CTRL_RX_ADDR);
- _SetEPTxAddr(ENDP0,VCOM_CTRL_TX_ADDR);
- Clear_Status_Out(ENDP0);
-
- SetEPRxCount(ENDP0, pProperty->MaxPacketSize);
- SetEPRxValid(ENDP0);
-
- /* setup management endpoint 1 */
- SetEPType (VCOM_NOTIFICATION_ENDP, EP_INTERRUPT);
- SetEPTxAddr (VCOM_NOTIFICATION_ENDP, VCOM_NOTIFICATION_ADDR);
- SetEPTxStatus (VCOM_NOTIFICATION_ENDP, EP_TX_NAK);
- SetEPRxStatus (VCOM_NOTIFICATION_ENDP, EP_RX_DIS);
-
- /* setup data endpoint OUT (rx) */
-/* SetEPType (VCOM_RX_ENDP, EP_BULK); */
-/* SetEPRxAddr (VCOM_RX_ENDP, VCOM_RX_ADDR); */
-/* SetEPRxCount (VCOM_RX_ENDP, VCOM_RX_EPSIZE); */
-/* // SetEPTxStatus (VCOM_RX_ENDP, EP_TX_DIS); */
-/* SetEPRxStatus (VCOM_RX_ENDP, EP_RX_VALID); */
-
- SetEPType (3, EP_BULK);
- SetEPRxAddr (3, 0x110);
- SetEPRxCount (3,64);
- // SetEPTxStatus (VCOM_RX_ENDP, EP_TX_DIS);
- SetEPRxStatus (3, EP_RX_VALID);
-
- /* setup data endpoint IN (tx) */
- SetEPType (VCOM_TX_ENDP, EP_BULK);
- SetEPTxAddr (VCOM_TX_ENDP, VCOM_TX_ADDR);
- SetEPTxStatus (VCOM_TX_ENDP, EP_TX_NAK);
- SetEPRxStatus (VCOM_TX_ENDP, EP_RX_DIS);
-
- bDeviceState = ATTACHED;
- SetDeviceAddress(0);
-
- /* reset the rx fifo */
- recvBufIn = 0;
- recvBufOut = 0;
- maxNewBytes = VCOM_RX_EPSIZE;
- countTx = 0;
+ pInformation->Current_Configuration = 0;
+
+ /* current feature is current bmAttributes */
+ pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED);
+
+ _SetBTABLE(USB_BTABLE_ADDRESS);
+
+ /* setup control endpoint 0 */
+ _SetEPType(ENDP0, EP_CONTROL);
+ _SetEPTxStatus(ENDP0, EP_TX_STALL);
+ _SetEPRxAddr(ENDP0,VCOM_CTRL_RX_ADDR);
+ _SetEPTxAddr(ENDP0,VCOM_CTRL_TX_ADDR);
+ Clear_Status_Out(ENDP0);
+
+ SetEPRxCount(ENDP0, pProperty->MaxPacketSize);
+ SetEPRxValid(ENDP0);
+
+ /* setup management endpoint 1 */
+ SetEPType (VCOM_NOTIFICATION_ENDP, EP_INTERRUPT);
+ SetEPTxAddr (VCOM_NOTIFICATION_ENDP, VCOM_NOTIFICATION_ADDR);
+ SetEPTxStatus (VCOM_NOTIFICATION_ENDP, EP_TX_NAK);
+ SetEPRxStatus (VCOM_NOTIFICATION_ENDP, EP_RX_DIS);
+
+ /* setup data endpoint OUT (rx) */
+ /* SetEPType (VCOM_RX_ENDP, EP_BULK); */
+ /* SetEPRxAddr (VCOM_RX_ENDP, VCOM_RX_ADDR); */
+ /* SetEPRxCount (VCOM_RX_ENDP, VCOM_RX_EPSIZE); */
+ /* // SetEPTxStatus (VCOM_RX_ENDP, EP_TX_DIS); */
+ /* SetEPRxStatus (VCOM_RX_ENDP, EP_RX_VALID); */
+
+ SetEPType (3, EP_BULK);
+ SetEPRxAddr (3, 0x110);
+ SetEPRxCount (3,64);
+ // SetEPTxStatus (VCOM_RX_ENDP, EP_TX_DIS);
+ SetEPRxStatus (3, EP_RX_VALID);
+
+ /* setup data endpoint IN (tx) */
+ SetEPType (VCOM_TX_ENDP, EP_BULK);
+ SetEPTxAddr (VCOM_TX_ENDP, VCOM_TX_ADDR);
+ SetEPTxStatus (VCOM_TX_ENDP, EP_TX_NAK);
+ SetEPRxStatus (VCOM_TX_ENDP, EP_RX_DIS);
+
+ bDeviceState = ATTACHED;
+ SetDeviceAddress(0);
+
+ /* reset the rx fifo */
+ recvBufIn = 0;
+ recvBufOut = 0;
+ maxNewBytes = VCOM_RX_EPSIZE;
+ countTx = 0;
}
void usbStatusIn(void) {
- /* adjust the usart line coding
- if we wish to couple the CDC line coding
- with the real usart port */
+ /* adjust the usart line coding
+ if we wish to couple the CDC line coding
+ with the real usart port */
}
void usbStatusOut(void) {
}
RESULT usbDataSetup(uint8 request) {
- uint8 *(*CopyRoutine)(uint16);
- CopyRoutine = NULL;
-
- if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
- switch (request) {
- case (GET_LINE_CODING):
- CopyRoutine = vcomGetSetLineCoding;
- last_request = GET_LINE_CODING;
- break;
- case (SET_LINE_CODING):
- CopyRoutine = vcomGetSetLineCoding;
- last_request = SET_LINE_CODING;
- break;
- default: break;
+ uint8 *(*CopyRoutine)(uint16);
+ CopyRoutine = NULL;
+
+ if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
+ switch (request) {
+ case (GET_LINE_CODING):
+ CopyRoutine = vcomGetSetLineCoding;
+ last_request = GET_LINE_CODING;
+ break;
+ case (SET_LINE_CODING):
+ CopyRoutine = vcomGetSetLineCoding;
+ last_request = SET_LINE_CODING;
+ break;
+ default: break;
+ }
}
- }
- if (CopyRoutine == NULL) {
- return USB_UNSUPPORT;
- }
+ if (CopyRoutine == NULL) {
+ return USB_UNSUPPORT;
+ }
- pInformation->Ctrl_Info.CopyData = CopyRoutine;
- pInformation->Ctrl_Info.Usb_wOffset = 0;
- (*CopyRoutine)(0);
- return USB_SUCCESS;
+ pInformation->Ctrl_Info.CopyData = CopyRoutine;
+ pInformation->Ctrl_Info.Usb_wOffset = 0;
+ (*CopyRoutine)(0);
+ return USB_SUCCESS;
}
RESULT usbNoDataSetup(u8 request) {
- uint8 new_signal;
-
- /* we support set com feature but dont handle it */
- if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
-
- switch (request) {
- case (SET_COMM_FEATURE):
- return USB_SUCCESS;
- case (SET_CONTROL_LINE_STATE):
- /* to reset the board, pull both dtr and rts low
- then pulse dtr by itself */
- new_signal = pInformation->USBwValues.bw.bb0 & (CONTROL_LINE_DTR | CONTROL_LINE_RTS);
- line_dtr_rts = new_signal & 0x03;
-
- switch (reset_state) {
- /* no default, covered enum */
- case DTR_UNSET:
- if ((new_signal & CONTROL_LINE_DTR) == 0 ) {
- reset_state = DTR_LOW;
- } else {
- reset_state = DTR_HIGH;
- }
- break;
-
- case DTR_HIGH:
- if ((new_signal & CONTROL_LINE_DTR) == 0 ) {
- reset_state = DTR_NEGEDGE;
- } else {
- reset_state = DTR_HIGH;
- }
- break;
-
- case DTR_NEGEDGE:
- if ((new_signal & CONTROL_LINE_DTR) == 0 ) {
- reset_state = DTR_LOW;
- } else {
- reset_state = DTR_HIGH;
- }
- break;
-
- case DTR_LOW:
- if ((new_signal & CONTROL_LINE_DTR) == 0 ) {
- reset_state = DTR_LOW;
- } else {
- reset_state = DTR_HIGH;
- }
- break;
- }
-
- return USB_SUCCESS;
+ uint8 new_signal;
+
+ /* we support set com feature but dont handle it */
+ if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
+
+ switch (request) {
+ case (SET_COMM_FEATURE):
+ return USB_SUCCESS;
+ case (SET_CONTROL_LINE_STATE):
+ /* to reset the board, pull both dtr and rts low
+ then pulse dtr by itself */
+ new_signal = pInformation->USBwValues.bw.bb0 & (CONTROL_LINE_DTR | CONTROL_LINE_RTS);
+ line_dtr_rts = new_signal & 0x03;
+
+ switch (reset_state) {
+ /* no default, covered enum */
+ case DTR_UNSET:
+ if ((new_signal & CONTROL_LINE_DTR) == 0 ) {
+ reset_state = DTR_LOW;
+ } else {
+ reset_state = DTR_HIGH;
+ }
+ break;
+
+ case DTR_HIGH:
+ if ((new_signal & CONTROL_LINE_DTR) == 0 ) {
+ reset_state = DTR_NEGEDGE;
+ } else {
+ reset_state = DTR_HIGH;
+ }
+ break;
+
+ case DTR_NEGEDGE:
+ if ((new_signal & CONTROL_LINE_DTR) == 0 ) {
+ reset_state = DTR_LOW;
+ } else {
+ reset_state = DTR_HIGH;
+ }
+ break;
+
+ case DTR_LOW:
+ if ((new_signal & CONTROL_LINE_DTR) == 0 ) {
+ reset_state = DTR_LOW;
+ } else {
+ reset_state = DTR_HIGH;
+ }
+ break;
+ }
+
+ return USB_SUCCESS;
+ }
}
- }
- return USB_UNSUPPORT;
+ return USB_UNSUPPORT;
}
RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting) {
- if (alt_setting > 0) {
- return USB_UNSUPPORT;
- } else if (interface > 1) {
- return USB_UNSUPPORT;
- }
+ if (alt_setting > 0) {
+ return USB_UNSUPPORT;
+ } else if (interface > 1) {
+ return USB_UNSUPPORT;
+ }
- return USB_SUCCESS;
+ return USB_SUCCESS;
}
u8* usbGetDeviceDescriptor(u16 length) {
- return Standard_GetDescriptorData(length, &Device_Descriptor);
+ return Standard_GetDescriptorData(length, &Device_Descriptor);
}
u8* usbGetConfigDescriptor(u16 length) {
- return Standard_GetDescriptorData(length, &Config_Descriptor);
+ return Standard_GetDescriptorData(length, &Config_Descriptor);
}
u8* usbGetStringDescriptor(u16 length) {
- uint8 wValue0 = pInformation->USBwValue0;
+ uint8 wValue0 = pInformation->USBwValue0;
- if (wValue0 > 2) {
- return NULL;
- }
- return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]);
+ if (wValue0 > 2) {
+ return NULL;
+ }
+ return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]);
}
/* internal callbacks to respond to standard requests */
void usbSetConfiguration(void) {
- if (pInformation->Current_Configuration != 0) {
- bDeviceState = CONFIGURED;
- }
+ if (pInformation->Current_Configuration != 0) {
+ bDeviceState = CONFIGURED;
+ }
}
void usbSetDeviceAddress(void) {
- bDeviceState = ADDRESSED;
+ bDeviceState = ADDRESSED;
}
diff --git a/libmaple/usb/usb_callbacks.h b/libmaple/usb/usb_callbacks.h
index a94de11..20d2c13 100644
--- a/libmaple/usb/usb_callbacks.h
+++ b/libmaple/usb/usb_callbacks.h
@@ -34,11 +34,12 @@ typedef enum {
extern RESET_STATE reset_state; /* tracks DTR/RTS */
extern uint8 line_dtr_rts;
-extern volatile uint8 countTx;
-extern uint8 vcomBufferRx[VCOM_RX_EPSIZE]; /* no reason this has to be VCOM_RX_EPSIZE, could be bigger */
-extern volatile uint8 recvBufIn; /* the FIFO in index to the recvbuffer */
-extern volatile uint8 recvBufOut; /* the FIFO out index to the recvbuffer */
-extern volatile uint8 maxNewBytes;
+extern volatile uint32 countTx;
+extern uint8 vcomBufferRx[VCOM_RX_BUFLEN]; /* no reason this has to be VCOM_RX_EPSIZE, could be bigger */
+extern volatile uint32 recvBufIn; /* the FIFO in index to the recvbuffer */
+extern volatile uint32 recvBufOut; /* the FIFO out index to the recvbuffer */
+extern volatile uint32 maxNewBytes;
+extern volatile uint32 newBytes;
void vcomDataTxCb(void);
void vcomDataRxCb(void);
diff --git a/libmaple/usb/usb_config.h b/libmaple/usb/usb_config.h
index ba05d42..e5f3979 100644
--- a/libmaple/usb/usb_config.h
+++ b/libmaple/usb/usb_config.h
@@ -26,6 +26,7 @@
#define VCOM_RX_EPNUM 0x03
#define VCOM_RX_ADDR 0x110
#define VCOM_RX_EPSIZE 0x40
+#define VCOM_RX_BUFLEN (VCOM_RX_EPSIZE*3)
#define bMaxPacketSize 0x40 /* 64B, maximum for USB FS Devices */
diff --git a/libmaple/usb/usb_hardware.c b/libmaple/usb/usb_hardware.c
index 2f37df6..505dcf1 100644
--- a/libmaple/usb/usb_hardware.c
+++ b/libmaple/usb/usb_hardware.c
@@ -1,29 +1,31 @@
-/* *****************************************************************************
+/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- * ****************************************************************************/
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
/**
- * @file hardware.c
+ * @file usb_hardware.c
*
* @brief init routines to setup clocks and interrupts for usb.
*
@@ -32,97 +34,106 @@
#include "usb_hardware.h"
void setPin(u32 bank, u8 pin) {
- u32 pinMask = 0x1 << (pin);
- SET_REG(GPIO_BSRR(bank),pinMask);
+ u32 pinMask = 0x1 << (pin);
+ SET_REG(GPIO_BSRR(bank),pinMask);
}
void resetPin(u32 bank, u8 pin) {
- u32 pinMask = 0x1 << (16+pin);
- SET_REG(GPIO_BSRR(bank),pinMask);
+ u32 pinMask = 0x1 << (16+pin);
+ SET_REG(GPIO_BSRR(bank),pinMask);
}
void systemReset(void) {
- SET_REG(RCC_CR, GET_REG(RCC_CR) | 0x00000001);
- SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xF8FF0000);
- SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFEF6FFFF);
- SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFFFBFFFF);
- SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xFF80FFFF);
+ SET_REG(RCC_CR, GET_REG(RCC_CR) | 0x00000001);
+ SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xF8FF0000);
+ SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFEF6FFFF);
+ SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFFFBFFFF);
+ SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xFF80FFFF);
- SET_REG(RCC_CIR, 0x00000000); /* disable all RCC interrupts */
+ SET_REG(RCC_CIR, 0x00000000); // disable all RCC interrupts
}
void setupCLK (void) {
- /* enable HSE */
- SET_REG(RCC_CR,GET_REG(RCC_CR) | 0x00010001);
- while ((GET_REG(RCC_CR) & 0x00020000) == 0); /* for it to come on */
-
- /* Configure PLL */
- SET_REG(RCC_CFGR,GET_REG(RCC_CFGR) | 0x001D0400); /* pll=72Mhz,APB1=36Mhz,AHB=72Mhz */
- SET_REG(RCC_CR,GET_REG(RCC_CR) | 0x01000000); /* enable the pll */
- while ((GET_REG(RCC_CR) & 0x03000000) == 0); /* wait for it to come on */
-
- /* Set SYSCLK as PLL */
- SET_REG(RCC_CFGR,GET_REG(RCC_CFGR) | 0x00000002);
- while ((GET_REG(RCC_CFGR) & 0x00000008) == 0); /* wait for it to come on */
+ /* enable HSE */
+ SET_REG(RCC_CR,GET_REG(RCC_CR) | 0x00010001);
+ /* for it to come on */
+ while ((GET_REG(RCC_CR) & 0x00020000) == 0);
+
+ /* Configure PLL */
+ /* pll=72Mhz,APB1=36Mhz,AHB=72Mhz */
+ SET_REG(RCC_CFGR,GET_REG(RCC_CFGR) | 0x001D0400);
+ /* enable the pll */
+ SET_REG(RCC_CR,GET_REG(RCC_CR) | 0x01000000);
+ /* wait for it to come on */
+ while ((GET_REG(RCC_CR) & 0x03000000) == 0);
+
+ /* Set SYSCLK as PLL */
+ SET_REG(RCC_CFGR,GET_REG(RCC_CFGR) | 0x00000002);
+ /* wait for it to come on */
+ while ((GET_REG(RCC_CFGR) & 0x00000008) == 0);
}
void nvicInit(NVIC_InitTypeDef* NVIC_InitStruct) {
- u32 tmppriority = 0x00;
- u32 tmpreg = 0x00;
- u32 tmpmask = 0x00;
- u32 tmppre = 0;
- u32 tmpsub = 0x0F;
-
- SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE;
- NVIC_TypeDef* rNVIC = (NVIC_TypeDef *) NVIC_BASE;
-
-
- /* Compute the Corresponding IRQ Priority --------------------------------*/
- tmppriority = (0x700 - (rSCB->AIRCR & (u32)0x700))>> 0x08;
- tmppre = (0x4 - tmppriority);
- tmpsub = tmpsub >> tmppriority;
-
- tmppriority = (u32)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
- tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
-
- tmppriority = tmppriority << 0x04;
- tmppriority = ((u32)tmppriority) << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08);
-
- tmpreg = rNVIC->IPR[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)];
- tmpmask = (u32)0xFF << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08);
- tmpreg &= ~tmpmask;
- tmppriority &= tmpmask;
- tmpreg |= tmppriority;
-
- rNVIC->IPR[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)] = tmpreg;
-
- /* Enable the Selected IRQ Channels --------------------------------------*/
- rNVIC->ISER[(NVIC_InitStruct->NVIC_IRQChannel >> 0x05)] =
- (u32)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (u8)0x1F);
+ u32 tmppriority = 0x00;
+ u32 tmpreg = 0x00;
+ u32 tmpmask = 0x00;
+ u32 tmppre = 0;
+ u32 tmpsub = 0x0F;
+
+ SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE;
+ NVIC_TypeDef* rNVIC = (NVIC_TypeDef *) NVIC_BASE;
+
+
+ /* Compute the Corresponding IRQ Priority -------------------------------*/
+ tmppriority = (0x700 - (rSCB->AIRCR & (u32)0x700))>> 0x08;
+ tmppre = (0x4 - tmppriority);
+ tmpsub = tmpsub >> tmppriority;
+
+ tmppriority = (u32)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority <<
+ tmppre;
+ tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
+
+ tmppriority = tmppriority << 0x04;
+ tmppriority = ((u32)tmppriority) <<
+ ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08);
+
+ tmpreg = rNVIC->IPR[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)];
+ tmpmask = (u32)0xFF <<
+ ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08);
+ tmpreg &= ~tmpmask;
+ tmppriority &= tmpmask;
+ tmpreg |= tmppriority;
+
+ rNVIC->IPR[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)] = tmpreg;
+
+ /* Enable the Selected IRQ Channels -------------------------------------*/
+ rNVIC->ISER[(NVIC_InitStruct->NVIC_IRQChannel >> 0x05)] =
+ (u32)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (u8)0x1F);
}
void nvicDisableInterrupts() {
- NVIC_TypeDef* rNVIC = (NVIC_TypeDef *) NVIC_BASE;
- rNVIC->ICER[0] = 0xFFFFFFFF;
- rNVIC->ICER[1] = 0xFFFFFFFF;
- rNVIC->ICPR[0] = 0xFFFFFFFF;
- rNVIC->ICPR[1] = 0xFFFFFFFF;
-
- SET_REG(STK_CTRL,0x04); /* disable the systick, which operates separately from nvic */
+ NVIC_TypeDef* rNVIC = (NVIC_TypeDef *) NVIC_BASE;
+ rNVIC->ICER[0] = 0xFFFFFFFF;
+ rNVIC->ICER[1] = 0xFFFFFFFF;
+ rNVIC->ICPR[0] = 0xFFFFFFFF;
+ rNVIC->ICPR[1] = 0xFFFFFFFF;
+
+ /* Disable the systick timer, which operates separately from NVIC */
+ SET_REG(STK_CTRL,0x04);
}
void systemHardReset(void) {
- SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE;
- typedef void (*funcPtr)(void);
-
- /* Reset */
- rSCB->AIRCR = (u32)AIRCR_RESET_REQ;
-
- /* should never get here */
- while (1) {
- asm volatile("nop");
- }
+ SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE;
+ typedef void (*funcPtr)(void);
+
+ /* Reset */
+ rSCB->AIRCR = (u32)AIRCR_RESET_REQ;
+
+ /* Should never get here */
+ while (1) {
+ asm volatile("nop");
+ }
}
diff --git a/libmaple/util.c b/libmaple/util.c
index be29e7e..135f005 100644
--- a/libmaple/util.c
+++ b/libmaple/util.c
@@ -23,8 +23,6 @@
*****************************************************************************/
/**
- * @file util.h
- *
* @brief Utility procedures for debugging, mostly an error LED fade
* and messages dumped over a uart for failed asserts.
*/
diff --git a/libmaple/util.h b/libmaple/util.h
index b6074d8..64782d9 100644
--- a/libmaple/util.h
+++ b/libmaple/util.h
@@ -77,10 +77,6 @@ void throb(void);
/* Asserts for sanity checks, redefine DEBUG_LEVEL in libmaple.h to
* compile out these checks */
-#define DEBUG_NONE 0
-#define DEBUG_FAULT 1
-#define DEBUG_ALL 2
-
#if DEBUG_LEVEL >= DEBUG_ALL
#define ASSERT(exp) \
if (exp) { \
diff --git a/libraries/LiquidCrystal/LiquidCrystal.cpp b/libraries/LiquidCrystal/LiquidCrystal.cpp
new file mode 100644
index 0000000..52f0308
--- /dev/null
+++ b/libraries/LiquidCrystal/LiquidCrystal.cpp
@@ -0,0 +1,324 @@
+#include "LiquidCrystal.h"
+
+#include <stdio.h>
+#include <string.h>
+#include "WProgram.h"
+
+// When the display powers up, it is configured as follows:
+//
+// 1. Display clear
+// 2. Function set:
+// DL = 1; 8-bit interface data
+// N = 0; 1-line display
+// F = 0; 5x8 dot character font
+// 3. Display on/off control:
+// D = 0; Display off
+// C = 0; Cursor off
+// B = 0; Blinking off
+// 4. Entry mode set:
+// I/D = 1; Increment by 1
+// S = 0; No shift
+//
+// Note, however, that resetting the Arduino doesn't reset the LCD, so we
+// can't assume that its in that state when a sketch starts (and the
+// LiquidCrystal constructor is called).
+
+// This library has been modified to be compatible with the LeafLabs Maple;
+// very conservative timing is used due to problems with delayMicroseconds()
+// that should be fixed in the 0.0.7 release of the libmaple. [bnewbold]
+
+LiquidCrystal::LiquidCrystal(uint8 rs, uint8 rw, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3,
+ uint8 d4, uint8 d5, uint8 d6, uint8 d7)
+{
+ init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
+}
+
+LiquidCrystal::LiquidCrystal(uint8 rs, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3,
+ uint8 d4, uint8 d5, uint8 d6, uint8 d7)
+{
+ init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
+}
+
+LiquidCrystal::LiquidCrystal(uint8 rs, uint8 rw, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3)
+{
+ init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
+}
+
+LiquidCrystal::LiquidCrystal(uint8 rs, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3)
+{
+ init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
+}
+
+void LiquidCrystal::init(uint8 fourbitmode, uint8 rs, uint8 rw, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3,
+ uint8 d4, uint8 d5, uint8 d6, uint8 d7)
+{
+ _rs_pin = rs;
+ _rw_pin = rw;
+ _enable_pin = enable;
+
+ _data_pins[0] = d0;
+ _data_pins[1] = d1;
+ _data_pins[2] = d2;
+ _data_pins[3] = d3;
+ _data_pins[4] = d4;
+ _data_pins[5] = d5;
+ _data_pins[6] = d6;
+ _data_pins[7] = d7;
+
+ pinMode(_rs_pin, OUTPUT);
+ // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
+ if (_rw_pin != 255) {
+ pinMode(_rw_pin, OUTPUT);
+ }
+ pinMode(_enable_pin, OUTPUT);
+
+ if (fourbitmode)
+ _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
+ else
+ _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
+
+ // TODO: bnewbold, re-enable this?
+ begin(16, 1);
+}
+
+void LiquidCrystal::begin(uint8 cols, uint8 lines, uint8 dotsize) {
+ if (lines > 1) {
+ _displayfunction |= LCD_2LINE;
+ }
+ _numlines = lines;
+ _currline = 0;
+
+ // for some 1 line displays you can select a 10 pixel high font
+ if ((dotsize != 0) && (lines == 1)) {
+ _displayfunction |= LCD_5x10DOTS;
+ }
+
+ // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
+ // according to datasheet, we need at least 40ms after power rises above 2.7V
+ // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
+ delay(50); // Maple mod
+ //delayMicroseconds(50000);
+ // Now we pull both RS and R/W low to begin commands
+ digitalWrite(_rs_pin, LOW);
+ digitalWrite(_enable_pin, LOW);
+ if (_rw_pin != 255) {
+ digitalWrite(_rw_pin, LOW);
+ }
+
+ //put the LCD into 4 bit or 8 bit mode
+ if (! (_displayfunction & LCD_8BITMODE)) {
+ // this is according to the hitachi HD44780 datasheet
+ // figure 24, pg 46
+
+ // we start in 8bit mode, try to set 4 bit mode
+ write4bits(0x03);
+ delay(5); // Maple mod
+ //delayMicroseconds(4500); // wait min 4.1ms
+
+ // second try
+ write4bits(0x03);
+ delay(5); // Maple mod
+ //delayMicroseconds(4500); // wait min 4.1ms
+
+ // third go!
+ write4bits(0x03);
+ delay(1); // Maple mod
+ //delayMicroseconds(150);
+
+ // finally, set to 8-bit interface
+ write4bits(0x02);
+ } else {
+ // this is according to the hitachi HD44780 datasheet
+ // page 45 figure 23
+
+ // Send function set command sequence
+ command(LCD_FUNCTIONSET | _displayfunction);
+ delay(5); // Maple mod
+ //delayMicroseconds(4500); // wait more than 4.1ms
+
+ // second try
+ command(LCD_FUNCTIONSET | _displayfunction);
+ delay(1); // Maple mod
+ //delayMicroseconds(150);
+
+ // third go
+ command(LCD_FUNCTIONSET | _displayfunction);
+ }
+
+ // finally, set # lines, font size, etc.
+ command(LCD_FUNCTIONSET | _displayfunction);
+
+ // turn the display on with no cursor or blinking default
+ _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
+ display();
+
+ // clear it off
+ clear();
+
+ // Initialize to default text direction (for romance languages)
+ _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
+ // set the entry mode
+ command(LCD_ENTRYMODESET | _displaymode);
+
+}
+
+/********** high level commands, for the user! */
+void LiquidCrystal::clear()
+{
+ command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
+ delay(2); // Maple mod
+ //delayMicroseconds(2000); // this command takes a long time!
+}
+
+void LiquidCrystal::home()
+{
+ command(LCD_RETURNHOME); // set cursor position to zero
+ delay(2); // Maple mod
+ //delayMicroseconds(2000); // this command takes a long time!
+}
+
+void LiquidCrystal::setCursor(uint8 col, uint8 row)
+{
+ int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
+ if ( row > _numlines ) {
+ row = _numlines-1; // we count rows starting w/0
+ }
+
+ command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
+}
+
+// Turn the display on/off (quickly)
+void LiquidCrystal::noDisplay() {
+ _displaycontrol &= ~LCD_DISPLAYON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+void LiquidCrystal::display() {
+ _displaycontrol |= LCD_DISPLAYON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+
+// Turns the underline cursor on/off
+void LiquidCrystal::noCursor() {
+ _displaycontrol &= ~LCD_CURSORON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+void LiquidCrystal::cursor() {
+ _displaycontrol |= LCD_CURSORON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+
+// Turn on and off the blinking cursor
+void LiquidCrystal::noBlink() {
+ _displaycontrol &= ~LCD_BLINKON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+void LiquidCrystal::blink() {
+ _displaycontrol |= LCD_BLINKON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+
+// These commands scroll the display without changing the RAM
+void LiquidCrystal::scrollDisplayLeft(void) {
+ command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
+}
+void LiquidCrystal::scrollDisplayRight(void) {
+ command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
+}
+
+// This is for text that flows Left to Right
+void LiquidCrystal::leftToRight(void) {
+ _displaymode |= LCD_ENTRYLEFT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// This is for text that flows Right to Left
+void LiquidCrystal::rightToLeft(void) {
+ _displaymode &= ~LCD_ENTRYLEFT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// This will 'right justify' text from the cursor
+void LiquidCrystal::autoscroll(void) {
+ _displaymode |= LCD_ENTRYSHIFTINCREMENT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// This will 'left justify' text from the cursor
+void LiquidCrystal::noAutoscroll(void) {
+ _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// Allows us to fill the first 8 CGRAM locations
+// with custom characters
+void LiquidCrystal::createChar(uint8 location, uint8 charmap[]) {
+ location &= 0x7; // we only have 8 locations 0-7
+ command(LCD_SETCGRAMADDR | (location << 3));
+ for (int i=0; i<8; i++) {
+ write(charmap[i]);
+ }
+}
+
+/*********** mid level commands, for sending data/cmds */
+
+inline void LiquidCrystal::command(uint8 value) {
+ send(value, LOW);
+}
+
+inline void LiquidCrystal::write(uint8 value) {
+ send(value, HIGH);
+}
+
+/************ low level data pushing commands **********/
+
+// write either command or data, with automatic 4/8-bit selection
+void LiquidCrystal::send(uint8 value, uint8 mode) {
+ digitalWrite(_rs_pin, mode);
+
+ // if there is a RW pin indicated, set it low to Write
+ if (_rw_pin != 255) {
+ digitalWrite(_rw_pin, LOW);
+ }
+
+ if (_displayfunction & LCD_8BITMODE) {
+ write8bits(value);
+ } else {
+ write4bits(value>>4);
+ write4bits(value);
+ }
+}
+
+void LiquidCrystal::pulseEnable(void) {
+ digitalWrite(_enable_pin, LOW);
+ delay(1); // Maple mod
+ //delayMicroseconds(1);
+ digitalWrite(_enable_pin, HIGH);
+ delay(1); // Maple mod
+ //delayMicroseconds(1); // enable pulse must be >450ns
+ digitalWrite(_enable_pin, LOW);
+ delay(1); // Maple mod
+ //delayMicroseconds(100); // commands need > 37us to settle
+}
+
+void LiquidCrystal::write4bits(uint8 value) {
+ for (int i = 0; i < 4; i++) {
+ pinMode(_data_pins[i], OUTPUT);
+ digitalWrite(_data_pins[i], (value >> i) & 0x01);
+ }
+
+ pulseEnable();
+}
+
+void LiquidCrystal::write8bits(uint8 value) {
+ for (int i = 0; i < 8; i++) {
+ pinMode(_data_pins[i], OUTPUT);
+ digitalWrite(_data_pins[i], (value >> i) & 0x01);
+ }
+
+ pulseEnable();
+}
diff --git a/libraries/LiquidCrystal/LiquidCrystal.h b/libraries/LiquidCrystal/LiquidCrystal.h
new file mode 100644
index 0000000..0baf543
--- /dev/null
+++ b/libraries/LiquidCrystal/LiquidCrystal.h
@@ -0,0 +1,105 @@
+#ifndef LiquidCrystal_h
+#define LiquidCrystal_h
+
+//#include <inttypes.h>
+#include "wirish.h"
+#include "Print.h"
+
+// commands
+#define LCD_CLEARDISPLAY 0x01
+#define LCD_RETURNHOME 0x02
+#define LCD_ENTRYMODESET 0x04
+#define LCD_DISPLAYCONTROL 0x08
+#define LCD_CURSORSHIFT 0x10
+#define LCD_FUNCTIONSET 0x20
+#define LCD_SETCGRAMADDR 0x40
+#define LCD_SETDDRAMADDR 0x80
+
+// flags for display entry mode
+#define LCD_ENTRYRIGHT 0x00
+#define LCD_ENTRYLEFT 0x02
+#define LCD_ENTRYSHIFTINCREMENT 0x01
+#define LCD_ENTRYSHIFTDECREMENT 0x00
+
+// flags for display on/off control
+#define LCD_DISPLAYON 0x04
+#define LCD_DISPLAYOFF 0x00
+#define LCD_CURSORON 0x02
+#define LCD_CURSOROFF 0x00
+#define LCD_BLINKON 0x01
+#define LCD_BLINKOFF 0x00
+
+// flags for display/cursor shift
+#define LCD_DISPLAYMOVE 0x08
+#define LCD_CURSORMOVE 0x00
+#define LCD_MOVERIGHT 0x04
+#define LCD_MOVELEFT 0x00
+
+// flags for function set
+#define LCD_8BITMODE 0x10
+#define LCD_4BITMODE 0x00
+#define LCD_2LINE 0x08
+#define LCD_1LINE 0x00
+#define LCD_5x10DOTS 0x04
+#define LCD_5x8DOTS 0x00
+
+class LiquidCrystal : public Print {
+public:
+ LiquidCrystal(uint8 rs, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3,
+ uint8 d4, uint8 d5, uint8 d6, uint8 d7);
+ LiquidCrystal(uint8 rs, uint8 rw, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3,
+ uint8 d4, uint8 d5, uint8 d6, uint8 d7);
+ LiquidCrystal(uint8 rs, uint8 rw, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3);
+ LiquidCrystal(uint8 rs, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3);
+
+ void init(uint8 fourbitmode, uint8 rs, uint8 rw, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3,
+ uint8 d4, uint8 d5, uint8 d6, uint8 d7);
+
+ void begin(uint8 cols, uint8 rows, uint8 charsize = LCD_5x8DOTS);
+
+ void clear();
+ void home();
+
+ void noDisplay();
+ void display();
+ void noBlink();
+ void blink();
+ void noCursor();
+ void cursor();
+ void scrollDisplayLeft();
+ void scrollDisplayRight();
+ void leftToRight();
+ void rightToLeft();
+ void autoscroll();
+ void noAutoscroll();
+
+ void createChar(uint8, uint8[]);
+ void setCursor(uint8, uint8);
+ virtual void write(uint8);
+ void command(uint8);
+private:
+ void send(uint8, uint8);
+ void write4bits(uint8);
+ void write8bits(uint8);
+ void pulseEnable();
+
+ uint8 _rs_pin; // LOW: command. HIGH: character.
+ uint8 _rw_pin; // LOW: write to LCD. HIGH: read from LCD.
+ uint8 _enable_pin; // activated by a HIGH pulse.
+ uint8 _data_pins[8];
+
+ uint8 _displayfunction;
+ uint8 _displaycontrol;
+ uint8 _displaymode;
+
+ uint8 _initialized;
+
+ uint8 _numlines,_currline;
+};
+
+#endif
diff --git a/libraries/LiquidCrystal/rules.mk b/libraries/LiquidCrystal/rules.mk
new file mode 100644
index 0000000..7b18203
--- /dev/null
+++ b/libraries/LiquidCrystal/rules.mk
@@ -0,0 +1,29 @@
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Local flags
+CFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES)
+
+# Local rules and targets
+cSRCS_$(d) :=
+
+cppSRCS_$(d) := LiquidCrystal.cpp
+
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \
+ $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
+
+TGT_BIN += $(OBJS_$(d))
+
+# Standard things
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
+sp := $(basename $(sp)) \ No newline at end of file
diff --git a/libraries/Servo/Servo.cpp b/libraries/Servo/Servo.cpp
new file mode 100644
index 0000000..ae87b63
--- /dev/null
+++ b/libraries/Servo/Servo.cpp
@@ -0,0 +1,138 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010, LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *****************************************************************************/
+
+#include "Servo.h"
+
+#include "boards.h"
+#include "io.h"
+#include "pwm.h"
+#include "wirish_math.h"
+
+// Configure prescaler and overflow for a 20msec period (could just
+// use HardwareTimer::setPeriod(), but this lets conversions below
+// happen more statically, in combination with an inlined map() -- a
+// premature optimization? TODO profile speed/size tradeoff)
+#define CYC_20MSEC (20000 * CYCLES_PER_MICROSECOND)
+#define SERVO_PRE ((uint16)((CYC_20MSEC >> 16) + 1))
+#define SERVO_OVF ((uint16)((CYC_20MSEC / SERVO_PRE) - 1))
+#define SERVO_TAU_USEC \
+ ((uint32)(((double)SERVO_OVF) * SERVO_PRE / CYCLES_PER_MICROSECOND + 0.5))
+
+#define US_TO_COMPARE(us) ((uint16)map(us, 0, SERVO_TAU_USEC, 0, SERVO_OVF))
+#define COMPARE_TO_US(c) ((uint32)map(c, 0, SERVO_OVF, 0, SERVO_TAU_USEC))
+
+#define ANGLE_TO_US(a) ((uint16)(map(a, 0, 180, this->min, this->max)))
+#define US_TO_ANGLE(us) ((uint8)(map(us, this->min, this->max, 0, 180)))
+
+Servo::Servo() {
+ this->pin = NOT_ATTACHED;
+ this->timer = 0;
+ this->channel = TIMER_INVALID;
+ this->min = SERVO_DEFAULT_MIN_PW;
+ this->max = SERVO_DEFAULT_MAX_PW;
+}
+
+bool Servo::attach(uint8_t pin) {
+ return this->attach(pin, SERVO_DEFAULT_MIN_PW, SERVO_DEFAULT_MAX_PW);
+}
+
+bool Servo::attach(uint8_t pin, uint16_t min, uint16_t max) {
+ timer_dev_num timer_num = PIN_MAP[pin].timer_num;
+ uint32_t channel = PIN_MAP[pin].timer_chan;
+ if (timer_num == TIMER_INVALID) {
+ // don't reset any members or ASSERT(0), to keep driving any
+ // previously attach()ed servo.
+ return false;
+ }
+ this->pin = pin;
+ this->timer = getTimer(timer_num);
+ this->channel = channel;
+ this->min = min;
+ this->max = max;
+
+ pinMode(pin, PWM);
+
+ this->timer->pause();
+ this->timer->setPrescaleFactor(SERVO_PRE);
+ this->timer->setOverflow(SERVO_OVF);
+ this->timer->generateUpdate();
+ this->timer->resume();
+ return true;
+}
+
+bool Servo::detach() {
+ if (this->pin == NOT_ATTACHED) return false;
+
+ this->timer->setChannelMode(this->channel, TIMER_DISABLED);
+
+ this->pin = NOT_ATTACHED;
+ this->timer = 0;
+ this->channel = TIMER_INVALID;
+ this->min = SERVO_DEFAULT_MIN_PW;
+ this->max = SERVO_DEFAULT_MAX_PW;
+
+ return true;
+}
+
+void Servo::write(unsigned int value) {
+ if (value < SERVO_MAX_WRITE_ANGLE) {
+ this->writeMicroseconds(ANGLE_TO_US(value));
+ } else {
+ this->writeMicroseconds(value);
+ }
+}
+
+void Servo::writeMicroseconds(uint16_t pulseWidth) {
+ if (this->pin == NOT_ATTACHED) {
+ ASSERT(0);
+ return;
+ }
+
+ pulseWidth = constrain(pulseWidth, this->min, this->max);
+ pwmWrite(this->pin, US_TO_COMPARE(pulseWidth));
+}
+
+int Servo::read() const {
+ if (this->pin == NOT_ATTACHED) {
+ ASSERT(0);
+ return 0;
+ }
+
+ unsigned int pw = this->readMicroseconds();
+ int a = US_TO_ANGLE(pw);
+ // map() round-trips in a weird way we correct for here
+ return a == 0 || a == 180 ? a : a + 1;
+}
+
+uint16_t Servo::readMicroseconds() const {
+ if (this->pin == NOT_ATTACHED) {
+ ASSERT(0);
+ return 0;
+ }
+
+ unsigned int compare = this->timer->getCompare(this->channel);
+ uint16_t c = COMPARE_TO_US(compare);
+ // map() round-trips in a weird way we correct for here
+ return c == 0 || c == 180 ? c : c + 1;
+}
diff --git a/libraries/Servo/Servo.h b/libraries/Servo/Servo.h
new file mode 100644
index 0000000..1c75618
--- /dev/null
+++ b/libraries/Servo/Servo.h
@@ -0,0 +1,116 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010, LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *****************************************************************************/
+
+#ifndef _SERVO_H_
+#define _SERVO_H_
+
+#include <stdint.h>
+
+#include "wirish.h" /* hack for IDE compile */
+
+/* Note on Arduino compatibility:
+
+ In the Arduino implementation, PWM is done "by hand" in the sense
+ that timer channels are hijacked in groups and an ISR is set which
+ toggles Servo::attach()ed pins using digitalWrite().
+
+ While this scheme allows any pin to drive a servo, it chews up
+ cycles and complicates the programmer's notion of when a particular
+ timer channel will be in use.
+
+ This implementation only allows Servo instances to Servo::attach()
+ to pins that already have a timer channel associated with them, and
+ just uses pwmWrite() to drive the wave.
+
+ This introduces an incompatibility: while the Arduino
+ implementation of attach() returns the affected channel on success
+ and 0 on failure, this one returns true on success and false on
+ failure.
+
+ RC Servos expect a pulse every 20ms. Since periods are set for
+ entire timers, rather than individual channels, attach()ing a Servo
+ to a pin can interfere with other pins associated with the same
+ timer. As always, the pin mapping mega table is your friend.
+ */
+
+// Pin number of unattached pins
+#define NOT_ATTACHED (-1)
+
+// Maximum angle in degrees you can write(), exclusive. Value chosen
+// for Arduino compatibility.
+#define SERVO_MAX_WRITE_ANGLE (200)
+
+// Default min (0 deg)/max(180 deg) pulse widths, in microseconds.
+// Value chosen for Arduino compatibility.
+#define SERVO_DEFAULT_MIN_PW (544)
+#define SERVO_DEFAULT_MAX_PW (2400)
+
+class Servo {
+public:
+ Servo();
+
+ /* Pin has to have a timer channel associated with it already;
+ * sets pinMode to PWM and returns true iff successful (failure
+ * when pin doesn't support PWM). doesn't detach any ISRs
+ * associated with timer channel. */
+ bool attach(uint8_t pin);
+
+ /* Like attach(int), but with (inclusive) min (0 degree) and max
+ * (180 degree) pulse widths, in microseconds.
+ */
+ bool attach(uint8_t pin, uint16_t min, uint16_t max);
+
+ /* Return pin number if currently attach()ed to a pin,
+ NOT_ATTACHED otherwise. */
+ int attached() const { return pin; }
+
+ /* Stop driving the wave by disabling the output compare
+ interrupt. Returns true if this call did anything. */
+ bool detach();
+
+ /* If value < MAX_WRITE_ANGLE, treated as an angle in degrees.
+ Otherwise, it's treated as a pulse width. */
+ void write(unsigned int value);
+
+ /* If outside of [min, max] determined by attach(), it is clamped
+ to lie in that range. */
+ void writeMicroseconds(uint16_t pulseWidth);
+
+ /* Return servo target angle, in degrees. This will lie between 0
+ and 180. */
+ int read() const;
+
+ /* Returns the current pulse width, in microseconds. This will
+ lie within the [min, max] range. */
+ uint16_t readMicroseconds() const;
+
+private:
+ int8_t pin;
+ HardwareTimer *timer;
+ int channel;
+ uint16_t min;
+ uint16_t max;
+};
+
+#endif /* _SERVO_H_ */
diff --git a/libraries/Servo/rules.mk b/libraries/Servo/rules.mk
new file mode 100644
index 0000000..13cd364
--- /dev/null
+++ b/libraries/Servo/rules.mk
@@ -0,0 +1,35 @@
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Local flags
+CFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES)
+
+# Local rules and targets
+cSRCS_$(d) :=
+
+# examples/UDPApp/udpapp.c \
+# examples/SocketApp/socketapp.c \
+# examples/WebClient/webclient.c \
+# examples/WebServer/webserver.c \
+# examples/Flash/webserver.c \
+
+cppSRCS_$(d) := Servo.cpp
+
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \
+ $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
+
+TGT_BIN += $(OBJS_$(d))
+
+# Standard things
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
+sp := $(basename $(sp)) \ No newline at end of file
diff --git a/libraries/Wire/README b/libraries/Wire/README
new file mode 100644
index 0000000..353d51a
--- /dev/null
+++ b/libraries/Wire/README
@@ -0,0 +1,5 @@
+Wirish soft (bit-banged) implementation of the Wire I2C library.
+
+This implementation is synchronous, and thus supports only a subset of
+the full Wire interface. An asynchronous hardware version implemented
+with DMA is expected for Maple IDE release 0.1.0.
diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp
new file mode 100644
index 0000000..736bd25
--- /dev/null
+++ b/libraries/Wire/Wire.cpp
@@ -0,0 +1,259 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 LeafLabs LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * @brief Wire library, ported from Arduino. Provides a simplistic
+ * interface to i2c.
+ */
+
+#include "Wire.h"
+#include "wirish.h"
+
+/* low level conventions:
+ * - SDA/SCL idle high (expected high)
+ * - always start with i2c_delay rather than end
+ */
+uint32 i2c_delay = 1;
+
+void i2c_start(Port port) {
+ I2C_DELAY;
+ digitalWrite(port.sda,LOW);
+ I2C_DELAY;
+ digitalWrite(port.scl,LOW);
+}
+
+void i2c_stop(Port port) {
+ I2C_DELAY;
+ digitalWrite(port.scl,HIGH);
+ I2C_DELAY;
+ digitalWrite(port.sda,HIGH);
+}
+
+boolean i2c_get_ack(Port port) {
+ I2C_DELAY;
+ digitalWrite(port.scl,LOW);
+ I2C_DELAY;
+ digitalWrite(port.sda,HIGH);
+ I2C_DELAY;
+ digitalWrite(port.scl,HIGH);
+ I2C_DELAY;
+
+ if (!digitalRead(port.sda)) {
+ I2C_DELAY;
+ digitalWrite(port.scl,LOW);
+ return true;
+ } else {
+ I2C_DELAY;
+ digitalWrite(port.scl,LOW);
+ return false;
+ }
+}
+
+void i2c_send_ack(Port port) {
+ I2C_DELAY;
+ digitalWrite(port.sda,LOW);
+ I2C_DELAY;
+ digitalWrite(port.scl,HIGH);
+ I2C_DELAY;
+ digitalWrite(port.scl,LOW);
+}
+
+void i2c_send_nack(Port port) {
+ I2C_DELAY;
+ digitalWrite(port.sda,HIGH);
+ I2C_DELAY;
+ digitalWrite(port.scl,HIGH);
+}
+
+uint8 i2c_shift_in(Port port) {
+ uint8 data = 0;
+
+ int i;
+ for (i=0;i<8;i++) {
+ I2C_DELAY;
+ digitalWrite(port.scl,HIGH);
+ I2C_DELAY;
+ data += digitalRead(port.sda) << (7-i);
+ I2C_DELAY;
+ digitalWrite(port.scl,LOW);
+ }
+
+ return data;
+}
+
+void i2c_shift_out(Port port, uint8 val) {
+ int i;
+ for (i=0;i<8;i++) {
+ I2C_DELAY;
+ digitalWrite(port.sda, !!(val & (1 << (7 - i))));
+ I2C_DELAY;
+ digitalWrite(port.scl, HIGH);
+ I2C_DELAY;
+ digitalWrite(port.scl, LOW);
+ }
+}
+
+TwoWire::TwoWire() {
+ i2c_delay = 0;
+ rx_buf_idx = 0;
+ rx_buf_len = 0;
+ tx_addr = 0;
+ tx_buf_idx = 0;
+ tx_buf_overflow = false;
+}
+
+/*
+ * Sets pins SDA and SCL to OUPTUT_OPEN_DRAIN, joining I2C bus as
+ * master. If you want them to be some other pins, use begin(uint8,
+ * uint8);
+ */
+void TwoWire::begin() {
+ begin(SDA, SCL);
+}
+
+/*
+ * Joins I2C bus as master on given SDA and SCL pins.
+ */
+void TwoWire::begin(uint8 sda, uint8 scl) {
+ port.sda = sda;
+ port.scl = scl;
+ pinMode(scl, OUTPUT_OPEN_DRAIN);
+ pinMode(sda, OUTPUT_OPEN_DRAIN);
+ digitalWrite(scl, HIGH);
+ digitalWrite(sda, HIGH);
+}
+
+void TwoWire::beginTransmission(uint8 slave_address) {
+ tx_addr = slave_address;
+ tx_buf_idx = 0;
+ tx_buf_overflow = false;
+ rx_buf_idx = 0;
+ rx_buf_len = 0;
+}
+
+void TwoWire::beginTransmission(int slave_address) {
+ beginTransmission((uint8)slave_address);
+}
+
+uint8 TwoWire::endTransmission(void) {
+ if (tx_buf_overflow) return EDATA;
+
+ i2c_start(port);
+
+ i2c_shift_out(port, (tx_addr << 1) | I2C_WRITE);
+ if (!i2c_get_ack(port)) return ENACKADDR;
+
+ // shift out the address we're transmitting to
+ for (uint8 i = 0; i < tx_buf_idx; i++) {
+ uint8 ret = writeOneByte(tx_buf[i]);
+ if (ret) return ret; // SUCCESS is 0
+ }
+
+ i2c_stop(port);
+
+ tx_buf_idx = 0;
+ tx_buf_overflow = false;
+ return SUCCESS;
+}
+
+uint8 TwoWire::requestFrom(uint8 address, int num_bytes) {
+ if (num_bytes > WIRE_BUFSIZ) num_bytes = WIRE_BUFSIZ;
+
+ rx_buf_idx = 0;
+ rx_buf_len = 0;
+ while (rx_buf_len < num_bytes) {
+ if(!readOneByte(address, rx_buf + rx_buf_len)) rx_buf_len++;
+ else break;
+ }
+ return rx_buf_len;
+}
+
+uint8 TwoWire::requestFrom(int address, int numBytes) {
+ return TwoWire::requestFrom((uint8)address, (uint8) numBytes);
+}
+
+void TwoWire::send(uint8 value) {
+ if (tx_buf_idx == WIRE_BUFSIZ) {
+ tx_buf_overflow = true;
+ return;
+ }
+
+ tx_buf[tx_buf_idx++] = value;
+}
+
+void TwoWire::send(uint8* buf, int len) {
+ for (uint8 i = 0; i < len; i++) send(buf[i]);
+}
+
+void TwoWire::send(int value) {
+ send((uint8)value);
+}
+
+void TwoWire::send(int* buf, int len) {
+ send((uint8*)buf, (uint8)len);
+}
+
+void TwoWire::send(char* buf) {
+ uint8 *ptr = (uint8*)buf;
+ while(*ptr) {
+ send(*ptr);
+ ptr++;
+ }
+}
+
+uint8 TwoWire::available() {
+ return rx_buf_len - rx_buf_idx;
+}
+
+uint8 TwoWire::receive() {
+ if (rx_buf_idx == rx_buf_len) return 0;
+ return rx_buf[rx_buf_idx++];
+}
+
+// private methods
+
+uint8 TwoWire::writeOneByte(uint8 byte) {
+ i2c_shift_out(port, byte);
+ if (!i2c_get_ack(port)) return ENACKTRNS;
+
+ return SUCCESS;
+}
+
+uint8 TwoWire::readOneByte(uint8 address, uint8 *byte) {
+ i2c_start(port);
+
+ i2c_shift_out(port, (address << 1) | I2C_READ);
+ if (!i2c_get_ack(port)) return ENACKADDR;
+
+ *byte = i2c_shift_in(port);
+
+ i2c_send_nack(port);
+ i2c_stop(port);
+
+ return SUCCESS; // no real way of knowing, but be optimistic!
+}
+
+// Declare the instance that the users of the library can use
+TwoWire Wire;
+
diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h
new file mode 100644
index 0000000..62e37bd
--- /dev/null
+++ b/libraries/Wire/Wire.h
@@ -0,0 +1,99 @@
+/* *****************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 LeafLabs LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * ****************************************************************************/
+
+/**
+ * @brief Wire library, ported from Arduino. Provides a lean
+ * interface to I2C (two-wire) communication.
+ */
+
+#include "wirish.h"
+
+#ifndef _WIRE_H_
+#define _WIRE_H_
+
+typedef struct {
+ uint8 scl;
+ uint8 sda;
+} Port;
+
+/* You must update the online docs if you change this value. */
+#define WIRE_BUFSIZ 32
+
+/* return codes from endTransmission() */
+#define SUCCESS 0 /* transmission was successful */
+#define EDATA 1 /* too much data */
+#define ENACKADDR 2 /* received nack on transmit of address */
+#define ENACKTRNS 3 /* received nack on transmit of data */
+#define EOTHER 4 /* other error */
+
+#define SDA 20
+#define SCL 21
+
+#define I2C_WRITE 0
+#define I2C_READ 1
+
+#define I2C_DELAY do{for(int i=0;i<50;i++) {asm volatile("nop");}}while(0)
+
+class TwoWire {
+ private:
+ uint8 rx_buf[WIRE_BUFSIZ]; /* receive buffer */
+ uint8 rx_buf_idx; /* first unread idx in rx_buf */
+ uint8 rx_buf_len; /* number of bytes read */
+
+ uint8 tx_addr; /* address transmitting to */
+ uint8 tx_buf[WIRE_BUFSIZ]; /* transmit buffer */
+ uint8 tx_buf_idx; /* next idx available in tx_buf, -1 overflow */
+ boolean tx_buf_overflow;
+ Port port;
+ uint8 writeOneByte(uint8);
+ uint8 readOneByte(uint8, uint8*);
+ public:
+ TwoWire();
+ void begin();
+ void begin(uint8, uint8);
+ void beginTransmission(uint8);
+ void beginTransmission(int);
+ uint8 endTransmission(void);
+ uint8 requestFrom(uint8, int);
+ uint8 requestFrom(int, int);
+ void send(uint8);
+ void send(uint8*, int);
+ void send(int);
+ void send(int*, int);
+ void send(char*);
+ uint8 available();
+ uint8 receive();
+};
+
+void i2c_start(Port port);
+void i2c_stop(Port port);
+boolean i2c_get_ack(Port port);
+void i2c_send_ack(Port port);
+void i2c_send_nack(Port port);
+uint8 i2c_shift_in(Port port);
+void i2c_shift_out(Port port, uint8 val);
+
+extern TwoWire Wire;
+
+#endif // _WIRE_H_
diff --git a/libraries/Wire/rules.mk b/libraries/Wire/rules.mk
new file mode 100644
index 0000000..71f5e75
--- /dev/null
+++ b/libraries/Wire/rules.mk
@@ -0,0 +1,29 @@
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Local flags
+CFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES)
+
+# Local rules and targets
+cSRCS_$(d) :=
+
+cppSRCS_$(d) := Wire.cpp
+
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \
+ $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
+
+TGT_BIN += $(OBJS_$(d))
+
+# Standard things
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
+sp := $(basename $(sp)) \ No newline at end of file
diff --git a/main.cpp.example b/main.cpp.example
index 1032733..8fc522a 100644
--- a/main.cpp.example
+++ b/main.cpp.example
@@ -1,15 +1,17 @@
-// Sample main.cpp file. Blinks an LED, sends a message out USART2
-// and turns on PWM on pin 2
+// Sample main.cpp file. Blinks the built-in LED, sends a message out
+// USART2, and turns on PWM on pin 2.
#include "wirish.h"
-#define LED_PIN 13
#define PWM_PIN 2
-void setup()
-{
+void setup() {
/* Set up the LED to blink */
- pinMode(LED_PIN, OUTPUT);
+ pinMode(BOARD_LED_PIN, OUTPUT);
+
+ /* Turn on PWM on pin PWM_PIN */
+ pinMode(PWM_PIN, PWM);
+ pwmWrite(PWM_PIN, 0x8000);
/* Send a message out USART2 */
Serial2.begin(9600);
@@ -17,28 +19,20 @@ void setup()
/* Send a message out the usb virtual serial port */
SerialUSB.println("Hello!");
-
- /* Turn on PWM on pin PWM_PIN */
- pinMode(PWM_PIN, PWM);
- pwmWrite(PWM_PIN, 0x8000);
}
-int toggle = 0;
-
void loop() {
- toggle ^= 1;
- digitalWrite(LED_PIN, toggle);
+ toggleLED();
delay(100);
}
// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated object that need libmaple may fail.
- __attribute__(( constructor )) void premain() {
+__attribute__(( constructor )) void premain() {
init();
}
-int main(void)
-{
+int main(void) {
setup();
while (1) {
diff --git a/notes/coding_standard.txt b/notes/coding_standard.txt
index bab1e38..5cb96c3 100644
--- a/notes/coding_standard.txt
+++ b/notes/coding_standard.txt
@@ -1,21 +1,31 @@
-Source code standards for libmaple.
+libmaple Coding Standards
+=========================
-Do it like this unless there's a really good reason why not. You
-being a lazy bastard doesn't count as a good reason.
+Author: Marti Bolivar (mbolivar@leaflabs.com)
+
+LeafLabs team members are required to follow these when producing new
+code. Community contributors to libmaple are strongly encouraged to
+do so; following these rules will greatly increase the probability
+that your patches will be folded in.
+
+In general, do it like this unless there's a really good reason why
+not. You being lazy doesn't count as a good reason. Most, if not
+all, of these decisions are entirely arbitrary, but it's important for
+readability that we be consistent.
The file .dir-locals.el in the libmaple root directory already ensures
-that many of these standards are followed by default, if you use emacs
-(and not Windows, where it would need to be named _dir_locals.el, and
-no way, man). There's also some elisp scattered about this file which
+that many of these standards are followed by default in Emacs (but not
+on Windows, where it would need to be named _dir_locals.el, and no
+way, man). There's also some elisp scattered about this file which
will provide you additional help.
-Vim customizations to do the same thing would be nice!
+Vim customizations to do the same thing would be nice (hint, hint)!
License
-------
- Put an MIT license at the beginning of the file (look at any of our
- source files for an example). Copyright should go to either your or
+ source files for an example). Copyright should go to either you or
LeafLabs LLC.
Emacs: if you don't like seeing the license, you should use
@@ -31,8 +41,8 @@ License
(dolist (hook mbolivar-programming-mode-hooks)
(add-hook hook (lambda () (elide-head))))
-Whitespace
-----------
+Whitespace/Indentation
+----------------------
- 4 space indents. [Set in .dir-locals.el]
@@ -45,17 +55,28 @@ Whitespace
http://github.com/mbolivar/code-fascism
- I hear tell you can get something similar in vim; ask Perry, I
+ I hear tell you can get something similar in vim; ask around, I
guess.
- Files end in exactly one newline. [The presence of a newline at EOF
is already done by `c-require-final-newline' in recent versions of
- emacs.]
+ Emacs.]
-- Exactly two newlines separate source paragraphs.
+- Exactly two newlines separate source paragraphs (you do separate
+ your code into paragraphs, don't you?).
- The first line in a function is non-blank.
+- Don't indent C code within a conditionally-compiled extern "C"
+ block. Emacs does this by default, which can be very annoying; you
+ can turn this behavior off with
+
+ (defun c-mode-inextern-lang-hook ()
+ (setcdr (assq 'inextern-lang c-offsets-alist) '-))
+
+ (add-hook 'c-mode-hook c-mode-inextern-lang-hook)
+
+
Comments
--------
@@ -72,6 +93,7 @@ Comments
* the comment can end on the same line */
- Doxygen comments are newline comments that begin with /** instead.
+ It is not required that the "/**" appear on a line by itself.
- Single-line comments on the same line are // in c or c++.
@@ -94,9 +116,13 @@ Braces
Naming conventions
------------------
-So there's always a fight about upper and lower case vs. underscores.
-We'll handle this as follows. First, Dammit_Dont_Mix_Like_This,
-because It_Looks_Really_Ugly, ok?
+- There's always a fight about upper and lower case vs. underscores.
+ We'll handle this as follows.
+
+ First, Dammit_Dont_Mix_Like_This, because It_Looks_Really_Ugly, ok?
+ [There's been some debate about this, and some exceptions are
+ already grandfathered in, so in order to settle it, let's call this
+ a "recommendation" instead of "requirement".]
- Variables: Use underscores to separate words in C identifiers:
@@ -109,17 +135,24 @@ because It_Looks_Really_Ugly, ok?
this_is_not, and like I said, Dont_You_DareTryANYTHING_STUPID.
- Functions: C functions are all lowercase, and words are separated by
- underscores. C++ method names are camel cased.
+ underscores. C++ method names are camel cased (thisIsAnExample).
- Structs: pick a style from "Variables" or "Classes" depending on how
you mean it (since it might be either a simple record type, in which
case do like c variables, or you might be faking an object in c, in
- which case do like classes). If it's in a typedef, should also
- probably put _t at the end, but maybe you won't, and I don't really
- feel too strongly about it.
+ which case do like classes). If it's in a typedef, don't feel
+ obliged to put "_t" at the end of the name; we don't.
+
+- Macros and constants: all caps, separated by underscores. Variables
+ with the "const" qualifier aren't considered "constants" for the
+ purposes of this rule; i.e., case them according to the rules for
+ variables.
+
+- foo.h gets #ifdef'ed to _FOO_H_.
- Acronyms: The case of letters in an acronym is determined by the
- case of the first letter in the acronym. Examples:
+ case of the first letter in the acronym, which is determined by
+ following the above rules. Examples:
void usb_func() { ... }
@@ -128,21 +161,43 @@ because It_Looks_Really_Ugly, ok?
void initUSB();
};
- NEVER DO THIS:
+ Never do this:
class BadUsb { ... }; // say "GoodUSB" instead
-- Macros and constants: all caps, separated by underscores.
-
-- foo.h gets ifdef'ed to _FOO_H_.
-
Documentation
-------------
-- Document your code, bitches!
-
-- At least put a doxygen comment with a nonempty @brief for every
- source file you add. See the existing ones for examples.
+- Document your code. This should go without saying.
+
+- For complicated peripherals, it would be nice if you put longer-form
+ comments into this directory (notes/), with a comment in the
+ corresponding .h file referring to it. See libmaple/dac.h for an
+ example. That lets us keep the source files relatively clean while
+ still allowing new readers to have a starting point.
+
+- At least put a doxygen comment with a nonempty @brief for every .h
+ file you add. See the existing ones for examples. For now, it'd be
+ better if you didn't put a @brief into any .c[pp] files, since it
+ (currently) interferes with our documentation generator in a way
+ that I won't explain here (though you can look into the LeafLabs or
+ michaeljones breathe repos on github and potentially figure out
+ why).
+
+- Doxygen comments generally just belong on types, functions,
+ etc. that are part of the public user-facing API. This generally
+ means that if there's ReST documentation for it under docs/source/,
+ it needs Doxygen comments, and that ReST should use Breathe to pull
+ that Doxygen comment out. (For more info on this, see docs/README).
+
+ There are some exceptions to this rule since Breathe isn't totally
+ mature yet and Sphinx's C++ domain is still in flux. In these
+ cases, document the code "manually" in ReST.
+
+ This should be avoided if at all possible, since it creates a
+ maintenance burden of documenting things in two places at once, and
+ provides an opportunity for bad documentation to slip in, when the
+ code comments fall out of sync with the ReST docs.
General Formatting
------------------
@@ -157,8 +212,12 @@ General Formatting
http://www.helsinki.fi/~sjpaavol/programs/lineker.el
- Then put the file somewhere in your load-path, and
+ Then put the file somewhere in your load-path, and:
(require 'lineker)
- (dolist (hook programming-mode-hooks)
+ (dolist (hook '(c-mode-hook c++-mode-hook))
(add-hook hook (lambda () (lineker-mode 1))))
+
+ There are only a few exceptional situations. The most important one
+ is when specifying a lookup table like PIN_MAP where it'd be ugly to
+ split each entry over multiple lines.
diff --git a/notes/native-pin-definitions.txt b/notes/native-pin-definitions.txt
new file mode 100644
index 0000000..b871f89
--- /dev/null
+++ b/notes/native-pin-definitions.txt
@@ -0,0 +1,201 @@
+Maple Native (STM32F103ZE) pin definitions, by GPIO bank.
+
+Source: ST DOC ID 14611, Datasheet for STM32F103xC, STM32F103xD,
+STM32F103xE, Table 5, pp. 30--35.
+
+Some peripherals and extra functionality with less/no libmaple
+relevance (at time of writing) are given in "Other" following each
+bank's main table. Non-default alternate functions are not listed. If
+wirish will/does remap the pin's main function after reset, the main
+function is listed under "Other".
+
+This document was prepared carefully and is believed to be complete
+and correct, but the final arbiter of truth is the ST datasheet.
+
+*** NB: UART 4 and 5 are NOT USART (columns are labeled appropriately).
+
+---------------------------------------------------------------------------
+STM32 ADC Timer FSMC I2S I2C USART SPI DAC 5v?
+---------------------------------------------------------------------------
+PA0 123in0 2ch1etr - - - 2cts - - -
+ 5ch1
+ 8etr
+PA1 123in1 5ch2 - - - 2rts - - -
+ 2ch2
+PA2 123in2 5ch3 - - - 2tx - - -
+ 2ch3
+PA3 123in3 5ch4 - - - 2rx - - -
+ 2ch4
+PA4 12in4 - - - - 2ck 1nss out1 -
+PA5 12in5 - - - - - 1sck out2 -
+PA6 12in6 8bkin - - - - 1miso - -
+ 3ch1
+PA7 12in7 8ch1n - - - - 1mosi - -
+ 3ch2
+PA8 - 1ch1 - - - 1ck - - Y
+PA9 - 1ch2 - - - 1tx - - Y
+PA10 - 1ch3 - - - 1rx - - Y
+PA11 - 1ch4 - - - 1cts - - Y
+PA12 - 1etr - - - 1rts - - Y
+PA13 - - - - - - - - Y
+PA14 - - - - - - - - Y
+PA15 - - - 3ws - - 3nss - Y
+
+Other:
+
+PA0: WKUP
+PA8: MCO
+PA11: USBDM, CAN_RX
+PA12: USBDP, CAN_TX
+PA13: JTMS-SWDIO (default)
+PA14: JTCK-SWCLK (default)
+PA15: JTDI (default)
+
+-------------------------------------------------------------------------------
+STM32 ADC Timer FSMC I2S I2C USART SPI DAC 5v? SDIO
+-------------------------------------------------------------------------------
+PB0 12in8 3ch3 - - - - - - - -
+ 8ch2n
+PB1 12in9 3ch4 - - - - - - - -
+ 8ch3n
+PB2 - - - - - - - - Y -
+PB3 - - - 3ck - - 3sck - Y -
+PB4 - - - - - - 3miso - Y -
+PB5 - - - 3sd 1smba - 3mosi - - -
+PB6 - 4ch1 - - 1scl - - - Y -
+PB7 - 4ch2 NADV - 1sda - - - Y -
+PB8 - 4ch3 - - - - - - Y D4
+PB9 - 4ch4 - - - - - - Y D5
+PB10 - - - - 2scl 3tx - - Y -
+PB11 - - - - 2sda 3rx - - Y -
+PB12 - 1bkin - 2ws 2smba 3ck 2nss - Y -
+PB13 - 1ch1n - 2ck - 3cts 2sck - Y -
+PB14 - 1ch2n - - - 3rts 2miso - Y -
+PB15 - 1ch3n - 2sd - - 2mosi - Y -
+
+Other:
+
+PB2: BOOT1
+PB3: JTDO (default)
+PB4: NJTRST (default)
+
+-------------------------------------------------------------------------------
+STM32 ADC Timer FSMC I2S I2C UART SPI DAC 5v? SDIO
+-------------------------------------------------------------------------------
+PC0 123in10 - - - - - - - - -
+PC1 123in11 - - - - - - - - -
+PC2 123in12 - - - - - - - - -
+PC3 123in13 - - - - - - - - -
+PC4 12in14 - - - - - - - - -
+PC5 12in15 - - - - - - - - -
+PC6 - 8ch1 - 2mck - - - - Y D6
+PC7 - 8ch2 - 3mck - - - - Y D7
+PC8 - 8ch3 - - - - - - Y D0
+PC9 - 8ch4 - - - - - - Y D1
+PC10 - - - - - 4tx - - Y D2
+PC11 - - - - - 4rx - - Y D3
+PC12 - - - - - 5tx - - Y CK
+PC13 - - - - - - - - - -
+PC14 - - - - - - - - - -
+PC15 - - - - - - - - - -
+
+Other:
+
+PC13: TAMPER_RTC
+PC14: OSC32_IN
+PC15: OSC32_OUT
+
+-------------------------------------------------------------------------------
+STM32 ADC Timer FSMC I2S I2C UART SPI DAC 5v? SDIO
+-------------------------------------------------------------------------------
+PD0 - - D2 - - - - - Y -
+PD1 - - D3 - - - - - Y -
+PD2 - 3etr - - - 5rx - - Y CMD
+PD3 - - CLK - - - - - Y -
+PD4 - - NOE - - - - - Y -
+PD5 - - NWE - - - - - Y -
+PD6 - - NWAIT - - - - - Y -
+PD7 - - NE1 - - - - - Y -
+ NCE2
+PD8 - - D13 - - - - - Y -
+PD9 - - D14 - - - - - Y -
+PD10 - - D15 - - - - - Y -
+PD11 - - A16 - - - - - Y -
+PD12 - - A17 - - - - - Y -
+PD13 - - A18 - - - - - Y -
+PD14 - - D0 - - - - - Y -
+PD15 - - D1 - - - - - Y -
+
+Other:
+
+PD0: OSC_IN (default)
+PD1: OSC_OUT (default)
+
+---------------------------------------------------------------------------
+STM32 ADC Timer FSMC I2S I2C USART SPI DAC 5v?
+---------------------------------------------------------------------------
+PE0 - 4etr NBL0 - - - - - Y
+PE1 - - NBL1 - - - - - Y
+PE2 - - A23 - - - - - Y
+PE3 - - A19 - - - - - Y
+PE4 - - A20 - - - - - Y
+PE5 - - A21 - - - - - Y
+PE6 - - A22 - - - - - Y
+PE7 - - D4 - - - - - Y
+PE8 - - D5 - - - - - Y
+PE9 - - D6 - - - - - Y
+PE10 - - D7 - - - - - Y
+PE11 - - D8 - - - - - Y
+PE12 - - D9 - - - - - Y
+PE13 - - D10 - - - - - Y
+PE14 - - D11 - - - - - Y
+PE15 - - D12 - - - - - Y
+
+Other:
+PE2: TRACECK
+PE3: TRACED0
+PE4: TRACED1
+PE5: TRACED2
+PE6: TRACED3
+
+---------------------------------------------------------------------------
+STM32 ADC Timer FSMC I2S I2C USART SPI DAC 5v?
+---------------------------------------------------------------------------
+PF0 - - A0 - - - - - Y
+PF1 - - A1 - - - - - Y
+PF2 - - A2 - - - - - Y
+PF3 - - A3 - - - - - Y
+PF4 - - A4 - - - - - Y
+PF5 - - A5 - - - - - Y
+PF6 3in4 - NIORD - - - - - -
+PF7 3in5 - NREG - - - - - -
+PF8 3in6 - NIOWR - - - - - -
+PF9 3in7 - CD - - - - - -
+PF10 3in8 - INTR - - - - - -
+PF11 - - NIOS16 - - - - - Y
+PF12 - - A6 - - - - - Y
+PF13 - - A7 - - - - - Y
+PF14 - - A8 - - - - - Y
+PF15 - - A9 - - - - - Y
+
+---------------------------------------------------------------------------
+STM32 ADC Timer FSMC I2S I2C USART SPI DAC 5v?
+---------------------------------------------------------------------------
+PG0 - - A10 - - - - - Y
+PG1 - - A11 - - - - - Y
+PG2 - - A12 - - - - - Y
+PG3 - - A13 - - - - - Y
+PG4 - - A14 - - - - - Y
+PG5 - - A15 - - - - - Y
+PG6 - - INT2 - - - - - Y
+PG7 - - INT3 - - - - - Y
+PG8 - - - - - - - - Y
+PG9 - - NE2 - - - - - Y
+ NCE3
+PG10 - - NCE4_1 - - - - - Y
+ NE3
+PG11 - - NCE4_2 - - - - - Y
+PG12 - - NE4 - - - - - Y
+PG13 - - A24 - - - - - Y
+PG14 - - A25 - - - - - Y
+PG15 - - - - - - - - Y
diff --git a/notes/pin-mapping.txt b/notes/pin-mapping.txt
index 67a675c..24402ed 100644
--- a/notes/pin-mapping.txt
+++ b/notes/pin-mapping.txt
@@ -1,3 +1,11 @@
+The pin maps in this document are included for informational purposes
+only. The final arbiters of truth are the PIN_MAP definitions in
+../wirish/boards.h and the STM32 datasheets.
+
+====
+Maple
+====
+
Reserved Pins: Function
PA11 USBDM
PA12 USBDP
@@ -13,8 +21,12 @@ PC12 DISC
PD0 OSC_IN
PD1 OSC_OUT
+Alternate function remaps:
+
+None?
+
-------------------------------------------------------------------------------
-Pin STM32 PIN ADC Timer I2C UART SPI F/T
+Pin STM32 PIN ADC Timer I2C UART SPI 5v?
-------------------------------------------------------------------------------
D0 PA3 ADC3 TIM2_CH4 - USART2_RX - -
D1 PA2 ADC2 TIM2_CH3 - USART2_TX - -
@@ -64,7 +76,88 @@ D37 PC8 - - - - - Y
Note: former pin D38 (PC9) is now attached to the BUT button and there is a
GND connection where D38 was.
-todo:
-adc pin check
-jtag pins for gpio
+TODO:
+- [?] JTAG pins for GPIO
+
+==========
+Maple Mini
+==========
+
+Reserved pins:
+
+Pin Function
+--- --------
+PA11 USBDM
+PA12 USBDP
+PB8 BUT button
+PB9 DISC
+PD0 OSC_IN
+PD1 OSC_OUT
+
+Alternate function remaps:
+
+Pin Default Remap
+--- ------- -----
+PB4 JNTRST GPIO
+PB3 JTDO GPIO
+PA15 JTDI GPIO
+PA14 JTCK GPIO
+PA13 JTMS GPIO
+
+-------------------------------------------------------------------------------
+Pin STM32 PIN ADC Timer I2C USART SPI 5v?
+-------------------------------------------------------------------------------
+D0 PB11 - - I2C2_SDA USART3_RX - Y
+D1 PB10 - - I2C2_SCL USART3_TX - Y
+D2 PB2 - - - - - Y
+D3 PB0 ADC8 TIM3_CH3 - - - -
+D4 PA7 ADC7 TIM3_CH2 - - SPI1_MOSI -
+D5 PA6 ADC6 TIM3_CH1 - - SPI1_MISO -
+D6 PA5 ADC5 - - - SPI1_SCK -
+D7 PA4 ADC4 - - USART2_CK SPI1_NSS -
+D8 PA3 ADC3 TIM2_CH4 - USART2_RX - -
+D9 PA2 ADC2 TIM2_CH3 - USART2_TX - -
+D10 PA1 ADC1 TIM2_CH2 - USART2_RTS - -
+D11 PA0 ADC0 TIM2_CH1_ETR - USART2_CTS - -
+D12 PC15 - - - - - -
+D13 PC14 - - - - - -
+D14 PC13 - - - - - -
+D15 PB7 - TIM4_CH2 I2C1_SDA - - Y
+D16 PB6 - TIM4_CH1 I2C1_SCL - - Y
+D17 PB5 - - I2C1_SMBA - - -
+D18 PB4 - - - - - Y
+D19 PB3 - - - - - Y
+D20 PA15 - - - - - Y
+D21 PA14 - - - - - Y
+D22 PA13 - - - - - Y
+# D23 is USBDP, but supports:
+ PA12 - - - - - Y
+# D24 is USBDM, but supports:
+ PA11 - - - - - Y
+D25 PA10 - TIM1_CH3 - USART1_RX - Y
+D26 PA9 - TIM1_CH2 - USART1_TX - Y
+D27 PA8 - TIM1_CH1 - USART1_CK - Y
+D28 PB15 - TIM1_CH3N - - SPI2_MOSI Y
+D29 PB14 - TIM1_CH2N - USART3_RTS SPI2_MISO Y
+D30 PB13 - TIM1_CH1N - USART3_CTS SPI2_SCK Y
+D31 PB12 - TIM1_BKIN I2C2_SMBAL USART3_CK SPI2_NSS Y
+D32 PB8 0 TIM4_CH3 - - - Y
+D33 PB1 ADC9 TIM3_CH4 - - - -
+
+TODO:
+- [?] JTAG pins for GPIO
+
+============
+Maple Native
+============
+
+Reserved pins:
+
+TODO
+
+Alternate function remaps:
+
+TODO
+The pin map on Maple Native is in flux. However, the bank/port pin
+definitions are available in notes/native-pin-definitions.txt.
diff --git a/support/ld/maple_mini/flash.ld b/support/ld/maple_mini/flash.ld
new file mode 100644
index 0000000..2d40100
--- /dev/null
+++ b/support/ld/maple_mini/flash.ld
@@ -0,0 +1,211 @@
+/* Linker script for STM32 (by Lanchon with Mods by LeafLabs)
+ *
+ * Version:Sourcery G++ 4.2-84
+ * BugURL:https://support.codesourcery.com/GNUToolchain/
+ *
+ * Copyright 2007 CodeSourcery.
+ *
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply. */
+
+/* Linker script for STM32 (by Lanchon),
+ * ROM and RAM relocated to their positions
+ * as placed by Maple bootloader
+ *
+ * Configure target memory and included script
+ * according to your application requirements. */
+
+/* Define memory spaces. */
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
+ rom (rx) : ORIGIN = 0x08005000, LENGTH = 108K
+}
+
+OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
+ENTRY(_start)
+SEARCH_DIR(.)
+/* GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3-lanchon-stm32) */
+GROUP(libgcc.a libc.a libm.a libcs3-lanchon-stm32.a)
+
+/* These force the linker to search for particular symbols from
+ * the start of the link process and thus ensure the user's
+ * overrides are picked up
+ */
+EXTERN(__cs3_reset_lanchon_stm32)
+INCLUDE names.inc
+EXTERN(__cs3_interrupt_vector_lanchon_stm32)
+EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end)
+EXTERN(_start)
+
+PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram);
+PROVIDE(__cs3_heap_start = _end);
+PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram);
+
+SECTIONS
+{
+ .text :
+ {
+ CREATE_OBJECT_SYMBOLS
+ __cs3_region_start_rom = .;
+ *(.cs3.region-head.rom)
+ __cs3_interrupt_vector = __cs3_interrupt_vector_lanchon_stm32;
+ *(.cs3.interrupt_vector)
+ /* Make sure we pulled in an interrupt vector. */
+ ASSERT (. != __cs3_interrupt_vector_lanchon_stm32, "No interrupt vector");
+ *(.rom)
+ *(.rom.b)
+
+ PROVIDE(__cs3_reset_lanchon_stm32 = _start);
+ __cs3_reset = __cs3_reset_lanchon_stm32;
+ *(.cs3.reset)
+
+ *(.text .text.* .gnu.linkonce.t.*)
+ *(.plt)
+ *(.gnu.warning)
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer)
+
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ *(.gcc_except_table)
+ *(.eh_frame_hdr)
+ *(.eh_frame)
+
+ . = ALIGN(4);
+ KEEP(*(.init))
+
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+
+ . = ALIGN(0x4);
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*crtend.o(.ctors))
+
+ . = ALIGN(4);
+ KEEP(*(.fini))
+
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*crtend.o(.dtors))
+
+ . = ALIGN(4);
+ __cs3_regions = .;
+ LONG (0)
+ LONG (__cs3_region_init_ram)
+ LONG (__cs3_region_start_ram)
+ LONG (__cs3_region_init_size_ram)
+ LONG (__cs3_region_zero_size_ram)
+ } >rom
+
+ /* .ARM.exidx is sorted, so has to go in its own output section. */
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } >rom
+ __exidx_end = .;
+ .text.align :
+ {
+ . = ALIGN(8);
+ _etext = .;
+ } >rom
+
+/* expose a custom rom only section */
+ .USER_FLASH :
+ {
+ *(.USER_FLASH)
+ } >rom
+
+
+ /* __cs3_region_end_rom is deprecated */
+ __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(rom);
+ __cs3_region_size_rom = LENGTH(rom);
+ __cs3_region_num = 1;
+
+ .data :
+ {
+ __cs3_region_start_ram = .;
+ *(.cs3.region-head.ram)
+ KEEP(*(.jcr))
+ *(.got.plt) *(.got)
+ *(.shdata)
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.ram)
+ . = ALIGN (8);
+ _edata = .;
+ } >ram AT>rom
+ .bss :
+ {
+ *(.shbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ *(.ram.b)
+ . = ALIGN (8);
+ _end = .;
+ __end = .;
+ } >ram AT>rom
+ /* __cs3_region_end_ram is deprecated */
+ __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram);
+ __cs3_region_size_ram = LENGTH(ram);
+ __cs3_region_init_ram = LOADADDR (.data);
+ __cs3_region_init_size_ram = _edata - ADDR (.data);
+ __cs3_region_zero_size_ram = _end - _edata;
+ __cs3_region_num = 1;
+
+ .stab 0 (NOLOAD) : { *(.stab) }
+ .stabstr 0 (NOLOAD) : { *(.stabstr) }
+ /* DWARF debug sections.
+ * Symbols in the DWARF debugging sections are relative to the beginning
+ * of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+
+ .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
+ .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/support/ld/maple_mini/jtag.ld b/support/ld/maple_mini/jtag.ld
new file mode 100644
index 0000000..435e3f0
--- /dev/null
+++ b/support/ld/maple_mini/jtag.ld
@@ -0,0 +1,186 @@
+/* Linker script for STM32 (by Lanchon),
+ * ROM and RAM relocated to their positions
+ * as placed by Maple bootloader
+ *
+ * Configure target memory and included script
+ * according to your application requirements. */
+
+/* Define memory spaces. */
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+}
+
+OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
+ENTRY(_start)
+SEARCH_DIR(.)
+/* GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3-lanchon-stm32) */
+GROUP(libgcc.a libc.a libm.a libcs3-lanchon-stm32.a)
+
+/* These force the linker to search for particular symbols from
+ * the start of the link process and thus ensure the user's
+ * overrides are picked up
+ */
+EXTERN(__cs3_reset_lanchon_stm32)
+INCLUDE names.inc
+EXTERN(__cs3_interrupt_vector_lanchon_stm32)
+EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end)
+EXTERN(_start)
+
+PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram);
+PROVIDE(__cs3_heap_start = _end);
+PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram);
+
+SECTIONS
+{
+ .text :
+ {
+ CREATE_OBJECT_SYMBOLS
+ __cs3_region_start_rom = .;
+ *(.cs3.region-head.rom)
+ __cs3_interrupt_vector = __cs3_interrupt_vector_lanchon_stm32;
+ *(.cs3.interrupt_vector)
+ /* Make sure we pulled in an interrupt vector. */
+ ASSERT (. != __cs3_interrupt_vector_lanchon_stm32, "No interrupt vector");
+ *(.rom)
+ *(.rom.b)
+
+ PROVIDE(__cs3_reset_lanchon_stm32 = _start);
+ __cs3_reset = __cs3_reset_lanchon_stm32;
+ *(.cs3.reset)
+
+ *(.text .text.* .gnu.linkonce.t.*)
+ *(.plt)
+ *(.gnu.warning)
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer)
+
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ *(.gcc_except_table)
+ *(.eh_frame_hdr)
+ *(.eh_frame)
+
+ . = ALIGN(4);
+ KEEP(*(.init))
+
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+
+ . = ALIGN(0x4);
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*crtend.o(.ctors))
+
+ . = ALIGN(4);
+ KEEP(*(.fini))
+
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*crtend.o(.dtors))
+
+ . = ALIGN(4);
+ __cs3_regions = .;
+ LONG (0)
+ LONG (__cs3_region_init_ram)
+ LONG (__cs3_region_start_ram)
+ LONG (__cs3_region_init_size_ram)
+ LONG (__cs3_region_zero_size_ram)
+ } >rom
+
+ /* .ARM.exidx is sorted, so has to go in its own output section. */
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } >rom
+ __exidx_end = .;
+ .text.align :
+ {
+ . = ALIGN(8);
+ _etext = .;
+ } >rom
+ /* __cs3_region_end_rom is deprecated */
+ __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(rom);
+ __cs3_region_size_rom = LENGTH(rom);
+ __cs3_region_num = 1;
+
+ .data :
+ {
+ __cs3_region_start_ram = .;
+ *(.cs3.region-head.ram)
+ KEEP(*(.jcr))
+ *(.got.plt) *(.got)
+ *(.shdata)
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.ram)
+ . = ALIGN (8);
+ _edata = .;
+ } >ram AT>rom
+ .bss :
+ {
+ *(.shbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ *(.ram.b)
+ . = ALIGN (8);
+ _end = .;
+ __end = .;
+ } >ram AT>rom
+ /* __cs3_region_end_ram is deprecated */
+ __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram);
+ __cs3_region_size_ram = LENGTH(ram);
+ __cs3_region_init_ram = LOADADDR (.data);
+ __cs3_region_init_size_ram = _edata - ADDR (.data);
+ __cs3_region_zero_size_ram = _end - _edata;
+ __cs3_region_num = 1;
+
+ .stab 0 (NOLOAD) : { *(.stab) }
+ .stabstr 0 (NOLOAD) : { *(.stabstr) }
+ /* DWARF debug sections.
+ * Symbols in the DWARF debugging sections are relative to the beginning
+ * of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+
+ .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
+ .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/support/ld/maple_mini/ram.ld b/support/ld/maple_mini/ram.ld
new file mode 100644
index 0000000..1fbecc5
--- /dev/null
+++ b/support/ld/maple_mini/ram.ld
@@ -0,0 +1,220 @@
+/* Linker script for STM32 (by Lanchon with Mods by LeafLabs)
+ *
+ * Version:Sourcery G++ 4.2-84
+ * BugURL:https://support.codesourcery.com/GNUToolchain/
+ *
+ * Copyright 2007 CodeSourcery.
+ *
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply. */
+
+/* Linker script for STM32 (by Lanchon),
+ * ROM and RAM relocated to their positions
+ * as placed by Maple bootloader
+ *
+ * Configure target memory and included script
+ * according to your application requirements. */
+
+/* Define memory spaces. */
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
+ rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
+}
+
+
+OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
+ENTRY(_start)
+SEARCH_DIR(.)
+/* GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3-lanchon-stm32) */
+GROUP(libgcc.a libc.a libm.a libcs3-lanchon-stm32.a)
+
+/* These force the linker to search for particular symbols from
+ * the start of the link process and thus ensure the user's
+ * overrides are picked up
+ */
+EXTERN(__cs3_reset_lanchon_stm32)
+INCLUDE names.inc
+EXTERN(__cs3_interrupt_vector_lanchon_stm32)
+EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end)
+EXTERN(_start)
+
+PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram);
+PROVIDE(__cs3_heap_start = _end);
+PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram);
+
+SECTIONS
+{
+ .text :
+ {
+ CREATE_OBJECT_SYMBOLS
+ __cs3_region_start_ram = .;
+ *(.cs3.region-head.ram)
+ __cs3_interrupt_vector = __cs3_interrupt_vector_lanchon_stm32;
+ *(.cs3.interrupt_vector)
+ /* Make sure we pulled in an interrupt vector. */
+ ASSERT (. != __cs3_interrupt_vector_lanchon_stm32, "No interrupt vector");
+
+ PROVIDE(__cs3_reset_lanchon_stm32 = _start);
+ __cs3_reset = __cs3_reset_lanchon_stm32;
+ *(.cs3.reset)
+
+ *(.text .text.* .gnu.linkonce.t.*)
+ *(.plt)
+ *(.gnu.warning)
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer)
+
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ *(.gcc_except_table)
+ *(.eh_frame_hdr)
+ *(.eh_frame)
+
+ . = ALIGN(4);
+ KEEP(*(.init))
+
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+
+ . = ALIGN(0x4);
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*crtend.o(.ctors))
+
+ . = ALIGN(4);
+ KEEP(*(.fini))
+
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*crtend.o(.dtors))
+
+ . = ALIGN(4);
+ __cs3_regions = .;
+ LONG (0)
+ LONG (__cs3_region_init_ram)
+ LONG (__cs3_region_start_ram)
+ LONG (__cs3_region_init_size_ram)
+ LONG (__cs3_region_zero_size_ram)
+ } >ram
+
+ /* .ARM.exidx is sorted, so has to go in its own output section. */
+ /* even cs3.rom is in ram since its running as user code under the Maple
+ bootloader */
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } >ram
+ __exidx_end = .;
+ .text.align :
+ {
+ . = ALIGN(8);
+ _etext = .;
+ } >ram
+
+ .cs3.rom :
+ {
+ __cs3_region_start_rom = .;
+ *(.cs3.region-head.rom)
+ *(.rom)
+ . = ALIGN (8);
+ } >ram
+
+ .cs3.rom.bss :
+ {
+ *(.rom.b)
+ . = ALIGN (8);
+ } >ram
+ /* __cs3_region_end_rom is deprecated */
+ __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(ram);
+ __cs3_region_size_rom = LENGTH(ram);
+ __cs3_region_init_rom = LOADADDR (.cs3.rom);
+ __cs3_region_init_size_rom = SIZEOF(.cs3.rom);
+ __cs3_region_zero_size_rom = SIZEOF(.cs3.rom.bss);
+
+ .data :
+ {
+
+ KEEP(*(.jcr))
+ *(.got.plt) *(.got)
+ *(.shdata)
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.ram)
+ . = ALIGN (8);
+ _edata = .;
+ } >ram
+ .bss :
+ {
+ *(.shbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ *(.ram.b)
+ . = ALIGN (8);
+ _end = .;
+ __end = .;
+ } >ram
+ /* __cs3_region_end_ram is deprecated */
+ __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram);
+ __cs3_region_size_ram = LENGTH(ram);
+ __cs3_region_init_ram = LOADADDR (.text);
+ __cs3_region_init_size_ram = _edata - ADDR (.text);
+ __cs3_region_zero_size_ram = _end - _edata;
+ __cs3_region_num = 1;
+
+ .stab 0 (NOLOAD) : { *(.stab) }
+ .stabstr 0 (NOLOAD) : { *(.stabstr) }
+ /* DWARF debug sections.
+ * Symbols in the DWARF debugging sections are relative to the beginning
+ * of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+
+ .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
+ .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
+
diff --git a/support/ld/maple_native/flash.ld b/support/ld/maple_native/flash.ld
index 7e1e453..4e820d2 100644
--- a/support/ld/maple_native/flash.ld
+++ b/support/ld/maple_native/flash.ld
@@ -26,7 +26,7 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K
- rom (rx) : ORIGIN = 0x08005000, LENGTH = 500K
+ rom (rx) : ORIGIN = 0x08005000, LENGTH = 492K
}
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
diff --git a/support/ld/maple_native/jtag.ld b/support/ld/maple_native/jtag.ld
index 85aae53..90a0a3f 100644
--- a/support/ld/maple_native/jtag.ld
+++ b/support/ld/maple_native/jtag.ld
@@ -8,8 +8,8 @@
/* Define memory spaces. */
MEMORY
{
- ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K
- rom (rx) : ORIGIN = 0x08005000, LENGTH = 500K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
}
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
diff --git a/support/openocd/flash_0.4.0.cfg b/support/openocd/flash_0.4.0.cfg
new file mode 100644
index 0000000..e66d28d
--- /dev/null
+++ b/support/openocd/flash_0.4.0.cfg
@@ -0,0 +1,89 @@
+# script for stm32
+
+interface ft2232
+ft2232_device_desc "Olimex OpenOCD JTAG"
+ft2232_layout olimex-jtag
+ft2232_vid_pid 0x15ba 0x0003
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME stm32
+}
+
+if { [info exists ENDIAN] } {
+ set _ENDIAN $ENDIAN
+} else {
+ set _ENDIAN little
+}
+
+# jtag speed speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so ufse F_JTAG = 1MHz
+jtag_khz 1000
+
+jtag_nsrst_delay 100
+jtag_ntrst_delay 100
+
+#use combined on interfaces or targets that can't set TRST/SRST separately
+reset_config trst_and_srst
+
+#jtag scan chain
+if { [info exists CPUTAPID ] } {
+ set _CPUTAPID $CPUTAPID
+} else {
+ # See STM Document RM0008
+ # Section 30.6.3
+ set _CPUTAPID 0x3ba00477
+}
+
+jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
+
+if { [info exists BSTAPID ] } {
+ # FIXME this never gets used to override defaults...
+ set _BSTAPID $BSTAPID
+} else {
+ # See STM Document RM0008
+ # Section 29.6.2
+ # Low density devices, Rev A
+ set _BSTAPID1 0x06412041
+ # Medium density devices, Rev A
+ set _BSTAPID2 0x06410041
+ # Medium density devices, Rev B and Rev Z
+ set _BSTAPID3 0x16410041
+ # High density devices, Rev A
+ set _BSTAPID4 0x06414041
+ # Connectivity line devices, Rev A and Rev Z
+ set _BSTAPID5 0x06418041
+}
+jtag newtap $_CHIPNAME bs -irlen 5 -expected-id $_BSTAPID1 \
+ -expected-id $_BSTAPID2 -expected-id $_BSTAPID3 \
+ -expected-id $_BSTAPID4 -expected-id $_BSTAPID5
+
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m3 -endian $_ENDIAN -chain-position $_TARGETNAME
+
+$_TARGETNAME configure -work-area-virt 0 -work-area-phys 0x20000000 -work-area-size 0x5000 -work-area-backup 0
+# TODO: native
+#$_TARGETNAME configure -work-area-virt 0 -work-area-phys 0x20000000 -work-area-size 0x10000 -work-area-backup 0
+
+flash bank bank0 stm32x 0x08000000 0x00020000 0 0 $_TARGETNAME
+
+proc flash_chip {} {
+ echo "Halting..."
+ halt
+ echo "Erasing..."
+ flash erase_address 0x08000000 0x20000
+ # TODO: native
+ #flash erase_address 0x08000000 0x80000
+ echo "Flashing image..."
+ flash write_bank 0 build/maple.bin 0
+ echo "Verifying image..."
+ verify_image build/maple.bin 0x08000000 bin
+ echo "Checksum verified, resetting chip"
+ reset run
+ echo "Daemon shutdown"
+ shutdown
+}
+
+init
+flash_chip
diff --git a/support/openocd/run_0.4.0.cfg b/support/openocd/run_0.4.0.cfg
new file mode 100644
index 0000000..bbc8864
--- /dev/null
+++ b/support/openocd/run_0.4.0.cfg
@@ -0,0 +1,75 @@
+# script for stm32
+
+interface ft2232
+ft2232_device_desc "Olimex OpenOCD JTAG"
+ft2232_layout olimex-jtag
+ft2232_vid_pid 0x15ba 0x0003
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME stm32
+}
+
+if { [info exists ENDIAN] } {
+ set _ENDIAN $ENDIAN
+} else {
+ set _ENDIAN little
+}
+
+# jtag speed speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so ufse F_JTAG = 1MHz
+jtag_khz 1000
+
+jtag_nsrst_delay 100
+jtag_ntrst_delay 100
+
+#use combined on interfaces or targets that can't set TRST/SRST separately
+reset_config trst_and_srst
+
+#jtag scan chain
+if { [info exists CPUTAPID ] } {
+ set _CPUTAPID $CPUTAPID
+} else {
+ # See STM Document RM0008
+ # Section 30.6.3
+ set _CPUTAPID 0x3ba00477
+}
+
+jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
+
+if { [info exists BSTAPID ] } {
+ # FIXME this never gets used to override defaults...
+ set _BSTAPID $BSTAPID
+} else {
+ # See STM Document RM0008
+ # Section 29.6.2
+ # Low density devices, Rev A
+ set _BSTAPID1 0x06412041
+ # Medium density devices, Rev A
+ set _BSTAPID2 0x06410041
+ # Medium density devices, Rev B and Rev Z
+ set _BSTAPID3 0x16410041
+ # High density devices, Rev A
+ set _BSTAPID4 0x06414041
+ # Connectivity line devices, Rev A and Rev Z
+ set _BSTAPID5 0x06418041
+}
+jtag newtap $_CHIPNAME bs -irlen 5 -expected-id $_BSTAPID1 \
+ -expected-id $_BSTAPID2 -expected-id $_BSTAPID3 \
+ -expected-id $_BSTAPID4 -expected-id $_BSTAPID5
+
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m3 -endian $_ENDIAN -chain-position $_TARGETNAME
+
+$_TARGETNAME configure -work-area-virt 0 -work-area-phys 0x20000000 -work-area-size 0x5000 -work-area-backup 0
+
+flash bank bank0 stm32x 0x08000000 0x00020000 0 0 $_TARGETNAME
+
+proc nopforever {} {
+ puts "Resetting the chip..."
+ reset run
+}
+
+init
+nopforever
diff --git a/support/scripts/copy-to-ide b/support/scripts/copy-to-ide
index 5bf52a4..301126d 100755
--- a/support/scripts/copy-to-ide
+++ b/support/scripts/copy-to-ide
@@ -1,16 +1,18 @@
#!/bin/sh
-# This hackish script copies the necessary library files into the Maple IDE
+# This hack copies the necessary library files into the Maple IDE
# repository.
-# Change this
-DEST=`pwd`/../maple-ide/hardware/leaflabs/cores/maple/
+DEST=$1
-ARCH=`uname -a`
+DEST_REF=$DEST/build/shared/reference
+DEST_CORES=$DEST/hardware/leaflabs/cores/maple
+DEST_LIBS=$DEST/libraries
-FILES="LICENSE
+LMAPLE_SRC="LICENSE
./libmaple/*.h
./libmaple/*.c
+ ./libmaple/*.S
./libmaple/usb/*.h
./libmaple/usb/*.c
./libmaple/usb/usb_lib/*.h
@@ -21,11 +23,13 @@ FILES="LICENSE
./wirish/*.cpp
./wirish/comm/*.cpp
./wirish/comm/*.h
- ./support/ld/maple/
- ./support/ld/maple_native/
+ ./support/ld/maple
+ ./support/ld/maple_native
./support/ld/libcs3-lanchon-stm32.a
./support/ld/names.inc"
+LMAPLE_DOCS=./docs
+LMAPLE_DOCS_BUILD=$LMAPLE_DOCS/build/html
echo "First make sure DEST exists: $DEST"
if !(test -d $DEST)
@@ -34,9 +38,23 @@ then
exit -1
fi
-echo "Then delete the old files..."
-rm -r $DEST/*.c $DEST/*.cpp $DEST/*.h $DEST/*.cxx $DEST/*.ld $DEST/*.inc $DEST/*.a $DEST/maple/ $DEST/maple_native/
+# source
+echo Copying libmaple source
+rm -rf $DEST_CORES/*.c $DEST_CORES/*.cpp $DEST_CORES/*.h $DEST_CORES/*.cxx $DEST_CORES/*.inc $DEST_CORES/*.a $DEST_CORES/*.S $DEST_CORES/maple $DEST_CORES/maple_native
+cp -R $LMAPLE_SRC $DEST_CORES
-echo "Finally copy the new source files!"
-cp -r $FILES $DEST
-echo "Done."
+echo Copying over libraries
+cp -R libraries/* $DEST_LIBS
+
+# docs
+echo Deleting old reference directory contents
+rm -rf $DEST_REF/*
+
+echo Rebuilding documentation
+( cd $LMAPLE_DOCS; doxygen && make clean 2>/dev/null 1>/dev/null && make html )
+
+echo Copying over documentation
+cp -R $LMAPLE_DOCS_BUILD/* $DEST_REF
+
+
+echo Done.
diff --git a/support/stm32loader.py b/support/stm32loader.py
index 02ca4e8..874d278 100755
--- a/support/stm32loader.py
+++ b/support/stm32loader.py
@@ -74,13 +74,12 @@ class CommandInterface:
if ask == 0x79:
# ACK
return 1
- else:
- if ask == 0x1F:
- # NACK
- raise CmdException("Chip replied with a NACK during %s" % info)
- else:
- # Unknown responce
- raise CmdException("Unrecognised response %x to %s" % (ask, info))
+ elif ask == 0x1F:
+ # NACK
+ raise CmdException("Chip replied with a NACK during %s" % info)
+
+ # Unknown response
+ raise CmdException("Unrecognised response 0x%x to %s" % (ask, info))
def reset(self):
self.sp.setDTR(0)
@@ -93,7 +92,7 @@ class CommandInterface:
self.sp.setRTS(0)
self.reset()
- # Be a bit more persistant when trying to initialise the chip
+ # Be a bit more persistent when trying to initialise the chip
stop = time.time() + 5.0
while time.time() <= stop:
@@ -276,7 +275,7 @@ class CommandInterface:
if usepbar:
widgets = ['Reading: ', Percentage(),', ', ETA(), ' ', Bar()]
pbar = ProgressBar(widgets=widgets,maxval=lng, term_width=79).start()
-
+
while lng > 256:
if usepbar:
pbar.update(pbar.maxval-lng)
@@ -298,7 +297,7 @@ class CommandInterface:
if usepbar:
widgets = ['Writing: ', Percentage(),' ', ETA(), ' ', Bar()]
pbar = ProgressBar(widgets=widgets, maxval=lng, term_width=79).start()
-
+
offs = 0
while lng > 256:
if usepbar:
@@ -319,7 +318,7 @@ class CommandInterface:
- def __init__(self) :
+ def __init__(self) :
pass
@@ -371,7 +370,7 @@ def read(filename):
return [ord(x) for x in bytes]
if __name__ == "__main__":
-
+
# Import Psyco if available
try:
import psyco
@@ -449,7 +448,8 @@ if __name__ == "__main__":
cmd = CommandInterface()
cmd.open(conf['port'], conf['baud'])
- mdebug(10, "Open port %(port)s, baud %(baud)d" % {'port':conf['port'], 'baud':conf['baud']})
+ mdebug(10, "Open port %(port)s, baud %(baud)d" % {'port':conf['port'],
+ 'baud':conf['baud']})
try:
if (conf['write'] or conf['verify']):
data = read(args[0])
@@ -461,7 +461,7 @@ if __name__ == "__main__":
bootversion = cmd.cmdGet()
- mdebug(0, "Bootloader version %X" % bootversion)
+ mdebug(0, "Bootloader version 0x%X" % bootversion)
if bootversion < 20 or bootversion >= 100:
raise Exception('Unreasonable bootloader version %d' % bootversion)
diff --git a/wirish/HardwareTimer.cpp b/wirish/HardwareTimer.cpp
index 6fbad8b..354663e 100644
--- a/wirish/HardwareTimer.cpp
+++ b/wirish/HardwareTimer.cpp
@@ -22,22 +22,17 @@
* THE SOFTWARE.
*****************************************************************************/
-/**
- * @brief wirish timer class to manage the four 16-bit timer peripherals
- *
- * This implementation is not very efficient (lots of duplicated functions)
+/*
+ * wirish timer class to manage the four 16-bit timer peripherals
*/
#include "wirish.h"
#include "HardwareTimer.h"
-HardwareTimer::HardwareTimer(uint8 timerNum) {
- ASSERT(timerNum <= NR_TIMERS && timerNum != 6 && timerNum != 7);
+HardwareTimer::HardwareTimer(timer_dev_num timerNum) {
+ ASSERT(timerNum != TIMER_INVALID);
this->timerNum = timerNum;
-
- // Need to remember over flow for bounds checking
- this->overflow = 0xFFFF;
}
void HardwareTimer::resume(void) {
@@ -48,126 +43,158 @@ void HardwareTimer::pause(void) {
timer_pause(this->timerNum);
}
+uint16 HardwareTimer::getPrescaleFactor(void) {
+ return timer_get_prescaler(this->timerNum) + 1;
+}
+
void HardwareTimer::setPrescaleFactor(uint16 factor) {
// The prescaler register is zero-indexed
timer_set_prescaler(this->timerNum, factor-1);
}
-void HardwareTimer::setOverflow(uint16 val) {
- this->overflow = val;
- timer_set_reload(this->timerNum, val);
+uint16 HardwareTimer::getOverflow() {
+ return timer_get_reload(this->timerNum);
}
-void HardwareTimer::setCount(uint16 val) {
- if(val > this->overflow) {
- val = this->overflow;
- }
- timer_set_count(this->timerNum, val);
+void HardwareTimer::setOverflow(uint16 val) {
+ timer_set_reload(this->timerNum, val);
}
uint16 HardwareTimer::getCount(void) {
return timer_get_count(this->timerNum);
}
-/* This function will set the prescaler and overflow to get a period
- * of the given length with the most resolution; the return value is
- * the overflow value and thus the largest value that can be set as a
- * compare. */
-uint16 HardwareTimer::setPeriod(uint32 microseconds) {
- // XXX: 72MHz shouldn't be hard coded in here... global define?
+void HardwareTimer::setCount(uint16 val) {
+ uint16 ovf = this->getOverflow();
+ timer_set_count(this->timerNum, min(val, ovf));
+}
+uint16 HardwareTimer::setPeriod(uint32 microseconds) {
// Not the best way to handle this edge case?
if(!microseconds) {
setPrescaleFactor(1);
setOverflow(1);
- return this->overflow;
+ return this->getOverflow();
}
+ uint32 cycles = microseconds * CYCLES_PER_MICROSECOND;
- // With a prescale factor of 1, there are 72counts/ms
- uint16 ps = ((microseconds*72)/65536) + 1;
+ // 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(((microseconds*72)/ps) - 1);
- return this->overflow;
+ setOverflow((cycles/ps) - 1);
+
+ return this->getOverflow();
+}
+
+inline void HardwareTimer::setChannelMode(int channel, TimerMode mode) {
+ timer_set_mode(this->timerNum, channel, mode);
+}
+
+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::setChannel1Mode(uint8 mode) {
- timer_set_mode(this->timerNum,1,mode);
+inline uint16 HardwareTimer::getCompare(int channel) {
+ return timer_get_compare_value(this->timerNum, channel);
}
-void HardwareTimer::setChannel2Mode(uint8 mode) {
- timer_set_mode(this->timerNum,2,mode);
+uint16 HardwareTimer::getCompare1() {
+ return this->getCompare(1);
}
-void HardwareTimer::setChannel3Mode(uint8 mode) {
- timer_set_mode(this->timerNum,3,mode);
+uint16 HardwareTimer::getCompare2() {
+ return this->getCompare(2);
}
-void HardwareTimer::setChannel4Mode(uint8 mode) {
- timer_set_mode(this->timerNum,4,mode);
+uint16 HardwareTimer::getCompare3() {
+ return this->getCompare(3);
+}
+
+uint16 HardwareTimer::getCompare4() {
+ return this->getCompare(4);
+}
+
+inline 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) {
- if(val > this->overflow) {
- val = this->overflow;
- }
- timer_set_compare_value(this->timerNum,1,val);
+ this->setCompare(1, val);
}
void HardwareTimer::setCompare2(uint16 val) {
- if(val > this->overflow) {
- val = this->overflow;
- }
- timer_set_compare_value(this->timerNum,2,val);
+ this->setCompare(2, val);
}
void HardwareTimer::setCompare3(uint16 val) {
- if(val > this->overflow) {
- val = this->overflow;
- }
- timer_set_compare_value(this->timerNum,3,val);
+ this->setCompare(3, val);
}
void HardwareTimer::setCompare4(uint16 val) {
- if(val > this->overflow) {
- val = this->overflow;
- }
- timer_set_compare_value(this->timerNum,4,val);
+ this->setCompare(4, val);
+}
+
+inline void HardwareTimer::attachInterrupt(int channel, voidFuncPtr handler) {
+ timer_attach_interrupt(this->timerNum, channel, handler);
}
void HardwareTimer::attachCompare1Interrupt(voidFuncPtr handler) {
- timer_attach_interrupt(this->timerNum,1,handler);
+ this->attachInterrupt(1, handler);
}
void HardwareTimer::attachCompare2Interrupt(voidFuncPtr handler) {
- timer_attach_interrupt(this->timerNum,2,handler);
+ this->attachInterrupt(2, handler);
}
void HardwareTimer::attachCompare3Interrupt(voidFuncPtr handler) {
- timer_attach_interrupt(this->timerNum,3,handler);
+ this->attachInterrupt(3, handler);
}
void HardwareTimer::attachCompare4Interrupt(voidFuncPtr handler) {
- timer_attach_interrupt(this->timerNum,4,handler);
+ this->attachInterrupt(4, handler);
+}
+
+inline void HardwareTimer::detachInterrupt(int channel) {
+ timer_detach_interrupt(this->timerNum, channel);
}
void HardwareTimer::detachCompare1Interrupt(void) {
- timer_detach_interrupt(this->timerNum,1);
+ this->detachInterrupt(1);
}
void HardwareTimer::detachCompare2Interrupt(void) {
- timer_detach_interrupt(this->timerNum,2);
+ this->detachInterrupt(2);
}
void HardwareTimer::detachCompare3Interrupt(void) {
- timer_detach_interrupt(this->timerNum,3);
+ this->detachInterrupt(3);
}
void HardwareTimer::detachCompare4Interrupt(void) {
- timer_detach_interrupt(this->timerNum,4);
+ this->detachInterrupt(4);
+}
+
+void HardwareTimer::generateUpdate(void) {
+ timer_generate_update(this->timerNum);
}
+
HardwareTimer Timer1(TIMER1);
HardwareTimer Timer2(TIMER2);
HardwareTimer Timer3(TIMER3);
@@ -177,3 +204,23 @@ HardwareTimer Timer5(TIMER5); // High-density devices only
HardwareTimer Timer8(TIMER8); // High-density devices only
#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;
+#if NR_TIMERS >= 8
+ case TIMER5:
+ return &Timer5;
+ case TIMER8:
+ return &Timer8;
+#endif
+ default:
+ return 0;
+ }
+}
diff --git a/wirish/HardwareTimer.h b/wirish/HardwareTimer.h
index c6e11c8..4034b1f 100644
--- a/wirish/HardwareTimer.h
+++ b/wirish/HardwareTimer.h
@@ -26,52 +26,388 @@
* @brief wirish timer class to manage the four 16-bit timer peripherals
*/
-#ifndef _TIMER_H_
-#define _TIMER_H_
+#ifndef _HARDWARETIMER_H_
+#define _HARDWARETIMER_H_
+#include "timers.h"
+
+/**
+ * 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.
+ */
class HardwareTimer {
private:
- uint16 overflow;
- uint8 timerNum;
+ timer_dev_num timerNum;
public:
- HardwareTimer(uint8 timer_num);
+ HardwareTimer(timer_dev_num timer_num);
+
+ /**
+ * Return this timer's device number. For example,
+ * Timer1.getTimerNum() == TIMER1
+ */
+ timer_dev_num getTimerNum() { return 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.
+ *
+ * @see HardwareTimer::resume()
+ */
void pause(void);
+
+ /**
+ * Resume a paused timer, without affecting its configuration.
+ *
+ * The timer will resume counting and firing interrupts as
+ * appropriate.
+ *
+ * Note that there is some function call overhead associated with
+ * using this method, so using it in concert with
+ * HardwareTimer::pause() is not a robust way to align multiple
+ * timers to the same count value.
+ *
+ * @see HardwareTimer::pause()
+ */
void resume(void);
+
+ /**
+ * Returns the timer's prescale factor.
+ * @see HardwareTimer::setPrescaleFactor()
+ */
+ uint16 getPrescaleFactor();
+
+ /**
+ * Set the timer's prescale factor.
+ *
+ * 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
+ * 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()
+ */
void setPrescaleFactor(uint16 factor);
- void setOverflow(uint16 val); // truncates to overflow
- void setCount(uint16 val); // truncates to overflow
+
+ /**
+ * Gets the timer overflow value.
+ * @see HardwareTimer::setOverflow()
+ */
+ uint16 getOverflow();
+
+ /**
+ * Sets 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.
+ *
+ * @param val The new overflow value to set
+ */
+ void setOverflow(uint16 val);
+
+ /**
+ * Retrieve the current timer count.
+ *
+ * @return The timer's current count value
+ */
uint16 getCount(void);
- // tries to set prescaler and overflow wisely; returns overflow
+ /**
+ * 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.
+ *
+ * @param val The new count value to set. If this value exceeds
+ * the timer's overflow value, it is truncated to the
+ * overflow value.
+ */
+ void setCount(uint16 val);
+
+ /**
+ * Configure 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).
+ */
uint16 setPeriod(uint32 microseconds);
- void setChannel1Mode(uint8 mode);
- void setChannel2Mode(uint8 mode);
- void setChannel3Mode(uint8 mode);
- void setChannel4Mode(uint8 mode);
- void setCompare1(uint16 val); // truncates to overflow
- void setCompare2(uint16 val); // truncates to overflow
- void setCompare3(uint16 val); // truncates to overflow
- void setCompare4(uint16 val); // truncates to overflow
+
+ /**
+ * Set the given channel of this timer to the given 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);
+
+ /**
+ * Gets 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.
+ *
+ * @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 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
+ *
+ * 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.
+ *
+ * @param channel the channel to attach the ISR to, from 1 to 4.
+ * @param handler The ISR to attach to the given channel.
+ * @see voidFuncPtr
+ */
+ 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.
+ *
+ * @param channel the channel whose interrupt to detach, from 1 to 4.
+ * @see HardwareTimer::attachInterrupt()
+ */
+ void detachInterrupt(int channel);
+
+ /**
+ * Equivalent to detachInterrupt(1).
+ * @see HardwareTimer::detachInterrupt()
+ */
void detachCompare1Interrupt(void);
+
+ /**
+ * Equivalent to detachInterrupt(2).
+ * @see HardwareTimer::detachInterrupt()
+ */
void detachCompare2Interrupt(void);
+
+ /**
+ * Equivalent to detachInterrupt(3).
+ * @see HardwareTimer::detachInterrupt()
+ */
void detachCompare3Interrupt(void);
+
+ /**
+ * Equivalent to detachInterrupt(4).
+ * @see HardwareTimer::detachInterrupt()
+ */
void detachCompare4Interrupt(void);
+
+ /**
+ * 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);
};
+/** Pre-instantiated timer for use by user code. */
extern HardwareTimer Timer1;
+/** Pre-instantiated timer for use by user code. */
extern HardwareTimer Timer2;
+/** Pre-instantiated timer for use by user code. */
extern HardwareTimer Timer3;
+/** Pre-instantiated timer for use by user code. */
extern HardwareTimer Timer4;
#if NR_TIMERS >= 8
+/** 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.
+ *
+ * @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.
+ *
+ * @see timer_dev_num
+ */
+HardwareTimer* getTimer(timer_dev_num timerNum);
+
#endif
diff --git a/wirish/bit_constants.h b/wirish/bit_constants.h
new file mode 100644
index 0000000..8accc6b
--- /dev/null
+++ b/wirish/bit_constants.h
@@ -0,0 +1,579 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * @brief BIT[n] and binary literal defines, for Arduino
+ * compatibility.
+ */
+
+#ifndef _BIT_CONSTANTS_H_
+#define _BIT_CONSTANTS_H_
+
+#define BIT0 (1 << 0)
+#define BIT1 (1 << 1)
+#define BIT2 (1 << 2)
+#define BIT3 (1 << 3)
+#define BIT4 (1 << 4)
+#define BIT5 (1 << 5)
+#define BIT6 (1 << 6)
+#define BIT7 (1 << 7)
+#define BIT8 (1 << 8)
+#define BIT9 (1 << 9)
+#define BIT10 (1 << 10)
+#define BIT11 (1 << 11)
+#define BIT12 (1 << 12)
+#define BIT13 (1 << 13)
+#define BIT14 (1 << 14)
+#define BIT15 (1 << 15)
+#define BIT16 (1 << 16)
+#define BIT17 (1 << 17)
+#define BIT18 (1 << 18)
+#define BIT19 (1 << 19)
+#define BIT20 (1 << 20)
+#define BIT21 (1 << 21)
+#define BIT22 (1 << 22)
+#define BIT23 (1 << 23)
+#define BIT24 (1 << 24)
+#define BIT25 (1 << 25)
+#define BIT26 (1 << 26)
+#define BIT27 (1 << 27)
+#define BIT28 (1 << 28)
+#define BIT29 (1 << 29)
+#define BIT30 (1 << 30)
+#define BIT31 (1 << 31)
+
+#define B0 0
+#define B00 0
+#define B000 0
+#define B0000 0
+#define B00000 0
+#define B000000 0
+#define B0000000 0
+#define B00000000 0
+#define B1 1
+#define B01 1
+#define B001 1
+#define B0001 1
+#define B00001 1
+#define B000001 1
+#define B0000001 1
+#define B00000001 1
+#define B10 2
+#define B010 2
+#define B0010 2
+#define B00010 2
+#define B000010 2
+#define B0000010 2
+#define B00000010 2
+#define B11 3
+#define B011 3
+#define B0011 3
+#define B00011 3
+#define B000011 3
+#define B0000011 3
+#define B00000011 3
+#define B100 4
+#define B0100 4
+#define B00100 4
+#define B000100 4
+#define B0000100 4
+#define B00000100 4
+#define B101 5
+#define B0101 5
+#define B00101 5
+#define B000101 5
+#define B0000101 5
+#define B00000101 5
+#define B110 6
+#define B0110 6
+#define B00110 6
+#define B000110 6
+#define B0000110 6
+#define B00000110 6
+#define B111 7
+#define B0111 7
+#define B00111 7
+#define B000111 7
+#define B0000111 7
+#define B00000111 7
+#define B1000 8
+#define B01000 8
+#define B001000 8
+#define B0001000 8
+#define B00001000 8
+#define B1001 9
+#define B01001 9
+#define B001001 9
+#define B0001001 9
+#define B00001001 9
+#define B1010 10
+#define B01010 10
+#define B001010 10
+#define B0001010 10
+#define B00001010 10
+#define B1011 11
+#define B01011 11
+#define B001011 11
+#define B0001011 11
+#define B00001011 11
+#define B1100 12
+#define B01100 12
+#define B001100 12
+#define B0001100 12
+#define B00001100 12
+#define B1101 13
+#define B01101 13
+#define B001101 13
+#define B0001101 13
+#define B00001101 13
+#define B1110 14
+#define B01110 14
+#define B001110 14
+#define B0001110 14
+#define B00001110 14
+#define B1111 15
+#define B01111 15
+#define B001111 15
+#define B0001111 15
+#define B00001111 15
+#define B10000 16
+#define B010000 16
+#define B0010000 16
+#define B00010000 16
+#define B10001 17
+#define B010001 17
+#define B0010001 17
+#define B00010001 17
+#define B10010 18
+#define B010010 18
+#define B0010010 18
+#define B00010010 18
+#define B10011 19
+#define B010011 19
+#define B0010011 19
+#define B00010011 19
+#define B10100 20
+#define B010100 20
+#define B0010100 20
+#define B00010100 20
+#define B10101 21
+#define B010101 21
+#define B0010101 21
+#define B00010101 21
+#define B10110 22
+#define B010110 22
+#define B0010110 22
+#define B00010110 22
+#define B10111 23
+#define B010111 23
+#define B0010111 23
+#define B00010111 23
+#define B11000 24
+#define B011000 24
+#define B0011000 24
+#define B00011000 24
+#define B11001 25
+#define B011001 25
+#define B0011001 25
+#define B00011001 25
+#define B11010 26
+#define B011010 26
+#define B0011010 26
+#define B00011010 26
+#define B11011 27
+#define B011011 27
+#define B0011011 27
+#define B00011011 27
+#define B11100 28
+#define B011100 28
+#define B0011100 28
+#define B00011100 28
+#define B11101 29
+#define B011101 29
+#define B0011101 29
+#define B00011101 29
+#define B11110 30
+#define B011110 30
+#define B0011110 30
+#define B00011110 30
+#define B11111 31
+#define B011111 31
+#define B0011111 31
+#define B00011111 31
+#define B100000 32
+#define B0100000 32
+#define B00100000 32
+#define B100001 33
+#define B0100001 33
+#define B00100001 33
+#define B100010 34
+#define B0100010 34
+#define B00100010 34
+#define B100011 35
+#define B0100011 35
+#define B00100011 35
+#define B100100 36
+#define B0100100 36
+#define B00100100 36
+#define B100101 37
+#define B0100101 37
+#define B00100101 37
+#define B100110 38
+#define B0100110 38
+#define B00100110 38
+#define B100111 39
+#define B0100111 39
+#define B00100111 39
+#define B101000 40
+#define B0101000 40
+#define B00101000 40
+#define B101001 41
+#define B0101001 41
+#define B00101001 41
+#define B101010 42
+#define B0101010 42
+#define B00101010 42
+#define B101011 43
+#define B0101011 43
+#define B00101011 43
+#define B101100 44
+#define B0101100 44
+#define B00101100 44
+#define B101101 45
+#define B0101101 45
+#define B00101101 45
+#define B101110 46
+#define B0101110 46
+#define B00101110 46
+#define B101111 47
+#define B0101111 47
+#define B00101111 47
+#define B110000 48
+#define B0110000 48
+#define B00110000 48
+#define B110001 49
+#define B0110001 49
+#define B00110001 49
+#define B110010 50
+#define B0110010 50
+#define B00110010 50
+#define B110011 51
+#define B0110011 51
+#define B00110011 51
+#define B110100 52
+#define B0110100 52
+#define B00110100 52
+#define B110101 53
+#define B0110101 53
+#define B00110101 53
+#define B110110 54
+#define B0110110 54
+#define B00110110 54
+#define B110111 55
+#define B0110111 55
+#define B00110111 55
+#define B111000 56
+#define B0111000 56
+#define B00111000 56
+#define B111001 57
+#define B0111001 57
+#define B00111001 57
+#define B111010 58
+#define B0111010 58
+#define B00111010 58
+#define B111011 59
+#define B0111011 59
+#define B00111011 59
+#define B111100 60
+#define B0111100 60
+#define B00111100 60
+#define B111101 61
+#define B0111101 61
+#define B00111101 61
+#define B111110 62
+#define B0111110 62
+#define B00111110 62
+#define B111111 63
+#define B0111111 63
+#define B00111111 63
+#define B1000000 64
+#define B01000000 64
+#define B1000001 65
+#define B01000001 65
+#define B1000010 66
+#define B01000010 66
+#define B1000011 67
+#define B01000011 67
+#define B1000100 68
+#define B01000100 68
+#define B1000101 69
+#define B01000101 69
+#define B1000110 70
+#define B01000110 70
+#define B1000111 71
+#define B01000111 71
+#define B1001000 72
+#define B01001000 72
+#define B1001001 73
+#define B01001001 73
+#define B1001010 74
+#define B01001010 74
+#define B1001011 75
+#define B01001011 75
+#define B1001100 76
+#define B01001100 76
+#define B1001101 77
+#define B01001101 77
+#define B1001110 78
+#define B01001110 78
+#define B1001111 79
+#define B01001111 79
+#define B1010000 80
+#define B01010000 80
+#define B1010001 81
+#define B01010001 81
+#define B1010010 82
+#define B01010010 82
+#define B1010011 83
+#define B01010011 83
+#define B1010100 84
+#define B01010100 84
+#define B1010101 85
+#define B01010101 85
+#define B1010110 86
+#define B01010110 86
+#define B1010111 87
+#define B01010111 87
+#define B1011000 88
+#define B01011000 88
+#define B1011001 89
+#define B01011001 89
+#define B1011010 90
+#define B01011010 90
+#define B1011011 91
+#define B01011011 91
+#define B1011100 92
+#define B01011100 92
+#define B1011101 93
+#define B01011101 93
+#define B1011110 94
+#define B01011110 94
+#define B1011111 95
+#define B01011111 95
+#define B1100000 96
+#define B01100000 96
+#define B1100001 97
+#define B01100001 97
+#define B1100010 98
+#define B01100010 98
+#define B1100011 99
+#define B01100011 99
+#define B1100100 100
+#define B01100100 100
+#define B1100101 101
+#define B01100101 101
+#define B1100110 102
+#define B01100110 102
+#define B1100111 103
+#define B01100111 103
+#define B1101000 104
+#define B01101000 104
+#define B1101001 105
+#define B01101001 105
+#define B1101010 106
+#define B01101010 106
+#define B1101011 107
+#define B01101011 107
+#define B1101100 108
+#define B01101100 108
+#define B1101101 109
+#define B01101101 109
+#define B1101110 110
+#define B01101110 110
+#define B1101111 111
+#define B01101111 111
+#define B1110000 112
+#define B01110000 112
+#define B1110001 113
+#define B01110001 113
+#define B1110010 114
+#define B01110010 114
+#define B1110011 115
+#define B01110011 115
+#define B1110100 116
+#define B01110100 116
+#define B1110101 117
+#define B01110101 117
+#define B1110110 118
+#define B01110110 118
+#define B1110111 119
+#define B01110111 119
+#define B1111000 120
+#define B01111000 120
+#define B1111001 121
+#define B01111001 121
+#define B1111010 122
+#define B01111010 122
+#define B1111011 123
+#define B01111011 123
+#define B1111100 124
+#define B01111100 124
+#define B1111101 125
+#define B01111101 125
+#define B1111110 126
+#define B01111110 126
+#define B1111111 127
+#define B01111111 127
+#define B10000000 128
+#define B10000001 129
+#define B10000010 130
+#define B10000011 131
+#define B10000100 132
+#define B10000101 133
+#define B10000110 134
+#define B10000111 135
+#define B10001000 136
+#define B10001001 137
+#define B10001010 138
+#define B10001011 139
+#define B10001100 140
+#define B10001101 141
+#define B10001110 142
+#define B10001111 143
+#define B10010000 144
+#define B10010001 145
+#define B10010010 146
+#define B10010011 147
+#define B10010100 148
+#define B10010101 149
+#define B10010110 150
+#define B10010111 151
+#define B10011000 152
+#define B10011001 153
+#define B10011010 154
+#define B10011011 155
+#define B10011100 156
+#define B10011101 157
+#define B10011110 158
+#define B10011111 159
+#define B10100000 160
+#define B10100001 161
+#define B10100010 162
+#define B10100011 163
+#define B10100100 164
+#define B10100101 165
+#define B10100110 166
+#define B10100111 167
+#define B10101000 168
+#define B10101001 169
+#define B10101010 170
+#define B10101011 171
+#define B10101100 172
+#define B10101101 173
+#define B10101110 174
+#define B10101111 175
+#define B10110000 176
+#define B10110001 177
+#define B10110010 178
+#define B10110011 179
+#define B10110100 180
+#define B10110101 181
+#define B10110110 182
+#define B10110111 183
+#define B10111000 184
+#define B10111001 185
+#define B10111010 186
+#define B10111011 187
+#define B10111100 188
+#define B10111101 189
+#define B10111110 190
+#define B10111111 191
+#define B11000000 192
+#define B11000001 193
+#define B11000010 194
+#define B11000011 195
+#define B11000100 196
+#define B11000101 197
+#define B11000110 198
+#define B11000111 199
+#define B11001000 200
+#define B11001001 201
+#define B11001010 202
+#define B11001011 203
+#define B11001100 204
+#define B11001101 205
+#define B11001110 206
+#define B11001111 207
+#define B11010000 208
+#define B11010001 209
+#define B11010010 210
+#define B11010011 211
+#define B11010100 212
+#define B11010101 213
+#define B11010110 214
+#define B11010111 215
+#define B11011000 216
+#define B11011001 217
+#define B11011010 218
+#define B11011011 219
+#define B11011100 220
+#define B11011101 221
+#define B11011110 222
+#define B11011111 223
+#define B11100000 224
+#define B11100001 225
+#define B11100010 226
+#define B11100011 227
+#define B11100100 228
+#define B11100101 229
+#define B11100110 230
+#define B11100111 231
+#define B11101000 232
+#define B11101001 233
+#define B11101010 234
+#define B11101011 235
+#define B11101100 236
+#define B11101101 237
+#define B11101110 238
+#define B11101111 239
+#define B11110000 240
+#define B11110001 241
+#define B11110010 242
+#define B11110011 243
+#define B11110100 244
+#define B11110101 245
+#define B11110110 246
+#define B11110111 247
+#define B11111000 248
+#define B11111001 249
+#define B11111010 250
+#define B11111011 251
+#define B11111100 252
+#define B11111101 253
+#define B11111110 254
+#define B11111111 255
+
+#endif /* _BIT_CONSTANTS_H_ */
diff --git a/wirish/bits.h b/wirish/bits.h
index 7b51e5e..b2c9d5c 100644
--- a/wirish/bits.h
+++ b/wirish/bits.h
@@ -1,56 +1,30 @@
-/*
- * Part of Arduino - http://www.arduino.cc/
+/******************************************************************************
+ * The MIT License
*
- * Copyright (c) 2005-2006 David A. Mellis
+ * Copyright (c) 2010 LeafLabs, LLC.
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
*
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
*
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- */
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
-// BIT DEFINITION
-
-#define BIT0 0x00000001
-#define BIT1 0x00000002
-#define BIT2 0x00000004
-#define BIT3 0x00000008
-#define BIT4 0x00000010
-#define BIT5 0x00000020
-#define BIT6 0x00000040
-#define BIT7 0x00000080
-#define BIT8 0x00000100
-#define BIT9 0x00000200
-#define BIT10 0x00000400
-#define BIT11 0x00000800
-#define BIT12 0x00001000
-#define BIT13 0x00002000
-#define BIT14 0x00004000
-#define BIT15 0x00008000
-#define BIT16 0x00010000
-#define BIT17 0x00020000
-#define BIT18 0x00040000
-#define BIT19 0x00080000
-#define BIT20 0x00100000
-#define BIT21 0x00200000
-#define BIT22 0x00400000
-#define BIT23 0x00800000
-#define BIT24 0x01000000
-#define BIT25 0x02000000
-#define BIT26 0x04000000
-#define BIT27 0x08000000
-#define BIT28 0x10000000
-#define BIT29 0x20000000
-#define BIT30 0x40000000
-#define BIT31 0x80000000
+/* Note: Use of this header file is deprecated. Use bit_constants.h
+ instead. */
+#include "bit_constants.h"
diff --git a/wirish/boards.h b/wirish/boards.h
index eed3e26..f8505ab 100644
--- a/wirish/boards.h
+++ b/wirish/boards.h
@@ -57,241 +57,433 @@ enum {
ADC12, ADC13, ADC14, ADC15, ADC16, ADC17, ADC18, ADC19, ADC20, };
#define ADC_INVALID 0xFFFFFFFF
-#define TIMER_INVALID (TimerCCR)0xFFFFFFFF
/* Types used for the tables below */
typedef struct PinMapping {
GPIO_Port *port;
uint32 pin;
uint32 adc;
- TimerCCR timer_channel;
+ TimerCCR timer_ccr;
uint32 exti_port;
+ timer_dev_num timer_num;
+ uint32 timer_chan;
} PinMapping;
-/* LeafLabs Maple rev3, rev4 */
+/* LeafLabs Maple rev3, rev5 */
#ifdef BOARD_maple
#define CYCLES_PER_MICROSECOND 72
- #define MAPLE_RELOAD_VAL 71999 /* takes a cycle to reload */
+ #define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */
+
+ #define BOARD_BUTTON_PIN 38
+ #define BOARD_LED_PIN 13
static __attribute__ ((unused)) PinMapping PIN_MAP[NR_GPIO_PINS] = {
/* D0/PA3 */
- {GPIOA_BASE, 3, ADC3, TIMER2_CH4_CCR, EXTI_CONFIG_PORTA},
+ {GPIOA_BASE, 3, ADC3, TIMER2_CH4_CCR, EXTI_CONFIG_PORTA, TIMER2, 4},
/* D1/PA2 */
- {GPIOA_BASE, 2, ADC2, TIMER2_CH3_CCR, EXTI_CONFIG_PORTA},
+ {GPIOA_BASE, 2, ADC2, TIMER2_CH3_CCR, EXTI_CONFIG_PORTA, TIMER2, 3},
/* D2/PA0 */
- {GPIOA_BASE, 0, ADC0, TIMER2_CH1_CCR, EXTI_CONFIG_PORTA},
+ {GPIOA_BASE, 0, ADC0, TIMER2_CH1_CCR, EXTI_CONFIG_PORTA, TIMER2, 1},
/* D3/PA1 */
- {GPIOA_BASE, 1, ADC1, TIMER2_CH2_CCR, EXTI_CONFIG_PORTA},
+ {GPIOA_BASE, 1, ADC1, TIMER2_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2, 2},
/* D4/PB5 */
- {GPIOB_BASE, 5, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
/* D5/PB6 */
- {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB, TIMER4, 1},
/* D6/PA8 */
- {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTA},
+ {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTA, TIMER1, 1},
/* D7/PA9 */
- {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA},
+ {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA, TIMER1, 2},
/* D8/PA10 */
- {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA},
+ {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA, TIMER1, 3},
/* D9/PB7 */
- {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB, TIMER4, 2},
/* D10/PA4 */
- {GPIOA_BASE, 4, ADC4, TIMER_INVALID, EXTI_CONFIG_PORTA},
+ {GPIOA_BASE, 4, ADC4, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
/* D11/PA7 */
- {GPIOA_BASE, 7, ADC7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA},
+ {GPIOA_BASE, 7, ADC7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2},
/* D12/PA6 */
- {GPIOA_BASE, 6, ADC6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA},
+ {GPIOA_BASE, 6, ADC6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1},
/* D13/PA5 */
- {GPIOA_BASE, 5, ADC5, TIMER_INVALID, EXTI_CONFIG_PORTA},
+ {GPIOA_BASE, 5, ADC5, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
/* D14/PB8 */
- {GPIOB_BASE, 8, ADC_INVALID, TIMER4_CH3_CCR, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 8, ADC_INVALID, TIMER4_CH3_CCR, EXTI_CONFIG_PORTB, TIMER4, 3},
/* Little header */
/* D15/PC0 */
- {GPIOC_BASE, 0, ADC10, TIMER_INVALID, EXTI_CONFIG_PORTC},
+ {GPIOC_BASE, 0, ADC10, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
/* D16/PC1 */
- {GPIOC_BASE, 1, ADC11, TIMER_INVALID, EXTI_CONFIG_PORTC},
+ {GPIOC_BASE, 1, ADC11, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
/* D17/PC2 */
- {GPIOC_BASE, 2, ADC12, TIMER_INVALID, EXTI_CONFIG_PORTC},
+ {GPIOC_BASE, 2, ADC12, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
/* D18/PC3 */
- {GPIOC_BASE, 3, ADC13, TIMER_INVALID, EXTI_CONFIG_PORTC},
+ {GPIOC_BASE, 3, ADC13, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
/* D19/PC4 */
- {GPIOC_BASE, 4, ADC14, TIMER_INVALID, EXTI_CONFIG_PORTC},
+ {GPIOC_BASE, 4, ADC14, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
/* D20/PC5 */
- {GPIOC_BASE, 5, ADC15, TIMER_INVALID, EXTI_CONFIG_PORTC},
+ {GPIOC_BASE, 5, ADC15, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
/* External header */
/* D21/PC13 */
- {GPIOC_BASE, 13, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTC},
+ {GPIOC_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
/* D22/PC14 */
- {GPIOC_BASE, 14, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTC},
+ {GPIOC_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
/* D23/PC15 */
- {GPIOC_BASE, 15, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTC},
+ {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
/* D24/PB9 */
- {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
/* D25/PD2 */
- {GPIOD_BASE, 2, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTD},
+ {GPIOD_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
/* D26/PC10 */
- {GPIOC_BASE, 10, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTC},
+ {GPIOC_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
/* D27/PB0 */
- {GPIOB_BASE, 0, ADC8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 0, ADC8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3},
/* D28/PB1 */
- {GPIOB_BASE, 1, ADC9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 1, ADC9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4},
/* D29/PB10 */
- {GPIOB_BASE, 10, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
/* D30/PB11 */
- {GPIOB_BASE, 11, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
/* D31/PB12 */
- {GPIOB_BASE, 12, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
/* D32/PB13 */
- {GPIOB_BASE, 13, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
/* D33/PB14 */
- {GPIOB_BASE, 14, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
/* D34/PB15 */
- {GPIOB_BASE, 15, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB},
+ {GPIOB_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
/* D35/PC6 */
- {GPIOC_BASE, 6, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTC},
+ {GPIOC_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
/* D36/PC7 */
- {GPIOC_BASE, 7, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTC},
+ {GPIOC_BASE, 7, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
/* D37/PC8 */
- {GPIOC_BASE, 8, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTC},
- /* PC9 (BUT) */
- {GPIOC_BASE, 9, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTC}
+ {GPIOC_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D38/PC9 (BUT) */
+ {GPIOC_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}
};
-#endif
+ #define BOARD_INIT do { \
+ } while(0)
+
+#elif defined(BOARD_maple_native)
-/* LeafLabs Maple Native (prototype) */
-#ifdef BOARD_maple_native
+ /* LeafLabs Maple Native (prototype) */
#define CYCLES_PER_MICROSECOND 72
- #define MAPLE_RELOAD_VAL 71999 /* takes a cycle to reload */
+ #define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */
+
+ #define BOARD_LED_PIN D21
+ #define BOARD_BUTTON_PIN D18
- // TODO:
static __attribute__ ((unused)) PinMapping PIN_MAP[NR_GPIO_PINS] = {
- /* D0/PA3 */
- {GPIOA_BASE, 3, ADC3, TIMER2_CH4_CCR},
- /* D1/PA2 */
- {GPIOA_BASE, 2, ADC2, TIMER2_CH3_CCR},
- /* D2/PA0 */
- {GPIOA_BASE, 0, ADC0, TIMER2_CH1_CCR},
- /* D3/PA1 */
- {GPIOA_BASE, 1, ADC1, TIMER2_CH2_CCR},
- /* D4/PB5 */
- {GPIOB_BASE, 5, ADC_INVALID, TIMER_INVALID},
- /* D5/PB6 */
- {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR},
- /* D6/PA8 */
- {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR},
- /* D7/PA9 */
- {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR},
- /* D8/PA10 */
- {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR},
- /* D9/PB7 */
- {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR},
- /* D10/PA4 */
- {GPIOA_BASE, 4, ADC4, TIMER_INVALID},
- /* D11/PA7 */
- {GPIOA_BASE, 7, ADC7, TIMER3_CH2_CCR},
- /* D12/PA6 */
- {GPIOA_BASE, 6, ADC6, TIMER3_CH1_CCR},
- /* D13/PA5 */
- {GPIOA_BASE, 5, ADC5, TIMER_INVALID},
- /* D14/PB8 */
- {GPIOB_BASE, 8, ADC_INVALID, TIMER4_CH3_CCR},
+ /* Top header */
- /* Little header */
+ /* D0/PB10 */
+ {GPIOB_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D1/PB2 */
+ {GPIOB_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D2/PB12 */
+ {GPIOB_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D3/PB13 */
+ {GPIOB_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D4/PB14 */
+ {GPIOB_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D5/PB15 */
+ {GPIOB_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D6/PC0 */
+ {GPIOC_BASE, 0, ADC10, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D7/PC1 */
+ {GPIOC_BASE, 1, ADC11, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D8/PC2 */
+ {GPIOC_BASE, 2, ADC12, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D9/PC3 */
+ {GPIOC_BASE, 3, ADC13, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D10/PC4 */
+ {GPIOC_BASE, 4, ADC14, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D11/PC5 */
+ {GPIOC_BASE, 5, ADC15, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D12/PC6 */
+ {GPIOC_BASE, 6, ADC_INVALID, TIMER8_CH1_CCR, EXTI_CONFIG_PORTC, TIMER8, 1},
+ /* D13/PC7 */
+ {GPIOC_BASE, 7, ADC_INVALID, TIMER8_CH2_CCR, EXTI_CONFIG_PORTC, TIMER8, 2},
+ /* D14/PC8 */
+ {GPIOC_BASE, 8, ADC_INVALID, TIMER8_CH3_CCR, EXTI_CONFIG_PORTC, TIMER8, 3},
+ /* D15/PC9 */
+ {GPIOC_BASE, 9, ADC_INVALID, TIMER8_CH4_CCR, EXTI_CONFIG_PORTC, TIMER8, 4},
+ /* D16/PC10 */
+ {GPIOC_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D17/PC11 */
+ {GPIOC_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D18/PC12 */
+ {GPIOC_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D19/PC13 */
+ {GPIOC_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D20/PC14 */
+ {GPIOC_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D21/PC15 */
+ {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D22/PA8 */
+ {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTA, TIMER1, 1},
+ /* D23/PA9 */
+ {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA, TIMER1, 2},
+ /* D24/PA10 */
+ {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA, TIMER1, 3},
+ /* D25/PB9 */
+ {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB, TIMER4, 4},
- /* D15/PC0 */
- {GPIOC_BASE, 0, ADC10, TIMER_INVALID},
- /* D16/PC1 */
- {GPIOC_BASE, 1, ADC11, TIMER_INVALID},
- /* D17/PC2 */
- {GPIOC_BASE, 2, ADC12, TIMER_INVALID},
- /* D18/PC3 */
- {GPIOC_BASE, 3, ADC13, TIMER_INVALID},
- /* D19/PC4 */
- {GPIOC_BASE, 4, ADC14, TIMER_INVALID},
- /* D20/PC5 */
- {GPIOC_BASE, 5, ADC15, TIMER_INVALID},
+ /* Bottom header */
- /* External header */
+ /* D26/PD2 */
+ {GPIOD_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D27/PD3 */
+ {GPIOD_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D28/PD6 */
+ {GPIOD_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D29/PG11 */
+ {GPIOG_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D30/PG12 */
+ {GPIOG_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D31/PG13 */
+ {GPIOG_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D32/PG14 */
+ {GPIOG_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D33/PG8 */
+ {GPIOG_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D34/PG7 */
+ {GPIOG_BASE, 7, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D35/PG6 */
+ {GPIOG_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D36/PB5 */
+ {GPIOB_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D37/PB6 */
+ {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB, TIMER4, 1},
+ /* D38/PB7 */
+ {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB, TIMER4, 2},
+ /* D39/PF6 */
+ {GPIOF_BASE, 6, ADC4, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D40/PF7 */
+ {GPIOF_BASE, 7, ADC5, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D41/PF8 */
+ {GPIOF_BASE, 8, ADC6, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D42/PF9 */
+ {GPIOF_BASE, 9, ADC7, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D43/PF10 */
+ {GPIOF_BASE, 10, ADC8, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D44/PF11 */
+ {GPIOF_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D45/PB1 */
+ {GPIOB_BASE, 1, ADC9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4},
+ /* D46/PB0 */
+ {GPIOB_BASE, 0, ADC8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3},
+ /* D47/PA0 */
+ {GPIOA_BASE, 0, ADC0, TIMER5_CH1_CCR, EXTI_CONFIG_PORTA, TIMER5, 1},
+ /* D48/PA1 */
+ {GPIOA_BASE, 1, ADC1, TIMER5_CH2_CCR, EXTI_CONFIG_PORTA, TIMER5, 2}, /* FIXME (?) what to do about D48--D50
+ also being TIMER2_CH[2,3,4]? */
+ /* D49/PA2 */
+ {GPIOA_BASE, 2, ADC2, TIMER5_CH3_CCR, EXTI_CONFIG_PORTA, TIMER5, 3},
+ /* D50/PA3 */
+ {GPIOA_BASE, 3, ADC3, TIMER5_CH4_CCR, EXTI_CONFIG_PORTA, TIMER5, 4},
+ /* D51/PA4 */
+ {GPIOA_BASE, 4, ADC4, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D52/PA5 */
+ {GPIOA_BASE, 5, ADC5, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D53/PA6 */
+ {GPIOA_BASE, 6, ADC6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1},
+ /* D54/PA7 */
+ {GPIOA_BASE, 7, ADC7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2},
- /* D21/PC13 */
- {GPIOC_BASE, 13, ADC_INVALID, TIMER_INVALID},
- /* D22/PC14 */
- {GPIOC_BASE, 14, ADC_INVALID, TIMER_INVALID},
- /* D23/PC15 */
- {GPIOC_BASE, 15, ADC_INVALID, TIMER_INVALID},
- /* D24/PB9 */
- {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR},
- /* D25/PD2 */
- {GPIOD_BASE, 2, ADC_INVALID, TIMER_INVALID},
- /* D26/PC10 */
- {GPIOC_BASE, 10, ADC_INVALID, TIMER_INVALID},
- /* D27/PB0 */
- {GPIOB_BASE, 0, ADC8, TIMER3_CH3_CCR},
- /* D28/PB1 */
- {GPIOB_BASE, 1, ADC9, TIMER3_CH4_CCR},
- /* D29/PB10 */
- {GPIOB_BASE, 10, ADC_INVALID, TIMER_INVALID},
- /* D30/PB11 */
- {GPIOB_BASE, 11, ADC_INVALID, TIMER_INVALID},
- /* D31/PB12 */
- {GPIOB_BASE, 12, ADC_INVALID, TIMER_INVALID},
- /* D32/PB13 */
- {GPIOB_BASE, 13, ADC_INVALID, TIMER_INVALID},
- /* D33/PB14 */
- {GPIOB_BASE, 14, ADC_INVALID, TIMER_INVALID},
- /* D34/PB15 */
- {GPIOB_BASE, 15, ADC_INVALID, TIMER_INVALID},
- /* D35/PC6 */
- {GPIOC_BASE, 6, ADC_INVALID, TIMER_INVALID},
- /* D36/PC7 */
- {GPIOC_BASE, 7, ADC_INVALID, TIMER_INVALID},
- /* D37/PC8 */
- {GPIOC_BASE, 8, ADC_INVALID, TIMER_INVALID},
- /* PC9 (BUT) */
- {GPIOC_BASE, 9, ADC_INVALID, TIMER_INVALID}
+ /* Right (triple) header */
+
+ /* D55/PF0 */
+ {GPIOF_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D56/PD11 */
+ {GPIOD_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D57/PD14 */
+ {GPIOD_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D58/PF1 */
+ {GPIOF_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D59/PD12 */
+ {GPIOD_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D60/PD15 */
+ {GPIOD_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D61/PF2 */
+ {GPIOF_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D62/PD13 */
+ {GPIOD_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D63/PD0 */
+ {GPIOD_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D64/PF3 */
+ {GPIOF_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D65/PE3 */
+ {GPIOE_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D66/PD1 */
+ {GPIOD_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D67/PF4 */
+ {GPIOF_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D68/PE4 */
+ {GPIOE_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D69/PE7 */
+ {GPIOE_BASE, 7, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D70/PF5 */
+ {GPIOF_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D71/PE5 */
+ {GPIOE_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D72/PE8 */
+ {GPIOE_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D73/PF12 */
+ {GPIOF_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D74/PE6 */
+ {GPIOE_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D75/PE9 */
+ {GPIOE_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D76/PF13 */
+ {GPIOF_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D77/PE10 */
+ {GPIOE_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D78/PF14 */
+ {GPIOF_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D79/PG9 */
+ {GPIOG_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D80/PE11 */
+ {GPIOE_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D81/PF15 */
+ {GPIOF_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID},
+ /* D82/PG10 */
+ {GPIOG_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D83/PE12 */
+ {GPIOE_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D84/PG0 */
+ {GPIOG_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D85/PD5 */
+ {GPIOD_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D86/PE13 */
+ {GPIOE_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D87/PG1 */
+ {GPIOG_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D88/PD4 */
+ {GPIOD_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D89/PE14 */
+ {GPIOE_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D90/PG2 */
+ {GPIOG_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D91/PE1 */
+ {GPIOE_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D92/PE15 */
+ {GPIOE_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D93/PG3 */
+ {GPIOG_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D94/PE0 */
+ {GPIOE_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID},
+ /* D95/PD8 */
+ {GPIOD_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D96/PG4 */
+ {GPIOG_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D97/PD9 */
+ {GPIOD_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID},
+ /* D98/PG5 */
+ {GPIOG_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID},
+ /* D99/PD10 */
+ {GPIOD_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}
};
- static __attribute__((unused)) ExtiInfo PIN_TO_EXTI_CHANNEL[NR_GPIO_PINS] =
- {
- /* D0/PA3 */
- {EXTI3, EXTI_CONFIG_PORTA},
- /* D1/PA2 */
- {EXTI2, EXTI_CONFIG_PORTA},
- /* D2/PA0 */
- {EXTI0, EXTI_CONFIG_PORTA},
- /* D3/PA1 */
- {EXTI1, EXTI_CONFIG_PORTA},
- /* D4/PB5 */
- {EXTI5, EXTI_CONFIG_PORTB},
- /* D5/PB6 */
- {EXTI6, EXTI_CONFIG_PORTB},
- /* D6/PA8 */
- {EXTI8, EXTI_CONFIG_PORTA},
- /* D7/PA9 */
- {EXTI9, EXTI_CONFIG_PORTA},
- /* D8/PA10 */
- {EXTI10, EXTI_CONFIG_PORTA},
- /* D9/PB7 */
- {EXTI7, EXTI_CONFIG_PORTB},
- /* D10/PA4 */
- {EXTI4, EXTI_CONFIG_PORTA},
- /* D11/PA7 */
- {EXTI7, EXTI_CONFIG_PORTA},
- /* D12/PA6 */
- {EXTI6, EXTI_CONFIG_PORTA},
- /* D13/PA5 */
- {EXTI5, EXTI_CONFIG_PORTA},
+ #define BOARD_INIT do { \
+ } while(0)
+
+#elif defined(BOARD_maple_mini)
+
+ #define CYCLES_PER_MICROSECOND 72
+ #define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */
+
+ #define BOARD_BUTTON_PIN 32
+ #define BOARD_LED_PIN 33
+
+ static __attribute__ ((unused)) PinMapping PIN_MAP[NR_GPIO_PINS] = {
+ /* D0/PB11 */
+ {GPIOB_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D1/PB10 */
+ {GPIOB_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D2/PB2 */
+ {GPIOB_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D3/PB0 */
+ {GPIOB_BASE, 0, ADC8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3},
+ /* D4/PA7 */
+ {GPIOA_BASE, 7, ADC7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2},
+ /* D5/PA6 */
+ {GPIOA_BASE, 6, ADC6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1},
+ /* D6/PA5 */
+ {GPIOA_BASE, 5, ADC5, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D7/PA4 */
+ {GPIOA_BASE, 4, ADC4, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D8/PA3 */
+ {GPIOA_BASE, 3, ADC3, TIMER2_CH4_CCR, EXTI_CONFIG_PORTA, TIMER2, 4},
+ /* D9/PA2 */
+ {GPIOA_BASE, 2, ADC2, TIMER2_CH3_CCR, EXTI_CONFIG_PORTA, TIMER2, 3},
+ /* D10/PA1 */
+ {GPIOA_BASE, 1, ADC1, TIMER2_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2, 2},
+ /* D11/PA0 */
+ {GPIOA_BASE, 0, ADC0, TIMER2_CH1_CCR, EXTI_CONFIG_PORTA, TIMER2, 1},
+ /* D12/PC15 */
+ {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D13/PC14 */
+ {GPIOC_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D14/PC13 */
+ {GPIOC_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D15/PB7 */
+ {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB, TIMER4, 1},
+ /* D16/PB6 */
+ {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB, TIMER4, 1},
+ /* D17/PB5 */
+ {GPIOB_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D18/PB4 */
+ {GPIOB_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D19/PB3 */
+ {GPIOB_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D20/PA15 */
+ {GPIOA_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D21/PA14 */
+ {GPIOA_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D22/PA13 */
+ {GPIOA_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D23/PA12 */
+ {GPIOA_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D24/PA11 */
+ {GPIOA_BASE, 11, ADC_INVALID, TIMER1_CH4_CCR, EXTI_CONFIG_PORTA, TIMER1, 4},
+ /* D25/PA10 */
+ {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA, TIMER1, 3},
+ /* D26/PA9 */
+ {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2, 2},
+ /* D27/PA8 */
+ {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTB, TIMER1, 1},
+ /* D28/PB15 */
+ {GPIOB_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D29/PB14 */
+ {GPIOB_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D30/PB13 */
+ {GPIOB_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D31/PB12 */
+ {GPIOB_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D32/PB8 */
+ {GPIOB_BASE, 8, ADC_INVALID, TIMER4_CH3_CCR, EXTI_CONFIG_PORTB, TIMER4, 3},
+ /* D33/PB1 */
+ {GPIOB_BASE, 1, ADC9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4},
};
-#endif
-#ifndef CYCLES_PER_MICROSECOND
+ /* since we want the Serial Wire/JTAG pins as GPIOs, disable both
+ SW and JTAG debug support */
+ /* don't use __clear_bits here! */
+ #define BOARD_INIT \
+ do { \
+ *AFIO_MAPR = (*AFIO_MAPR | BIT(26)) & ~(BIT(25) | BIT(24)); \
+ } while (0)
+
+#else
+
#error "Board type has not been selected correctly."
+
#endif
#ifdef __cplusplus
diff --git a/wirish/comm/HardwareSPI.h b/wirish/comm/HardwareSPI.h
index 03d1ea1..7241d0b 100644
--- a/wirish/comm/HardwareSPI.h
+++ b/wirish/comm/HardwareSPI.h
@@ -29,18 +29,23 @@
#ifndef _HARDWARESPI_H_
#define _HARDWARESPI_H_
+/**
+ * Defines the possible SPI communication speeds.
+ */
typedef enum SPIFrequency {
- SPI_18MHZ = 0,
- SPI_9MHZ = 1,
- SPI_4_5MHZ = 2,
- SPI_2_25MHZ = 3,
- SPI_1_125MHZ = 4,
- SPI_562_500KHZ = 5,
- SPI_281_250KHZ = 6,
- SPI_140_625KHZ = 7,
- MAX_SPI_FREQS = 8,
+ SPI_18MHZ = 0, /**< 18 MHz */
+ SPI_9MHZ = 1, /**< 9 MHz */
+ SPI_4_5MHZ = 2, /**< 4.5 MHz */
+ SPI_2_25MHZ = 3, /**< 2.25 MHZ */
+ SPI_1_125MHZ = 4, /**< 1.125 MHz */
+ SPI_562_500KHZ = 5, /**< 562.500 KHz */
+ SPI_281_250KHZ = 6, /**< 281.250 KHz */
+ SPI_140_625KHZ = 7, /**< 140.625 KHz */
+ MAX_SPI_FREQS = 8, /**< The number of SPI frequencies. */
} SPIFrequency;
+/* Documented by hand in docs/source/lang/api/hardwarespi.rst; if you
+ make any changes, make sure to update this document. */
class HardwareSPI {
private:
uint32 spi_num;
diff --git a/wirish/comm/HardwareSerial.cpp b/wirish/comm/HardwareSerial.cpp
index 425c610..d6c7e82 100644
--- a/wirish/comm/HardwareSerial.cpp
+++ b/wirish/comm/HardwareSerial.cpp
@@ -34,9 +34,9 @@
#include "gpio.h"
#include "timers.h"
-HardwareSerial Serial1(USART1, 4500000UL, GPIOA_BASE, 9, 10, TIMER1, 2);
-HardwareSerial Serial2(USART2, 2250000UL, GPIOA_BASE, 2, 3, TIMER2, 3);
-HardwareSerial Serial3(USART3, 2250000UL, GPIOB_BASE, 10, 11, 0, 0);
+HardwareSerial Serial1(USART1, 4500000UL, GPIOA_BASE, 9,10, TIMER1, 2);
+HardwareSerial Serial2(USART2, 2250000UL, GPIOA_BASE, 2, 3, TIMER2, 3);
+HardwareSerial Serial3(USART3, 2250000UL, GPIOB_BASE, 10,11, TIMER_INVALID, 0);
// TODO: High density device ports
HardwareSerial::HardwareSerial(uint8 usart_num,
@@ -44,7 +44,7 @@ HardwareSerial::HardwareSerial(uint8 usart_num,
GPIO_Port *gpio_port,
uint8 tx_pin,
uint8 rx_pin,
- uint8 timer_num,
+ timer_dev_num timer_num,
uint8 compare_num) {
this->usart_num = usart_num;
this->max_baud = max_baud;
@@ -75,8 +75,7 @@ void HardwareSerial::begin(uint32 baud) {
gpio_set_mode(gpio_port, tx_pin, GPIO_MODE_AF_OUTPUT_PP);
gpio_set_mode(gpio_port, rx_pin, GPIO_MODE_INPUT_FLOATING);
- if ((usart_num == USART1) ||
- (usart_num == USART2)) {
+ if (timer_num != TIMER_INVALID) {
/* turn off any pwm if there's a conflict on this usart */
timer_set_mode(timer_num, compare_num, TIMER_DISABLED);
}
diff --git a/wirish/comm/HardwareSerial.h b/wirish/comm/HardwareSerial.h
index 17be49f..aad8aa7 100644
--- a/wirish/comm/HardwareSerial.h
+++ b/wirish/comm/HardwareSerial.h
@@ -31,8 +31,17 @@
#ifndef _HARDWARESERIAL_H_
#define _HARDWARESERIAL_H_
+#include "timers.h"
+
#include "Print.h"
+/* NB: this class documented "by hand" (i.e., not using Doxygen) in:
+
+ libmaple/docs/source/lang/serial.rst
+
+ If you alter the public HardwareSerial interface, you must update
+ the documentation accordingly. */
+
class HardwareSerial : public Print {
private:
uint8 usart_num;
@@ -40,7 +49,7 @@ class HardwareSerial : public Print {
GPIO_Port *gpio_port;
uint8 tx_pin;
uint8 rx_pin;
- uint8 timer_num;
+ timer_dev_num timer_num;
uint8 compare_num;
public:
HardwareSerial(uint8 usart_num,
@@ -48,9 +57,9 @@ class HardwareSerial : public Print {
GPIO_Port *gpio_port,
uint8 tx_pin,
uint8 rx_pin,
- uint8 timer_num,
+ timer_dev_num timer_num,
uint8 compare_num);
- void begin(uint32);
+ void begin(uint32 baud);
void end(void);
uint32 available(void);
uint8 read(void);
diff --git a/wirish/ext_interrupts.c b/wirish/ext_interrupts.c
index f02cdc5..dd7c1a8 100644
--- a/wirish/ext_interrupts.c
+++ b/wirish/ext_interrupts.c
@@ -32,17 +32,8 @@
#include "exti.h"
#include "ext_interrupts.h"
-/**
- * @brief Attach an interrupt handler to be triggered on a given
- * transition on the pin. Runs in interrupt context
- *
- * @param pin Maple pin number
- * @param handler Function to run upon external interrupt trigger.
- * @param mode Type of transition to trigger on, eg falling, rising, etc.
- *
- * @sideeffect Registers a handler
- */
-void attachInterrupt(uint8 pin, voidFuncPtr handler, uint32 mode) {
+/* Attach ISR handler on pin, triggering on the given mode. */
+void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) {
uint8 outMode;
/* Parameter checking */
@@ -65,6 +56,7 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, uint32 mode) {
outMode = EXTI_RISING_FALLING;
break;
default:
+ ASSERT(0);
return;
}
@@ -76,11 +68,7 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, uint32 mode) {
return;
}
-/**
- * @brief Disable an external interrupt
- * @param pin maple pin number
- * @sideeffect unregisters external interrupt handler
- */
+/* Disable any interrupts */
void detachInterrupt(uint8 pin) {
if (!(pin < NR_GPIO_PINS)) {
return;
diff --git a/wirish/ext_interrupts.h b/wirish/ext_interrupts.h
index fef8c8f..304e267 100644
--- a/wirish/ext_interrupts.h
+++ b/wirish/ext_interrupts.h
@@ -22,6 +22,9 @@
* THE SOFTWARE.
*****************************************************************************/
+#include "libmaple_types.h"
+#include "nvic.h"
+
/**
* @file ext_interrupts.h
*
@@ -31,19 +34,76 @@
#ifndef _EXT_INTERRUPTS_H_
#define _EXT_INTERRUPTS_H_
-enum {
- RISING,
- FALLING,
- CHANGE
-};
+/**
+ * The kind of transition on an external pin which should trigger an
+ * interrupt.
+ */
+typedef enum ExtIntTriggerMode_ {
+ RISING, /**< To trigger an interrupt when the pin transitions LOW
+ to HIGH */
+ FALLING, /**< To trigger an interrupt when the pin transitions
+ HIGH to LOW */
+ CHANGE /**< To trigger an interrupt when the pin transitions from
+ LOW to HIGH or HIGH to LOW (i.e., when the pin
+ changes). */
+} ExtIntTriggerMode;
#ifdef __cplusplus
extern "C"{
#endif
-void attachInterrupt(uint8 pin, voidFuncPtr, uint32 mode);
+/**
+ * @brief Registers an interrupt handler on a pin.
+ *
+ * The interrupt will be triggered on a given transition on the pin,
+ * as specified by the mode parameter. The handler runs in interrupt
+ * context. The new handler will replace whatever handler is
+ * currently registered for the pin, if any.
+ *
+ * @param pin Maple pin number
+ * @param handler Function to run upon external interrupt trigger.
+ * The handler should take no arguments, and have void return type.
+ * @param mode Type of transition to trigger on, e.g. falling, rising, etc.
+ *
+ * @sideeffect Registers a handler
+ * @see detachInterrupt()
+ */
+void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode);
+
+/**
+ * @brief Disable any registered external interrupt.
+ * @param pin Maple pin number
+ * @sideeffect unregisters external interrupt handler
+ * @see attachInterrupt()
+ */
void detachInterrupt(uint8 pin);
+/**
+ * Re-enable interrupts.
+ *
+ * Call this after noInterrupts() to re-enable interrupt handling,
+ * after you have finished with a timing-critical section of code.
+ *
+ * @see noInterrupts()
+ */
+static ALWAYS_INLINE void interrupts() {
+ nvic_globalirq_enable();
+}
+
+/**
+ * Disable interrupts.
+ *
+ * After calling this function, all user-programmable interrupts will
+ * be disabled. You can call this function before a timing-critical
+ * section of code, then call interrupts() to re-enable interrupt
+ * handling.
+ *
+ * @see interrupts()
+ */
+static ALWAYS_INLINE void noInterrupts() {
+ nvic_globalirq_disable();
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/wirish/io.h b/wirish/io.h
index 647e79c..2d22dcd 100644
--- a/wirish/io.h
+++ b/wirish/io.h
@@ -33,59 +33,192 @@
#include "gpio.h"
#include "adc.h"
+#include "time.h"
#ifdef __cplusplus
extern "C"{
#endif
+/**
+ * Specifies a GPIO pin behavior.
+ *
+ * Each of the GPIO pins on a Maple board may be configured using
+ * pinMode() to behave in a number of ways: as a digital output pin,
+ * or as an analog input pin, etc., depending on the particular pin.
+ *
+ * This enum specifies the complete set of possible configurations;
+ * not every pin can have all of these modes. For example, on the
+ * Maple, pin 15 may be configured as INPUT_ANALOG, but not as PWM.
+ * See your device's silkscreen and and the GPIO documentation for
+ * more information.
+ *
+ * @see pinMode()
+ */
typedef enum WiringPinMode {
- OUTPUT,
- OUTPUT_OPEN_DRAIN,
- INPUT,
- INPUT_ANALOG,
- INPUT_PULLUP,
- INPUT_PULLDOWN,
- INPUT_FLOATING,
- PWM,
- PWM_OPEN_DRAIN,
+ OUTPUT, /**< Basic digital output: when the pin is HIGH, the
+ voltage is held at +3.3v (Vcc) and when it is 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, /**< 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
+ might cause the state to flip). */
+
+ INPUT_ANALOG, /**< This is a special mode for when the pin will be
+ used for analog (not digital) reads. Enables ADC
+ conversion to be performed on the voltage at the
+ pin. */
+
+ 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
+ affect 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
+ affect the state of the input. */
+
+ INPUT_FLOATING, /**< Synonym for INPUT. */
+
+ PWM, /**< This is a special mode for when the pin will be used for
+ PWM output (a special case of digital output). */
+
+ PWM_OPEN_DRAIN, /**< Like PWM, except that instead of alternating
+ cycles of LOW and HIGH, the voltage on the pin
+ consists of alternating cycles of LOW and
+ floating (disconnected). */
} WiringPinMode;
+/**
+ * Configure behavior of a GPIO pin.
+ *
+ * @param pin Pin to configure. One of: 0-38 (pin numbers as labeled
+ * on silkscreen), or D0-D38 (symbols for same)
+ * @param mode Mode corresponding to desired pin behavior.
+ * @see WiringPinMode
+ */
+void pinMode(uint8 pin, WiringPinMode mode);
-/* Set pin to mode
- * pinMode(pin, mode):
- * pin -> {0-38, D0-D39, A0-16}
- * mode -> {
- * INPUT/INPUT_DIGITAL
- * INPUT_PULLUP
- * INPUT_PULLDOWN
- * INPUT_ANALOG
- * OUTPUT/OUTPUT_PP
- * OUTPUT_OPEN_DRAIN
- * }
+/**
+ * Writes a (digital) value to a pin. The pin must have its
+ * mode set to <code>OUTPUT</code> or <code>OUTPUT_OPEN_DRAIN</code>.
+ *
+ * @param pin Pin to write to. One of: 0-38 (pin numbers as labeled
+ * on silkscreen), or D0-D38 (symbols for same)
+ * @param value Either LOW (write a 0) or HIGH (write a 1).
+ * @see pinMode()
*/
-void pinMode(uint8, uint8);
-
-/*
- * Writes VALUE to digital pin[0-38]
- * digitalWrite(pin, value):
- * pin -> {0-38, D0-D39, A0-16}
- * value -> LOW, HIGH;
-*/
-void digitalWrite(uint8, uint8);
-
-/* Read a digital value from pin, the pin mode must be set to
- * {INPUT, INPUT_PULLUP, INPUT_PULLDOWN}
- * digitalRead(pin)
- * pin -> {0-38, D0-D39, A0-16}
+void digitalWrite(uint8 pin, uint8 value);
+
+/**
+ * Read a digital value from a pin. The pin must have its mode set to
+ * one of INPUT, INPUT_PULLUP, and INPUT_PULLDOWN.
+ *
+ * @param pin Pin to read from. One of: 0-38 (pin numbers as labeled
+ * on silkscreen), or D0-D38 (symbols for same)
+ * @return LOW or HIGH.
+ * @see pinMode()
*/
-uint32 digitalRead(uint8);
+uint32 digitalRead(uint8 pin);
+
+/**
+ * Read an analog value from pin. This function blocks during ADC
+ * conversion, and has 12 bits of resolution. The pin must have its
+ * mode set to INPUT_ANALOG. Ignoring function call overhead,
+ * conversion time is 55.5 cycles.
+ *
+ * @param pin Pin to read from. One of: 0, 1, 2, 3, 10, 11, 12, 13,
+ * 15, 16, 17, 18, 19, 20, 27, 28.
+
+ * @return ADC-converted voltage, in the range 0--4095, inclusive
+ * (i.e. a 12-bit ADC conversion).
-/* Read an analog value from pin, the pin mode must be set
- * to INPUT_ANALOG
- * analogRead(pin)
- * pin -> {A0-A16}
+ * @see pinMode()
+ */
+uint32 analogRead(uint8 pin);
+
+/**
+ * Toggles the digital value at the given pin.
+ *
+ * The pin must have its mode set to OUTPUT.
+ *
+ * @param pin the pin to toggle. If the pin is HIGH, set it LOW. If
+ * it is LOW, set it HIGH.
+ *
+ * @see pinMode()
+ */
+void togglePin(uint8 pin);
+
+/**
+ * Toggle the LED.
+ *
+ * If the LED is on, turn it off. If it is off, turn it on.
+ *
+ * The LED must its mode set to OUTPUT. This can be accomplished
+ * portably over all LeafLabs boards by calling pinMode(BOARD_LED_PIN,
+ * OUTPUT) before calling this function.
+ *
+ * @see pinMode()
+ */
+static inline void toggleLED() {
+ togglePin(BOARD_LED_PIN);
+}
+
+/**
+ * If the button is currently pressed, waits until the button is no
+ * longer being pressed, and returns true. Otherwise, returns false.
+ *
+ * The button pin must have its mode set to INPUT. This can be
+ * accomplished portably over all LeafLabs boards by calling
+ * pinMode(BOARD_BUTTON_PIN, INPUT).
+ *
+ * @see pinMode()
+ */
+uint8 isButtonPressed();
+
+/**
+ * Wait until the button is pressed and released, timing out if no
+ * press occurs.
+ *
+ * The button pin must have its mode set to INPUT. This can be
+ * accomplished portably over all LeafLabs boards by calling
+ * pinMode(BOARD_BUTTON_PIN, INPUT).
+ *
+ * @param timeout_millis Number of milliseconds to wait until the
+ * button is pressed. If timeout_millis is 0, wait forever.
+ *
+ * @return true, if the button was pressed; false, if the timeout was
+ * reached.
+ *
+ * @see pinMode()
*/
-uint32 analogRead(uint8);
+uint8 waitForButtonPress(uint32 timeout_millis);
#ifdef __cplusplus
} // extern "C"
diff --git a/wirish/pwm.c b/wirish/pwm.c
index 2f555ab..072e4cd 100644
--- a/wirish/pwm.c
+++ b/wirish/pwm.c
@@ -38,13 +38,11 @@ void pwmWrite(uint8 pin, uint16 duty_cycle) {
return;
}
- ccr = PIN_MAP[pin].timer_channel;
+ ccr = PIN_MAP[pin].timer_ccr;
- if (ccr == TIMER_INVALID) {
+ if (ccr == 0) {
return;
}
timer_pwm_write_ccr(ccr, duty_cycle);
}
-
-
diff --git a/wirish/pwm.h b/wirish/pwm.h
index fe170cd..d0bc9e0 100644
--- a/wirish/pwm.h
+++ b/wirish/pwm.h
@@ -35,8 +35,20 @@
extern "C"{
#endif
+/**
+ * As a convenience, analogWrite is an alias of pwmWrite to ease
+ * porting Arduino code. However, period and duty will have to be
+ * recalibrated.
+ */
#define analogWrite pwmWrite
-void pwmWrite(uint8, uint16);
+
+/**
+ * Set the PWM duty on the given pin.
+ *
+ * User code is expected to determine and honor the maximum value
+ * (based on the configured period).
+ */
+void pwmWrite(uint8 pin, uint16 duty_cycle);
#ifdef __cplusplus
}
diff --git a/wirish/time.c b/wirish/time.c
index 3a48197..c0a0649 100644
--- a/wirish/time.c
+++ b/wirish/time.c
@@ -43,7 +43,6 @@ void delayMicroseconds(uint32 us) {
/* fudge for function call overhead */
us--;
- int x = 4;
asm volatile(" mov r0, %[us] \n\t"
"1: subs r0, #1 \n\t"
" bhi 1b \n\t"
diff --git a/wirish/time.h b/wirish/time.h
index 2a561d3..8d3d074 100644
--- a/wirish/time.h
+++ b/wirish/time.h
@@ -23,7 +23,8 @@
*****************************************************************************/
/**
- * @brief Timing and delay functions.
+ * @file time.h
+ * @brief Timing and delay functions.
*/
#ifndef _TIME_H
@@ -40,12 +41,20 @@ extern "C"{
#define US_PER_MS 1000
-/* time in milliseconds since boot */
+/**
+ * Returns time (in milliseconds) since the beginning of program
+ * execution. On overflow, restarts at 0.
+ * @see micros()
+ */
static inline uint32 millis(void) {
return systick_timer_millis;
}
-/* Time in microseconds since boot */
+/**
+ * Returns time (in microseconds) since the beginning of program
+ * execution. On overflow, restarts at 0.
+ * @see millis()
+ */
static inline uint32 micros(void) {
uint32 ms;
uint32 cycle_cnt;
@@ -58,15 +67,36 @@ static inline uint32 micros(void) {
nvic_globalirq_enable();
- /* MAPLE_RELOAD_VAL is 1 less than the number of cycles it actually
- takes to complete a systick reload */
+ /* SYSTICK_RELOAD_VAL is 1 less than the number of cycles it
+ actually takes to complete a SysTick reload */
res = (ms * US_PER_MS) +
- (MAPLE_RELOAD_VAL + 1 - cycle_cnt)/CYCLES_PER_MICROSECOND;
+ (SYSTICK_RELOAD_VAL + 1 - cycle_cnt)/CYCLES_PER_MICROSECOND;
return res;
}
+/**
+ * Delay for at least the given number of milliseconds.
+ *
+ * Interrupts, etc. may cause the actual number of milliseconds to
+ * exceed ms. However, this function will return no less than ms
+ * milliseconds from the time it is called.
+ *
+ * @param ms the number of milliseconds to delay.
+ * @see delayMicroseconds()
+ */
void delay(unsigned long ms);
+
+/**
+ * Delay for at least the given number of microseconds.
+ *
+ * Interrupts, etc. may cause the actual number of microseconds to
+ * exceed us. However, this function will return no less than us
+ * microseconds from the time it is called.
+ *
+ * @param us the number of microseconds to delay.
+ * @see delay()
+ */
void delayMicroseconds(uint32 us);
#ifdef __cplusplus
diff --git a/wirish/usb_serial.cpp b/wirish/usb_serial.cpp
index 405220a..e2cdee3 100644
--- a/wirish/usb_serial.cpp
+++ b/wirish/usb_serial.cpp
@@ -101,17 +101,27 @@ uint32 USBSerial::available(void) {
return usbBytesAvailable();
}
+/* blocks forever until len_bytes is received */
uint32 USBSerial::read(void *buf, uint32 len) {
if (!buf) {
return 0;
}
- return usbReceiveBytes((uint8*)buf, len);
+ uint32 bytes_in = 0;
+ while (len > 0) {
+ uint32 new_bytes = usbReceiveBytes((uint8*)((uint8*)buf+bytes_in), len);
+ len -= new_bytes;
+ bytes_in += new_bytes;
+ }
+
+ return len;
}
+/* blocks forever until 1 byte is received */
uint8 USBSerial::read(void) {
uint8 ch;
- usbReceiveBytes(&ch, 1);
+
+ while (usbReceiveBytes(&ch, 1) == 0);
return ch;
}
@@ -119,10 +129,12 @@ uint8 USBSerial::pending(void) {
return usbGetPending();
}
+// TODO deprecate the crap out of this
uint8 USBSerial::getDTR(void) {
return usbGetDTR();
}
+// TODO deprecate the crap out of this
uint8 USBSerial::getRTS(void) {
return usbGetRTS();
}
diff --git a/wirish/wirish.c b/wirish/wirish.c
index 89adc1e..5935f95 100644
--- a/wirish/wirish.c
+++ b/wirish/wirish.c
@@ -62,7 +62,7 @@ void init(void) {
rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1);
nvic_init();
- systick_init(MAPLE_RELOAD_VAL);
+ systick_init(SYSTICK_RELOAD_VAL);
gpio_init();
adc_init();
timer_init(TIMER1, 1);
@@ -74,4 +74,7 @@ void init(void) {
timer_init(TIMER8, 1);
#endif
setupUSB();
+
+ /* include the board-specific init macro */
+ BOARD_INIT;
}
diff --git a/wirish/wirish.h b/wirish/wirish.h
index c1c46cb..311c74f 100644
--- a/wirish/wirish.h
+++ b/wirish/wirish.h
@@ -62,8 +62,8 @@ extern "C"{
#define LSBFIRST 0
#define MSBFIRST 1
-#define lowByte(w) ((w) & 0xff)
-#define highByte(w) ((w) >> 8)
+#define lowByte(w) ((w) & 0xFF)
+#define highByte(w) (((w) >> 8) & 0xFF)
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
diff --git a/wirish/wirish_digital.c b/wirish/wirish_digital.c
index f4868da..6f9906d 100644
--- a/wirish/wirish_digital.c
+++ b/wirish/wirish_digital.c
@@ -22,8 +22,8 @@
* THE SOFTWARE.
*****************************************************************************/
-/**
- * @brief Arduino-compatible digital I/O implementation.
+/*
+ * Arduino-compatible digital I/O implementation.
*/
#include "wirish.h"
@@ -31,6 +31,7 @@
void pinMode(uint8 pin, WiringPinMode mode) {
uint8 outputMode;
+ boolean pwm = false;
if (pin >= NR_GPIO_PINS) {
return;
@@ -58,9 +59,11 @@ void pinMode(uint8 pin, WiringPinMode mode) {
break;
case PWM:
outputMode = GPIO_MODE_AF_OUTPUT_PP;
+ pwm = true;
break;
case PWM_OPEN_DRAIN:
outputMode = GPIO_MODE_AF_OUTPUT_OD;
+ pwm = true;
break;
default:
ASSERT(0);
@@ -68,6 +71,20 @@ void pinMode(uint8 pin, WiringPinMode mode) {
}
gpio_set_mode(PIN_MAP[pin].port, PIN_MAP[pin].pin, outputMode);
+
+ if (PIN_MAP[pin].timer_num != TIMER_INVALID) {
+ /* enable/disable timer channels if we're switching into or
+ out of pwm */
+ if (pwm) {
+ timer_set_mode(PIN_MAP[pin].timer_num,
+ PIN_MAP[pin].timer_chan,
+ TIMER_PWM);
+ } else {
+ timer_set_mode(PIN_MAP[pin].timer_num,
+ PIN_MAP[pin].timer_chan,
+ TIMER_DISABLED);
+ }
+ }
}
@@ -86,3 +103,35 @@ void digitalWrite(uint8 pin, uint8 val) {
gpio_write_bit(PIN_MAP[pin].port, PIN_MAP[pin].pin, val);
}
+
+void togglePin(uint8 pin) {
+ gpio_toggle_pin(PIN_MAP[pin].port, PIN_MAP[pin].pin);
+}
+
+uint8 isButtonPressed() {
+ if (digitalRead(BOARD_BUTTON_PIN)) {
+ while (digitalRead(BOARD_BUTTON_PIN))
+ ;
+ return true;
+ }
+ return false;
+}
+
+uint8 waitForButtonPress(uint32 timeout) {
+ uint32 start = millis();
+ uint32 time;
+ if (timeout == 0) {
+ while (!isButtonPressed())
+ ;
+ return true;
+ }
+ do {
+ time = millis();
+ /* properly handle wrap-around */
+ if ((start > time && time + (0xffffffffU - start) > timeout) ||
+ time - start > timeout) {
+ return false;
+ }
+ } while (!isButtonPressed());
+ return true;
+}
diff --git a/wirish/wirish_math.cpp b/wirish/wirish_math.cpp
index 12a21c3..5aa6510 100644
--- a/wirish/wirish_math.cpp
+++ b/wirish/wirish_math.cpp
@@ -47,8 +47,3 @@ long random(long howsmall, long howbig) {
return random(diff) + howsmall;
}
-long map(long x, long in_min, long in_max, long out_min, long out_max) {
- return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
-}
-
-
diff --git a/wirish/wirish_math.h b/wirish/wirish_math.h
index 4543c1b..14614ba 100644
--- a/wirish/wirish_math.h
+++ b/wirish/wirish_math.h
@@ -22,6 +22,11 @@
* THE SOFTWARE.
*****************************************************************************/
+/**
+ * @file wirish_math.h
+ * @brief Includes cmath; provides Arduino-compatible math routines.
+ */
+
#ifndef _WIRING_MATH_H_
#define _WIRING_MATH_H_
@@ -29,10 +34,56 @@
#ifdef __cplusplus
-void randomSeed(unsigned int);
-long random(long);
-long random(long, long);
-long map(long, long, long, long, long);
+/**
+ * @brief Initialize the pseudo-random number generator.
+ * @param seed the number used to initialize the seed; cannot be zero.
+ */
+void randomSeed(unsigned int seed);
+
+/**
+ * @brief Generate a pseudo-random number with upper bound.
+ * @param max An upper bound on the returned value, exclusive.
+ * @return A pseudo-random number in the range [0,max).
+ * @see randomSeed()
+ */
+long random(long max);
+
+/**
+ * @brief Generate a pseudo-random number with lower and upper bounds.
+ * @param min Lower bound on the returned value, inclusive.
+ * @param max Upper bound on the returned value, exclusive.
+ * @return A pseudo-random number in the range [min, max).
+ * @see randomSeed()
+ */
+long random(long min, long max);
+
+/**
+ * @brief Remap a number from one range to another.
+ *
+ * That is, a value equal to fromStart gets mapped to toStart, a value
+ * of fromEnd to toEnd, and other values are mapped proportionately.
+ *
+ * Does not constrain value to lie within [fromStart, fromEnd].
+ *
+ * If a "start" value is larger than its corresponding "end", the
+ * ranges are reversed, so map(n, 1, 10, 10, 1) would reverse the
+ * range [1,10].
+ *
+ * Negative numbers may appear as any argument.
+ *
+ * @param value the value to map.
+ * @param fromStart the beginning of the value's current range.
+ * @param fromEnd the end of the value's current range.
+ * @param toStart the beginning of the value's mapped range.
+ * @param toEnd the end of the value's mapped range.
+ * @return the mapped value.
+ */
+/* TODO: profile code bloat due to inlining this */
+inline long map(long value, long fromStart, long fromEnd,
+ long toStart, long toEnd) {
+ return (value - fromStart) * (toEnd - toStart) / (fromEnd - fromStart) +
+ toStart;
+}
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
@@ -56,4 +107,48 @@ long map(long, long, long, long, long);
#endif
+/* Following are duplicate declarations (with Doxygen comments) for
+ * some of the math.h functions; this is for the convenience of the
+ * Sphinx docs.
+ */
+
+/**
+ * Compute the cosine of an angle, in radians.
+ * @param x The radian measure of the angle.
+ * @return The cosine of x. This value will be between -1 and 1.
+ */
+double cos(double x);
+
+/**
+ * Compute the sine of an angle, in radians.
+ * @param x The radian measure of the angle.
+ * @return The sine of x. This value will be between -1 and 1.
+ */
+double sin(double x);
+
+/**
+ * Compute the tangent of an angle, in radians.
+ * @param x The radian measure of the angle.
+ * @return The tangent of x. There are no limits on the return value
+ * of this function.
+ */
+double tan(double x);
+
+/**
+ * Compute the square root of a number.
+ * @param x The number whose square root to find. This value cannot
+ * be negative.
+ * @return The square root of x. The return value is never negative.
+ */
+double sqrt(double x);
+
+/**
+ * Compute an exponentiation.
+ * @param x the base. This value cannot be zero if y <= 0. This value
+ * cannot be negative if y is not an integral value.
+ * @param y the exponent.
+ * @return x raised to the power y.
+ */
+double pow(double x, double y);
+
#endif